我有一个字符串(不包含换行符),我想找到第一个字符串中的所有子序列。
例如,我们假设我要查找的字符串是"hello world"
。如果我在此字符串中搜索(使用正则表达式):"1h2e3l4l5o6 7w8o9r0l0d0"
,它应该能够发现它确实包含(一次)字符串"hello world"
。它还应该能够在以下字符串中找到多个匹配项:"hheelloo wwoorrlldd"
。
我有以下代码:
string stringToSearch = // could be anything (no newline)
int numOfSubSeq = 0;
Regex myRegex = new Regex("h.*e.*l.*l.*o.* .*w.*o.*r.*l.*d");
MatchCollection matches = myRegex.Matches(stringToSearch);
numOfSubSeq = matches.Count; // I only need the number of matches
这很有效。有点。如果stringToSearch
为"1h2e3l4l5o6 7w8o9r0l0d0"
,则效果很好。但是,如果stringToSearch
是"hheelloo wwoorrlldd"
,则此正则表达式只能找到一个匹配,这是错误的。
关于如何解决此问题的任何想法?
答案 0 :(得分:2)
使用.NET正则表达式,你不会有任何运气。你最好的选择是为它编写一个算法。正则表达式不适合这项工作。
那就是说,你可以使用PCRE正则表达式做到这一点,我只是为了好玩而做到了这一点;)
免责声明:我是本文中使用的库的作者。
Fisrt,安装PCRE.NET:
m_settingsDialog = new QDialog;
QWidget settingsWidget = loader.load(&file);
settingsWidget.setParent(m_settingsDialog);
然后,构建一个这样的模式:
Install-Package PCRE.NET
在PCRE用语中,h.*?e.*?l.*?l.*?o.*?\ .*?w.*?o.*?r.*?l.*?d(?C1)
事件被称为标注。它指示正则表达式引擎在匹配的这一点调用你的自定义函数。然后,您可以说该部分是否应被视为匹配。
计算调用callout函数的次数,并告诉引擎模式应该失败,这会强制它回溯。完成工作。
(?C1)
致电public static int GetMatchCount(string searchFor, string searchIn)
{
if (string.IsNullOrEmpty(searchFor) || string.IsNullOrEmpty(searchIn))
return 0;
var patternBuilder = new StringBuilder();
foreach (var searchChar in searchFor)
patternBuilder.Append(Regex.Escape(searchChar.ToString())).Append(".*?");
patternBuilder.Length -= 3;
patternBuilder.Append("(?C1)");
var pattern = new PcreRegex(patternBuilder.ToString());
var count = 0;
pattern.Match(searchIn, callout =>
{
++count;
return PcreCalloutResult.Fail;
});
return count;
}
会返回GetMatchCount("hello world", "hheelloo wwoorrlldd")
。
哦,顺便说一句,如果你想真正看到字符在输入字符串中的位置,这里有一些代码:
512
这是结果:
public static void PrintMatches(string searchFor, string searchIn)
{
if (string.IsNullOrEmpty(searchFor) || string.IsNullOrEmpty(searchIn))
return;
var patternBuilder = new StringBuilder();
foreach (var searchChar in searchFor)
patternBuilder.Append("(").Append(Regex.Escape(searchChar.ToString())).Append(").*?");
patternBuilder.Length -= 3;
patternBuilder.Append("(?C1)");
var pattern = new PcreRegex(patternBuilder.ToString());
var outputBuilder = new StringBuilder();
Console.WriteLine(searchIn);
pattern.Match(searchIn, callout =>
{
outputBuilder.Clear();
outputBuilder.Append(' ', searchIn.Length);
foreach (var group in callout.Match.Groups.Skip(1))
outputBuilder[group.Index] = '^';
Console.WriteLine(outputBuilder);
return PcreCalloutResult.Fail;
});
}
答案 1 :(得分:0)
当然,由于两个原因,您无法找到多于一个结果
h
而不是h*
)。您可以将此网站用作正则表达式的测试区:https://regex101.com/r/uT8eS0/1
首先,如果您想要只有一个匹配项,则必须定义匹配组。否则你只会一直得到一场比赛。当您搜索h
时,您也在搜索单个字符。如果您想匹配多个,则必须将其更改为h*
或h+
。如果您决定使用+
,则匹配一个到无限制字符。如果你选择*
,它将匹配零到无限字符。
将您的模式更改为"h+.*e+.*l+.*l+.*o+.* .*w+.*o+.*r+.*l+.*d+
也将匹配您发布的模式中您的字符之间的.*
指令中处理的字符。 Afaik它不可能只在一个字符串中匹配不同的组。您可以在组或子组中分隔每个字符,但这会产生大量不同的组。
答案 2 :(得分:0)
我知道,我应该用C#编写这个,但是我在PERL中写了它,因为它也知道正则表达式; @时间更容易。
$_ = "hheelllloo";
sub matchmaker {
my @blah = @_;
if ($blah[0] =~ /[h]{$blah[1],}[e]{$blah[1],}[l]{$blah[1],}[l]{$blah[1],}[o]{$blah[1],}/) {
$blah[1]++;
print("deeper\n");
matchmaker($blah[0],$blah[1]);
} else {
return $blah[1]-1;
}
}
$match = matchmaker($_,1);
print("match ",$match);
它是递归函数,如果您将查看您的字符串并要求越来越多的字母匹配您要求的模式。您可以在5分钟内将其转换为c#。模式{min,max}的正则表达式语法的关键;你增加最小值并让最大值尽可能地贪婪。所以我寻找一个h,然后是一个e,然后是一个l,而不是另一个l。如果我找到所有,我会寻找2小时,2小时,2小时,2小时1和2小时......你明白了。
现在,如果您想要增强此功能并获得更多匹配,请在字符串中向前移动一个字母,然后重新运行匹配。
你可以暂时玩这个,它是否有效。不知道:))
答案 3 :(得分:0)
请查看this解决方案以解决类似的问题(使用javascript,但很容易理解)。