我甚至不确定这是否可行,但这就是我想要的。
String: "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870"
我有一个文本框,我在其中输入搜索参数,并且它们以空格分隔。因此,我想返回一个匹配字符串是string1在字符串中,然后string2在字符串中,或者string2在字符串中,然后string1在字符串中。我不在乎字符串的顺序是什么,但是它们(我将超过2个)必须在字符串中。
例如,在我想要的提供字符串中:
"FEB Low"
或
"Low FEB"
...作为比赛返回。
我真的是regex的新手,只阅读here上的一些教程,但那是不久前我需要今天完成这项工作。星期一我开始了一个更重要的新项目,不能分散这个问题。无论如何使用正则表达式来执行此操作,还是必须遍历搜索过滤器的每个部分并排列顺序?任何和所有的帮助非常感谢。感谢。
更新: 我不想迭代循环并且正在寻找最佳性能的原因是因为不幸的是,我正在使用的dataTable在每次按键时调用此函数,我不希望它陷入困境。 / p>
更新: 谢谢大家的帮助,非常感谢。
代码更新:
最终,这就是我的目标。
string sSearch = nvc["sSearch"].ToString().Replace(" ", ")(?=.*");
if (sSearch != null && sSearch != "")
{
Regex r = new Regex("^(?=.*" + sSearch + ").*$", RegexOptions.IgnoreCase);
_AdminList = _AdminList.Where<IPB>(
delegate(IPB ipb)
{
//Concatenated all elements of IPB into a string
bool returnValue = r.IsMatch(strTest); //strTest is the concatenated string
return returnValue;
}).ToList<IPB>();
}
}
IPB类有X个元素,整个站点中没有一个表我正在处理的是相同顺序的列。因此,我需要任何订单搜索,我不想写很多代码来做它。这里有其他好的想法,但我知道我的老板真的很喜欢Regex(讲道他们),因此我认为如果我现在就去那里是最好的。如果由于某种原因网站的性能下滑(内部网站点),那么我会尝试另一种方式。谢谢大家。
答案 0 :(得分:95)
您可以使用(?=…)
positive lookahead;它断言给定的模式可以匹配。你将锚定在字符串的开头,并以任何顺序逐个查找每个模式的匹配。
它看起来像这样:
^(?=.*one)(?=.*two)(?=.*three).*$
这将按任意顺序(as seen on rubular.com)匹配包含"one"
,"two"
,"three"
的字符串。
根据具体情况,您可能希望在\A
和\Z
上anchor,并使用单行模式,以便the dot匹配所有内容。
这不是解决问题的最有效方法。最好的解决方案是解析输入中的单词并将其置于有效的集合表示中等。
假设我们想要密码:
然后我们可以写一个这样的正则表达式:
^(?=.{8,15}$)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[!@#$%^&*]).*$
\__________/\_________/\_________/\_________/\______________/
length upper lower digit symbol
答案 1 :(得分:4)
为什么不对文本进行简单的检查,因为顺序无关紧要?
string test = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
test = test.ToUpper();
bool match = ((test.IndexOf("FEB") >= 0) && (test.IndexOf("LOW") >= 0));
你需要它来使用正则表达式吗?
答案 2 :(得分:3)
我认为今天最方便的事情是string.Split(' ')
搜索字词,然后迭代确认sourceString.Contains(searchTerm)
var source = @"NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870".ToLowerInvariant();
var search = "FEB Low";
var terms = search.Split(' ');
bool all_match = !terms.Any(term => !(source.Contains(term.ToLowerInvariant())));
请注意,我们使用Any()
来设置短路,因此如果第一项无法匹配,我们会跳过检查第二个,第三个,等等。
这不是RegEx的一个很好的用例。采用任意数量的搜索字符串并将其转换为模式所需的字符串操作几乎肯定会抵消将模式与RegEx引擎匹配的性能优势,尽管这可能会根据您匹配的内容而有所不同。
您已在一些评论中指出您希望避免循环,但RegEx不是一次性解决方案。创建可以逐字逐句循环和逐步进行的可怕的非性能搜索并不难,例如臭名昭着的catastrophic backtracking,其中一个非常简单的匹配需要数千个步骤才能返回false
。
答案 3 :(得分:2)
var text = @"NS306Low FEBRUARY 2FEB0078/9/201013B1-9-1Low31 AUGUST 19870";
var matches = Regex.Matches(text, @"(FEB)|(Low)");
foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}
Output:
Low
FEB
FEB
Low
应该让你开始。
答案 4 :(得分:2)
@polygenelubricants的答案既完整又完美,但我有一个案例,我希望匹配一个日期和其他东西,例如一个10位数字,所以前瞻不匹配,我不能只用前瞻做,所以我使用命名组:
(?:.*(?P<1>[0-9]{10}).*(?P<2>2[0-9]{3}-(?:0?[0-9]|1[0-2])-(?:[0-2]?[0-9]|3[0-1])).*)+
这样的数字总是第1组,日期总是第2组。当然它有一些缺陷,但它对我非常有用,我只是觉得我应该分享它! (看看https://www.debuggex.com/r/YULCcpn8XtysHfmE)
答案 5 :(得分:0)
您不必测试每个排列,只需将搜索分成多个部分“FEB”和“Low”,并确保每个部分匹配。这比试图一次性匹配整个事物的正则表达式要容易得多(我确信理论上可行,但实际上可能不实用)。
答案 6 :(得分:0)
使用string.Split()。它将返回一个由指定的字符串/ char重新分隔的子字符串数组。代码看起来像这样。
int maximumSize = 100;
string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string[] individualString = myString.Split(' ', maximumSize);
了解更多信息 http://msdn.microsoft.com/en-us/library/system.string.split.aspx
编辑:
如果您真的想使用正则表达式,这种模式将起作用。
[^ ]*
你只需使用Regex.Matches();
代码将是这样的:
string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string pattern = "[^ ]*";
Regex rgx = new Regex(pattern);
foreach(Match match in reg.Matches(s))
{
//do stuff with match.value
}