【问题标题】:Conditional match without false force a match?没有错误的条件匹配强制匹配?
【发布时间】:2019-03-16 03:38:53
【问题描述】:

我在 c# 中使用以下正则表达式来匹配一些输入案例:

^
(?<entry>[#])?
(?(entry)(?<id>\w+))
(?<value>.*)
$

选项忽略模式空格。

我的输入如下:

hello
#world
[xxx]

这一切都可以在这里测试:DEMO

我的问题是这个正则表达式与最后一行不匹配。为什么? 我想要做的是检查输入字符。如果它在那里,我会强制使用\w+ 的标识符。其余输入应在最后一组中捕获。

这是一个简化的正则表达式和简化的输入。

如果我将 id 正则表达式更改为 (?(entry)(?&lt;id&gt;\w+)|)(?(entry)(?&lt;id&gt;\w+))?(?(entry)(?&lt;id&gt;\w+)?) 之类的内容,则可以解决此问题。

我试图理解为什么条件组与原始正则表达式中所述不匹配。

我对正则表达式很坚定,并且知道可以将正则表达式简化为 ^(\#(?&lt;id&gt;\w+))?(?&lt;value&gt;.*)$ 以满足我的需求。但真正的正则表达式包含另外两个可选组:

^
(?<entry>[#])?
(\?\:)?
(\(\?(?:\w+(?:-\w+)?|-\w+)\))?
(?(entry)(?<id>\w+))
(?<value>.*)
$

这就是我尝试使用条件匹配的原因。

2018 年 10 月 12 日更新

我对它进行了一些测试。我发现以下正则表达式应该匹配每个输入,甚至是一个空的输入 - 但它没有:

(?(a)a).*

DEMO

我认为这是 .net 正则表达式中的一个错误,并将其报告给微软:See here for more information

【问题讨论】:

  • @WiktorStribiżew 是的,正如我已经说过的,我知道这将解决我的问题。但为什么?有Balancing Group Definitions 在没有那个hack 的情况下工作。
  • 我实际上可以在 C# 中重现它。出于某种原因,它匹配foo,但不匹配[foo]
  • 这是live C# example (演示问题)
  • @PoulBak 是的,id 组强制 \w+[ 不匹配。但仅当entry 组有捕获时才应评估该组。该组没有[foo] 的捕获,因此不应评估 id 组,整个字符串应由(?&lt;value&gt;.*) 组捕获。但它不是那样工作的。
  • 对不起,我想我已经接近解决了,让我再深入一点。

标签: c# regex


【解决方案1】:

在正则表达式解析器中没有错误,但是在使用. 通配符说明符时。 . 说明符将消耗所有字符,等待它,除了换行符 \n。 (见Character Classes in Regular Expressions“任意字符”.])

如果您希望您的正则表达式工作,您需要使用所有字符包括换行,这可以通过指定选项SingleLine 来完成。用什么来解释所说的话

Singline 告诉解析器处理. 以匹配包括\n 在内的所有字符。


为什么不处于单行模式时仍然会失败,因为其他行已被消耗?那是因为最终匹配实际上将当前位置放在\n 并且唯一的选项(指定为使用)是 [.*];正如我们提到的,不能使用它,因此停止解析器。此时$ 也会锁定操作。


让我演示一下我创建的一个工具正在发生什么,该工具说明了这个问题。在工具中,左上角是我们看到的示例文本。下面是解析器看到的\r\n 字符分别由↵¶ 表示。包含在该窗格中的是当时在包含匹配项的黄色框中匹配的内容。中间的框是实际的模式,最后的右侧框通过监听返回结构并显示前面提到的空白区域来详细显示匹配结果。

请注意,第二个匹配项(作为索引 1)在组捕获中具有 world idvalue 作为

我猜你的令牌处理器没有在正确的组中得到你想要的,因为人们实际上并没有将value 的成功匹配视为\r,所以它被忽略了。

让我们打开单线,看看会发生什么。

现在一切都被消耗掉了,但是有一个不同的问题。 :-)

【讨论】:

  • 感谢您的解释。我了解\r 的问题。在我的情况下,我只有一条线。如果您比我理解得更好,请解释为什么(?(a)a).* 与输入xxx 不匹配(没有换行符或换行符;只有三个字符)。 DEMO。在我看来(?(a)a).* 必须匹配每个输入,即使是空的。此正则表达式使用?(a) 查找a 并使用它。如果没有a,则所有输入都必须由.* 捕获,但正则表达式不匹配任何不包含a 的字符串。请解释
  • 混淆在于条件匹配(?( ) ) 失败时,它会停止正则表达式处理冷处理(就像任何匹配失败一样)。由于您只提供了一个条件a,因此解析器查看第一个字符并没有找到a;美好的。然后它会查看用户是否指定了一个 or 条件来执行 when 第一个条件失败....否。您没有提供 or 条件,因此处理停止。如果添加or | condition,它会按预期工作。因此(?(a)a|.*) 就像一个魅力。 :-) 匹配中的任何失败条件都会在该点停止匹配。
  • No:如果表达式不匹配,则 no 是可选的匹配模式从您提供的链接的第一句复制而来。 no 部分是可选的!顺便提一句。 Balancing group definitions 使用完全相同的技巧,没有任何 no 部分。表达式的结尾是(?(Open)(?!))。相信我,你不需要锚。我经常使用平衡组定义,并且我的许多正则表达式在该定义之后继续并且工作正常。
  • 苹果和橙子搭配得均衡,那是另一种动物。即使没有 optional 模式,您仍然会因为缺少 a 而失败。你的意思是失败是可选的,模式匹配应该继续。将模式更改为 a?.* 然后如果这是你想要的。
猜你喜欢
  • 1970-01-01
  • 2019-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-04
  • 2018-12-03
相关资源
最近更新 更多