Regex 如何有效地实现像.*a.*b.*这样的正则表达式?

Regex 如何有效地实现像.*a.*b.*这样的正则表达式?,regex,algorithm,performance,Regex,Algorithm,Performance,我想像这样匹配文件名。我试着用正则表达式来解决它 在Colibri中搜索时,您可以在文件名中按顺序键入字符,它会在文件名中按顺序查找所有具有这些字符的文件。例如,对于“ab”,它可以找到“阴谋集团”、“ab”和“achab” 在字母之间简单地插入*(因此搜索的字符串“ab”变成正则表达式*a.*b.*),但我想在大量文件中使用它 到目前为止,我有O(N*?),其中N是文件名的数量,而???充其量是线性复杂度(我假设我的语言使用NFA)。我不太在乎空间的复杂性。我应该选择哪些数据结构或算法来提高效

我想像这样匹配文件名。我试着用正则表达式来解决它

在Colibri中搜索时,您可以在文件名中按顺序键入字符,它会在文件名中按顺序查找所有具有这些字符的文件。例如,对于“ab”,它可以找到“阴谋集团”、“ab”和“achab”

在字母之间简单地插入
*
(因此搜索的字符串“ab”变成正则表达式
*a.*b.*
),但我想在大量文件中使用它


到目前为止,我有O(N*?),其中N是文件名的数量,而???充其量是线性复杂度(我假设我的语言使用NFA)。我不太在乎空间的复杂性。我应该选择哪些数据结构或算法来提高效率(时间复杂度)?

如果您只想检查搜索字符串搜索的字符是否以相同的顺序包含在另一个字符串str中,您可以使用以下简单算法:

pos := -1
for each character in search do
    pos := indexOf(str, character, pos+1)
    if pos is -1 then
        break
    endif
endfor
return pos

该算法返回str中搜索的最后一个字符的偏移量,否则返回-1。它的运行时间是O(n)(您可以用一个简单的
while
循环来替换
indexOf
,该循环将str中的字符从pos到Length(str)-1进行比较,并返回偏移量或-1)。

如果将
替换为字符求反,将大大提高效率。i、 e

 [^a]*a[^b]*b.*
这样你就少了很多回溯


Edit*@yiu\H您是对的,这个正则表达式可能也可以:

a[^b]*b

对于有限的字符集,创建包含匹配文件名的数组或链接列表的查找表可能是有意义的

如果ABC包含X个字符,“1长度”查找表将包含X个表格条目,如果是“2长度”表,则将包含X^2个条目,依此类推。长度为2的表格将包含每个条目(“ab”、“qx”)的所有文件,这些文件按该顺序包含这些字母。当搜索较长的输入“字符串”时,请查找相应的条目并对这些条目进行搜索


注意:计算所需的额外内存并测量速度提高(与全表扫描相比),好处取决于数据集。

您的
是不必要的。如果您只需转换“abc”,您将获得更好的性能 进入
^[^a]*a[^b]*b[^c]*c

string exp = "^";
foreach (char c in inputString)
{
   string s = Regex.Escape (c.ToString()); // escape `.` as `\.`
   exp += "[^" + s + "]*" + s; // replace `a` with `[^a]*a`
}
Regex regex = new Regex (exp, RegexOptions.IgnoreCase);
foreach (string fileName in fileNames)
{
   if (regex.IsMatch (fileName))
      yield return fileName;
}

把多余的
*
放在末尾,这就是我的想法+1背景跟踪?真正的正则表达式不会回溯谢谢我正在考虑存储每个单词中的字符…:)若您稍微扩展一下,这相当于NFA解决方案,但并没有必须处理一般情况的捆绑复杂性。您可以很容易地添加额外的功能来检查每个字母的匹配位置。@user712092如果其中一个字母有助于您解决问题,请不要忘记接受答案。因此,我应该为有限的序列长度创建从
任意序列
包含它的所有文件名的映射,是的。您可以将条目(例如:“exe”)编码为一个数字,对于一个简单的字母表,这将是一个介于0和26^3-1之间的数字。对于较长的用户输入,请删除字母表中最常用的字母,并查找其余字母(3个字符)。您可以存储实际文件名的指针,这样它将占用更少的空间。我不知道你的数据集有多大,文件名有多长,但听起来并不复杂,可能值得一试。