我不明白,为什么会有以下正则表达式:
^*$
匹配字符串“127.0.0.1”?使用Regex.IsMatch("127.0.0.1", "^*$");
使用Expresso,它不匹配,这也是我所期望的。使用表达式^.*$
确实匹配字符串,我也希望这样。
从技术上讲,^*$
应该匹配字符串/行的开头任意次,然后是字符串/行的结尾。似乎*被隐含地视为.*
我错过了什么?
编辑: 运行以下命令以查看问题的示例。
using System;
using System.Text.RegularExpressions;
namespace RegexFubar
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Regex.IsMatch("127.0.0.1", "^*$"));
Console.Read();
}
}
}
我不希望^ * $匹配我的字符串,我想知道它为什么确实匹配它。我认为该表达式应该导致抛出异常,或者至少是不匹配。
EDIT2: 澄清任何困惑。我没有写这个正则表达式,意图让它匹配“127.0.0.1”。我们的应用程序的用户输入了表达式,并想知道为什么它不应该匹配字符串。看了之后,我无法解释为什么它匹配 - 特别是因为Expresso和.NET似乎不同地处理它。
我想这个问题是由于.NET实现避免抛出异常而得到回答,甚至认为它在技术上是一个不正确的表达式。但这真的是我们想要的吗?
答案 0 :(得分:27)
嗯,理论上你是对的,它不应该匹配。但这取决于实施如何在内部运作。大多数正则表达式。将从前面取你的正则表达式并剥离^(注意它必须从字符串的开头匹配)并从末尾剥离$(注意它必须到字符串的结尾),遗留的只是“* “和”*“本身就是一个有效的正则表达式。您正在使用的实现对于如何处理它是错误的。你可以试试如果用“*”替换“^ * $”会发生什么;我想它也会匹配一切。似乎实现将单个星号视为“。*”。
根据ISO / IEC 9945-2:1993标准,也在POSIX standard中描述,它已被破坏。它被打破是因为标准说在^字符之后,星号没有任何特殊含义。这意味着“^ * $”实际上只匹配一个字符串,而这个字符串是“*”!
引用标准:
除非使用星号,否则星号是特殊的:
- 在括号表达式
中- 作为整个BRE的第一个字符(在初始^之后,如果有的话)
- 作为子表达式的第一个字符(在初始^之后,如果有的话);看BRE匹配多个字符。
因此,如果它是第一个字符(并且^如果存在则不算作第一个字符),它没有特殊含义。这意味着在这种情况下,星号应该只匹配一个字符,这是一个星号。
微软说
Microsoft .NET Framework常规 表达式包含最多 其他常规的流行功能 表达式实现,如 那些在Perl和awk。设计为 兼容Perl 5常规 表达式,.NET Framework常规 表达式包括尚未提供的功能 在其他实现中看到,例如 从右到左的匹配和即时 汇编
来源:http://msdn.microsoft.com/en-us/library/hs600312.aspx
好的,让我们测试一下:
# echo -n 127.0.0.1 | perl -n -e 'print (($_ =~ m/(^.*$)/)[0]),"\n";'
-> 127.0.0.1
# echo -n 127.0.0.1 | perl -n -e 'print (($_ =~ m/(^*$)/)[0]),"\n";'
->
不,它没有。 Perl工作正常。 ^。* $匹配字符串,^ * $不=> .NET的正则表达式实现被破坏,它不像MS声称的那样像Perl 5那样工作。
答案 1 :(得分:9)
星号(*)匹配前面的元素 ZERO OR MORE 次。如果您想要一个或多个,请使用+运算符而不是*。
您要求它匹配字符串标记的可选开头和字符串标记的结尾。即如果我们省略字符串标记的开头,你只需要查找字符串标记的结尾...它将匹配任何字符串!
我真的不明白你想要做什么。如果您可以提供更多信息,那么我可以告诉您应该做些什么:)
答案 2 :(得分:2)
如果您尝试
Regex.Match("127.0.0.1", "^*1$")
你会看到它也匹配。 Match.Index 属性的值为8,表示它匹配最后一个'1',而不是第一个'1'。这是有道理的,因为“^ *”将匹配零个或多个行首,并且在“1”之前没有行首。
想想“a * 1 $”的匹配方式,因为“1 $”之前没有'a'。所以“a * $”会与行尾相匹配,就像你的例子一样。
顺便说一句,MSDN文档没有提到'*'只是简单地匹配'*',除非转义为'\ *'。并且'*'本身会抛出异常,而不是'*'。
答案 3 :(得分:0)
你实际上是在说“匹配一个什么都不包含的字符串”。所以它会匹配。在这种情况下,^和$绑定并没有真正区别。
答案 4 :(得分:0)
非法的正则表达式,你想要写的很可能不是那样。
你写道:“^ * $应该匹配字符串/行的开头任意次,然后是字符串/行的结尾”,这意味着你想要多行regexp,但是你忘记了一行无法启动两次,中间没有一条线。
此外,您在要求中提出的问题实际上符合“127.0.0.1”:)“^”不是换行/回车,而是行的开头,“$”不仅仅是换行但是结束了。
此外,“*”尽可能匹配(除非设置了ungreedy模式),这意味着regexp /^.**$/ regexp将匹配所有内容。如果您想管理换行符,则必须明确地对其进行编码。
希望这能澄清一些事情:)
答案 5 :(得分:0)
POSIX正则表达式标准非常陈旧且有限。今天仍然关注的几个工具,如grep,sed和friends,大多数都在unix / linux shell上。 Perl和PCRE是两种非常扩展的口味,其中POSIX标准中几乎没有提到的东西仍然适用。
http://www.regular-expressions.info/refflavors.html
在PCRE和Perl中,引擎将^
和$
视为与字符串的开头和结尾匹配的标记(如果设置了多行标记,则为行)。 *
只需重复^
个标记零次或多次(在这种情况下,恰好为零次)。因此引擎只查找源字符串的末尾,它匹配任何字符串。
答案 6 :(得分:-1)
使用RegexDesigner,我可以看到它在'127.0.0.1'后面的'null'标记上匹配。似乎因为你没有指定一个令牌而加号匹配零次或多次,它匹配'null'令牌。
以下正则表达式应该有效:
^+$