C ++中的简单通配符搜索算法

时间:2011-11-16 01:31:22

标签: c++ string search wildcard

我有一项任务,我必须创建一个包含通配符'?'的搜索模式。我们还没有涉及字符串库的循环和属性,所以我的老师不希望我使用数组或任何我们没有涉及的内容。

我的问题是为特殊字符'?'创建算法。您是否知道如何在不使用更高级技巧的情况下将其集成到我的程序中?我尝试的一切都是完全错误或者有一些错误。

程序应该请求用户输入源字符串,然后请求搜索字符串的另一个输入,其中包括“?”在里面。例如:

源字符串:光荣 搜索字符串:?r?o

在index:2处找到匹配的字符串 匹配的字符串是:orio

6 个答案:

答案 0 :(得分:2)

可能你最好创造两个功能。一个检查模式是否匹配某个给定位置的字符串,另一个使用第一个函数检查输入字符串中的所有位置。

检查匹配模式的函数将遍历模式中的所有字符,并且对于每个字符检查它是?还是与输入字符串中相应位置的字符相同

答案 1 :(得分:2)

我只对暗示回复和评论中的递归感到难过。这是一个解释:

策略:

专注于 wilcards之间的令牌(通配符不应该匹配)。

  • 从模式中提取第一个令牌
  • 成功退出没有(更多)令牌
  • 表示输入中的每个令牌匹配
    • 将模式的其余部分与输入的其余部分
    • 进行匹配
    • 如果没有成功的子匹配,则失败,否则完成

有递归(余数类匹配(....)递归)。

有回溯(如果递归匹配不成功,我们尝试下一个令牌子匹配)

示例(参见https://ideone.com/yApYp

仅使用循环和std::string接口(以及iostreams来显示测试输出):)

#include <iostream>
#include <string>

typedef std::string::const_iterator It;

/*
 * Extract sequences of non-wildcard characters from pattern range
 */
std::string extract_token(It &s, It e) // [s,e) is (sub)pattern
{
    It wcard;
    for (wcard=s; wcard!=e; ++wcard)
        if ('?' == *wcard) break;

    std::string token(s,wcard);

    for (s=wcard; s!=e; ++s)
        if ('?' != *s) break; // treat '??' as '?' in pattern

    return token;
}

/*
 * Match a (sub)pattern against a (sub)input
 *
 * (See "Strategy" above)
 */
bool match(It patb, It pate, const std::string& input)
{
    while (patb != pate)
    {
        // get next token from pattern, advancing patb
        std::string token = extract_token(patb, pate); // updates patb

        if (!token.empty()) // could happen if pattern begins/ends with redundant '?'
        {
            size_t submatch = input.find(token);  // first submatch please

            while (std::string::npos != submatch)  // while we have a submatch
            {
                if (match(patb, pate, input.substr(token.size())))
                    return true; // match completed successfully

                // look for later potential submatches (*backtrack*)
                submatch = input.find(token, submatch+1);
            }
            return false; // required token not found
        }
    }
    return true; // no (remaining) pattern, always match
}

bool match(const std::string& pattern, const std::string& input)
{
    // just relay to overload more suited for recursion
    return match(pattern.begin(), pattern.end(), input); 
}

//////////////////////
// TEST PROGRAM

void test(const std::string& pattern, const std::string& input)
{
    std::cout << std::boolalpha;
    std::cout << "match(\"" << pattern << "\", \"" << input << "\") => " 
              << match(pattern, input) << std::endl;
}

int main()
{
    // matches
    test("?????",               "");
    test("?????",               "?????");
    test("",                    "");
    test("",                    "glorious");
    test("?r?o",                "glorious");
    test("some?words?exist",    "some silly words should, most definitely, be existing");
    test("some??words?exist?",  "some silly words should, most definitely, be existing");

    // failing matches
    test("_",                   "");
    test("_",                   "glorious");
    test("_",                   "glorious");
    test("glorious",            "glo?ious");
    test("?some??words?exist?", "bogus");
}

答案 2 :(得分:0)

或许将通配符视为匹配每个字符,直到到达下一个字符或字符串的结尾。所以算法将是:

if NextCharToMatch is ? then
  get the next search char
  loop until the input equals the new char to match

答案 3 :(得分:0)

这是我提出的功能。最后,我发现了一种使用有限知识的方法。它有效,但可能表现非常糟糕。

感谢您的帮助,他们激励了我,即使我不能直接使用它们,因为我的技术先进。

void wildcard(string source, string search)
{
    unsigned int j = 0, i = 0, z = 0;
    string s1 = "", search2 = search;
    //Starting with a null string and adding found parts to it

    /*************************IF IT STARTS WITH QUESTION MARK*************************/

    if(search.find('?') == 0)
    {
        for(; search.at(z) == '?'; z++)
            //loop make search string start without question marks.
        {
            search2 = search.substr(z + 1, search.length());
        }

        for(; j <= source.length()-search2.length(); ++j)
            //application of Brute Force Search Algoritm for this case.
        {
            while(i < search2.length() && (source.at(z+i+j) == search2.at(i) || search2.at(i) == '?'))
            {
                s1 = s1 + source.at(z+j+i);
                i++;
            }
        }

        if(s1.length() == search2.length())
            //showing results for this case.
        {
            cout << "The matched string was found at index: " << source.find(s1) - z << endl;
            cout << "The matched string is: " << source.substr((source.find(s1)-z), search.length()) << endl << endl;
        }
        else
        {
            cout << "The search string could not found in the source string." << endl << endl;
        }
    }

    /********************IF IT DOES NOT START WITH QUESTION MARK**********************/

    else
        //If it doesnot start with ?, use normal test.
    {
        for(; j <= source.length()-search.length(); ++j)
            //application of Brute Force Search Algoritm for this case.
        {
            while(i < search.length() && (source.at(i+j) == search.at(i) || search.at(i) == '?'))
            {
                s1 = s1 + source.at(j+i);
                i++;
            }
        }

        if(s1.length() == search.length())
            //results
        {
            cout << "The matched string was found at index: " << source.find(s1) << endl;
            cout << "The matched string is: " << s1 << endl << endl;
        }
        else
        {
            cout << "The search string could not found in the source string." << endl << endl;
        }
    }
}

答案 4 :(得分:0)

请参阅我的回答here,它对于大多数用途来说也应该足够快(它尽可能地避免堆分配,并且它基本上是一个非确定性的有限状态自动机)。

答案 5 :(得分:0)

在过去的一周里,我开始移动我的私人&amp;来自bitbucket的公共存储库,我记得这个。

C ++通配符的开放实现。原生C / C ++&amp; .NET

现在,除了慢速正则表达式引擎等之外,它还是从我的沙盒中分成了一个新的项目,作为轻量级,快速和强大的通配符。

enum MetaSymbols
{
    MS_ANY      = _T('*'), // {0, ~}
    MS_SPLIT    = _T('|'), // str1 or str2 or ...
    MS_ONE      = _T('?'), // {0, 1}, ??? - {0, 3}, ...
    MS_BEGIN    = _T('^'), // [str... or [str1... |[str2...
    MS_END      = _T('$'), // ...str] or ...str1]| ...str2]
    MS_MORE     = _T('+'), // {1, ~}
    MS_SINGLE   = _T('#'), // {1}
    MS_ANYSP    = _T('>'), // as [^/]*  //TODO: >\>/ i.e. '>' + {symbol}
};

如何实现自己的等。请看这里:

但是,对于.NET用户来说,它也可以通过Conari引擎。

一般情况下,请参阅“如何运作”或“原样”(MIT许可证)

的实施
#include "regXwildAPI.h"

using namespace net::r_eg::regXwild;

...
if(searchEssC(_T("regXwild"), _T("reg?wild"), true)) {
    // ...
}
searchEss(data, _T("^main*is ok$"));
searchEss(data, _T("^new*pro?ection"));
searchEss(data, _T("pro*system"));
searchEss(data, _T("sys###s"));
searchEss(data, _T("new+7+system"));
searchEss(data, _T("some project|open*and*star|system"));
...

因此,我更新了我的旧答案。享受。