正则表达式和管道操作员

时间:2009-08-14 23:14:52

标签: c# regex

请一点正则表达式帮助。

为什么这些不同?

Regex.Replace("(999) 555-0000 /x ext123", "/x.*|[^0-9]", String.Empty)
"9995550000"


Regex.Replace("(999) 555-0000 /x ext123", "[^0-9]|/x.*", String.Empty)
"9995550000123"

我以为管道操作员不关心订单......或者可能有其他东西可以解释这个?

5 个答案:

答案 0 :(得分:7)

如果我做了一个疯狂的猜测,我会说它首先运行表达式的第一部分,然后是第二部分。所以,在第二种情况下发生的事情是它正在删除所有非数字部分,这意味着第二部分将永远不会匹配,并使您的扩展保持原样。

由于它必须首先运行表达式的某些部分,因为它不能同时运行,我会说这是一个相当自然的假设,虽然我可以看到为什么你可能会被抓住...绝对是一个有趣的问题。

编辑:为了解决措辞,正如Ben正确指出的那样,尝试从字符串中的每个字符开始匹配表达式。那么,第二种情况会发生什么:

  • 没有"^"锚点,所以我们尝试在每个子字符串的开头:
  • 对于"(999) 555-0000 /x ext123""("匹配[^0-9],因此请将其替换为空(删除)。
  • 对于"999) 555-0000 /x ext123""999"部分与[^0-9]不匹配,也不匹配/x.*,因此我们会继续尝试")",匹配[^0-9],因此我们将其删除。
  • 等等。当它到达"/"时,同样的事情发生,它匹配[^0-9]并被删除,这意味着正则表达式的第二部分永远不会匹配。

在第一种情况下,会发生以下情况:

  • 同样,没有"^"锚,所以我们尝试所有子串:
  • 对于"(999) 555-0000 /x ext123""("/x.*不匹配,但它与[^0-9]匹配,因此请将其替换为空(删除)。
  • 对于"999) 555-0000 /x ext123""999"部分与/x.*不匹配,也不匹配[^0-9],因此我们会继续尝试")",与/x.*不匹配,但匹配[^0-9],因此我们将其删除。
  • 当我们点击"/x"时,这次/x.* 匹配,它与"/x ext123"匹配,其他字符串被移除,留下我们没法继续。

答案 1 :(得分:3)

我认为你对交替(即管道)有错误的想法。在纯粹的DFA正则表达式实现中,无论排序方式如何,交替都有利于最长匹配。换句话说,整个正则表达式,无论它是否包含交替,总是返回最早和最长的匹配 - “最左边最长”的规则。

然而,当今大多数流行的编程语言(包括.NET)中的正则表达式实现都是Friedl调用传统NFA 引擎的。它们与DFA引擎之间最重要的区别之一是交替是贪心;它按照它们列出的顺序尝试替代方案,并在其中一个匹配时立即停止。唯一会导致它改变主意的是,如果匹配在正则表达式中的稍后点失败,则强制它回溯到交替。

请注意,如果您在两个正则表达式中将[^0-9]更改为[^0-9]+,您将从两者中获得相同的结果 - 但不是您想要的结果。 (我假设/x.*替代方案应匹配 - 并删除 - 字符串的其余部分,包括分机号。)我建议这样的事情:

"[^0-9/]+|/x.*$"

这样,即使启动也不能替代另一个匹配的替代品。这不仅可以防止您遇到的混乱,还可以避免潜在的性能瓶颈。 DFA和NFA之间的其他其他主要差异之一是,写得很糟糕的NFA容易出现严重(甚至catastrophic)性能问题,而且草率交替是触发它们的最简单方法之一

答案 2 :(得分:0)

交替运算符(|)按提供的顺序尝试表达式。在第一个示例中,它首先尝试匹配表达式/x.*,然后尝试匹配[^0-9]

因为字符串" /x ext"可以与第一个表达式[^0-9]匹配,如第二个示例所示,表达式的第二部分/x.*永远不会被调用。

Billy3

编辑:有关交替运算符的更多信息:http://www.regular-expressions.info/alternation.html

答案 3 :(得分:-2)

您缺少一些括号。 :)

答案 4 :(得分:-2)

表达式中的问题是/x.*匹配贪婪。在第一个表达式中,它首先被提供,因此引擎首先尝试匹配它,导致在/ x之后匹配字符串的所有其余部分,因为。*。

如果将其更改为/x.*?你得到与第二个表达式相同的结果。的?在*告诉正则表达式引擎匹配非贪婪之后。

检查http://www.regular-expressions.info/repeat.html以了解有关贪婪的更多信息。