假设我们匹配FIND files where file2=29 AND file32="12" OR file623134="file23"
作为解释,我将分步进行。
显然,与字符串完全匹配的正则表达式会匹配。
FIND files where file2=29 AND file32="12" OR file623134="file23"
首先让我们决定我们要从中读取哪些位...并使其可访问。
FIND (files) where file(2)=(29) AND file(32)=("12") OR file(623134)=("file23")
在这里,我们在要读取的所有位周围加上括号。这将这些位定义为“捕获组”。在 C# 中,我们可以给它们命名。我们稍后会这样做。
现在...让我们概括这个正则表达式,以便它匹配更多示例...键是数字,因此我们可以使用[0-9]+ 捕获它们。这意味着match a character in the range 0 to 9, at least once。
FIND (files) where file([0-9]+)=(29) AND file([0-9]+)=("12") OR file([0-9]+)=("file23")
好的..现在值...这里有些是字符串..让我们匹配那些...
字符串是不是 " 被 '"' 或 "[^"]+" 包围的东西
(注意.. 加号表示我们不能匹配空字符串,因为我们至少需要一个字符。* 可以让您匹配空字符串。)
FIND (files) where file([0-9]+)=(29) AND file([0-9]+)=("[^"]+") OR file([0-9]+)=("[^"]+")
这个例子中的一个值是一个数字。所以我们假设它们可以是整数。
FIND (files) where file([0-9]+)=([0-9]+) AND file([0-9]+)=("[^"]+") OR file([0-9]+)=("[^"]+")
第一个例子没有什么特别的。所以我们假设所有的值都可以是字符串或整数。要创建两个选项,我们使用| 选项匹配器。 (现在..我猜你在屏幕上大喊“不,它们可以是任何东西......不仅仅是字符串和数字”,但没关系。我稍后也会处理。)
FIND (files) where file([0-9]+)=("[^"]+"|[0-9]+) AND file([0-9]+)=("[^"]+"|[0-9]+) OR file([0-9]+)=("[^"]+"|[0-9]+)
现在...我们这里有很多重复...最后一部分是相同的,除了一个有“OR”而另一个有“AND”。这很重要......我们想知道operator 正在使用什么......所以让我们也捕捉一下。
FIND (files) where file([0-9]+)=("[^"]+"|[0-9]+) (AND) file([0-9]+)=("[^"]+"|[0-9]+) (OR) file([0-9]+)=("[^"]+"|[0-9]+)
现在我们可以通过删除最后一部分并说它是前一个键/值对的重复来排除重复。
FIND (files) where file([0-9]+)=("[^"]+"|[0-9]+)( (AND|OR) file([0-9]+)=("[^"]+"|[0-9]+))*
我添加了一个“*”,因为表达式的最后一部分可以根据需要重复多次,或者根本不存在。
现在...如果我们想处理任何值、浮点数、时间等,我们要么需要为每个匹配,要么需要一个通用的“任何”匹配器。两者都有缺点。如果我们明确匹配所有类型,我们还有更多工作要做。如果我们不这样做,那么我们需要对“我们如何知道值何时完成?”做出一些假设
假设我们假设值后面会有空格。然后我们可以匹配所有字符,直到我们点击空格...[^\s]+
FIND (files) where file([0-9]+)=([^\s]+)( (AND|OR) file([0-9]+)=([^\s]+))*
但是现在.. 如果该值是一个字符串,并且它包含空格,它会中断。
我们可能想单独处理字符串来解决这个问题。
FIND (files) where file([0-9]+)=("[^"]+"|[^\s]+)( (AND|OR) file([0-9]+)=("[^"]+"|[^\s]+))*
"[^"]+" 不处理字符串中的转义字符。更好的匹配器是"(\\"|[^"])+",它表示引用,然后重复转义引用或非引用,然后引用。使用它会为您的表达式添加一个新的捕获组。我们不需要那个,所以我们可以通过在括号内添加?: 来告诉它不要捕获这个组。例如"(?:\\"|[^"])+"
FIND (files) where file([0-9]+)=("(?:\\"|[^"])+"|[^\s]+)( (AND|OR) file([0-9]+)=("(?:\\"|[^"])+"|[^\s]+))*
正如我所提到的......在 C# 中,您可以命名捕获组。为此,您可以在组内添加 ?<name>。
FIND (?<table>files) where file(?<key>[0-9]+)=(?<value>"(?:\\"|[^"])+"|[^\s]+)( (?<operator>AND|OR) file(?<key>[0-9]+)=(?<value>"(?:\\"|[^"])+"|[^\s]+))*
这个表达式中仍然存在重复。但如果我们把它去掉,我们将允许无效的表达式匹配。例如。
FIND (?<table>files)( (?<operator>AND|OR|where) file(?<key>[0-9]+)=(?<value>"(?:\\"|[^"])+"|[^\s]+))+
这将允许FIND files AND file2="test" 匹配.. 这并不是您真正想要的,但可能已经足够了。
我可能只是使用字符串 concat 来删除重复,
var pair = @"(?<pair>file(?<key>[0-9]+)=(?<value>"(?:\\\"|[^\"])+\"|[^\s]+))";
var query = @"FIND (?<table>files) where "+pair+"( (?<operator>AND|OR) "+pair+")*";
var ex = new Regex(query);
或者只是进行代码检查以确保第一个运算符是“where”
var query = @"FIND (?<table>files)(?<condition> (?<operator>AND|OR|where) file(?<key>[0-9]+)=(?<value>"(?:\\\"|[^\"])+\"|[^\s]+))+";
var ex = new Regex(query);
var match = ex.Match(...);
... match.Groups["table"].Value ...
您现在可以匹配一个字符串,遍历“条件”组并询问他们的operator,key, andvalue`。
见How do I access named capturing groups in a .NET Regex?