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

Simple wildcard search algorithm in C++

本文关键字:通配符 搜索算法 简单 c++      更新时间:2023-10-16

我有一个任务,我必须创建一个搜索模式,包括通配符'?'。除了循环和字符串库的属性,我们还没有讲到更多的东西,所以我的老师不希望我使用数组或者任何我们没有讲到的东西。

我的问题是为特殊字符'?'创建一个算法。你知道如何在不使用更高级技巧的情况下将它集成到我的程序中吗?我所做的每件事不是完全错误就是有一些错误。

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

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

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

我为在注释中只给提示回溯和递归而感到难过。下面是解释:

策略:

关注通配符之间的标记(通配符不是应该匹配的)。

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

存在递归(递归地匹配剩余类match(....))。

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

样本(见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");
}

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

检查匹配模式的函数将循环遍历模式中的所有字符,并检查每个字符是否为?或与输入字符串中相应位置的字符相同。

这是我想出的函数。最后我利用我有限的知识找到了一个方法。它可以工作,但可能性能真的很差。

谢谢你所有的帮助,他们启发了我,即使我不能直接使用他们,因为先进的技术对我来说。

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;
        }
    }
}

可以认为通配符匹配每个字符,直到到达下一个字符或字符串的末尾。所以算法是:

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

在这里查看我的答案,它对于大多数用途来说也应该足够快(它尽可能地避免堆分配,并且它基本上是一个不确定的有限状态自动机)。

在过去的一周里,我开始移动我的私人&我想起来了

c++通配符的开放实现。本地C/c++ &net

现在它从我的沙盒中分离出来,作为轻量级,快速和强大的通配符,除了慢速的regex引擎等。

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}
};

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

  • https://github.com/3F/regXwild

但是,对于。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"));
...

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