EOL特殊字符不匹配

4

我正在尝试在输入字符串中查找每个“a -> b,c,d”模式。 我使用的模式如下:

"^[ \t]*(\\w+)[ \t]*->[ \t]*(\\w+)((?:,[ \t]*\\w+)*)$"

这个模式是一个C#模式,"\t"代表制表符(它是单个转义字面量,由.NET字符串API解释),"\w"代表预定义的正则表达式字面量类,双重转义以被.NET字符串API解释为"\w",然后由.NET Regex API解释为“WORD CLASS”。
输入为:
a -> b
b -> c
c -> d

该函数是:

private void ParseAndBuildGraph(String input) {
    MatchCollection mc = Regex.Matches(input, "^[ \t]*(\\w+)[ \t]*->[ \t]*(\\w+)((?:,[ \t]*\\w+)*)$", RegexOptions.Multiline);
    foreach (Match m in mc) {
        Debug.WriteLine(m.Value);
    }
}

输出结果为:
c -> d

实际上,“$”特殊字符的行结束有问题。如果我在“$”之前插入“\r”,它就可以工作,但是我认为“$”会匹配任何行终止符(使用多行选项),特别是Windows环境中的\r\n。难道不是这样吗?

3个回答

7
这也让我感到惊讶。在.NET正则表达式中,$不会匹配行分隔符之前的字符,而是匹配换行符——即字符\n之前的字符。这种行为与Perl的正则表达式风格一致,但在我看来仍然是错误的。根据Unicode标准$应该在以下任何一个字符之前匹配: \n\r\n\r\x85\u2028\u2029\v\f ...并且永远不会在\r\n之间匹配。Java遵守这个规定(除了\v\f),但.NET出现得比Java晚,其Unicode支持至少与Java一样好,却只识别\n。考虑到Microsoft与该行分隔符密切相关,你会认为他们至少会正确处理\r\n
请注意,. 遵循相同的规则:它不匹配 \n(除非设置了 Singleline 模式),但是它会匹配 \r。如果你在正则表达式中使用了 .+ 而不是 \w+,你可能没有注意到这个问题;回车符将包含在匹配项中,但是当你打印结果时控制台会忽略它。

编辑:如果您想允许回车符而不将其包含在结果中,可以使用 lookahead 替换锚点:(?=\r?\n


谢谢您的回答。确实,这是一个令人惊讶的结论 :) - Aurelien Ribon
想知道是否有一个标志可以设置,使系统像C/C++中的O_BINARY标志一样匹配数据。 - Dave
@Dave:我找不到。 我最终设法找到了有关此问题的提及,他们唯一提供的救济措施是在锚点前加上\r?: http://msdn.microsoft.com/en-us/library/h5181w5w.aspx#End - Alan Moore
也许有点难以置信,尤其是来自于主要操作系统的开发者,要使用\r\n作为换行符,但这绝对是真实的。我的建议解决方法是先将输入字符串中所有的\r去掉。 - Jan Goyvaerts

1
你是指正则表达式中的 \t 还是 C# 中的 \t?我通常会在正则表达式中使用逐字字符串:
@"^[ \t]*(\w+)[ \t]*->[ \t]*(\w+)(,[ \t]*\w+)*$"

(唯一需要转义的是 ",将其转义为 ""


实际上,\t 指的是制表符。我不想使用 \s 来表示空格字符,因为我不希望用户输入行尾,只允许输入空格和制表符。但是我的问题仍然与简化模式 "^(\w+) -> (\w+)((?:, \w+)*)$" 相同。我已更新原始问题。 - Aurelien Ribon
@Aurélien - 是的,但是如果没有原样字符串字面量,正则表达式根本看不到\t - Marc Gravell
@Guvante是对的:正则表达式编译器会将制表符视为字面字符,并进行匹配(我已经测试过了)。而使用你的版本,它会将\t序列视为制表符的转义序列;无论哪种方式都可以正常工作。 - Alan Moore
好的,知道了,谢谢。我曾经想删除它,但这是C# /正则表达式中常见的错误,所以我留下来供后人参考。 - Marc Gravell
1
@Aurélien:如果你真的需要一个带有制表符的字符串,请使用旧式字面量。但是,为了匹配正则表达式中的制表符,反斜杠-'t'同样有效,就像我之前说的那样。 - Alan Moore
显示剩余4条评论

1
通常在C、C++、C#中,程序中的字符串使用"\n"作为换行符。如果打开了文本模式转换,则"\r\n"仅出现在I/O层。

好观点。我总是很惊讶这个问题为什么这么少被提及,我想这也是其中一个原因。但我仍然认为他们不采用Unicode标准是错误的。 - Alan Moore
"\r\n" 是 Microsoft 的行終止符號。例如,Notepad.exe 不認識 "\n" 終止符號,只認識 "\r\n"。對於 Unix 用戶來說,"\n" 是通常的行終止符號;而對於 Mac 用戶來說,則是 "\r"。這真是一團糟糕的混亂!我同意 :-) - Aurelien Ribon
\r\n 是文本文件(在 Windows 中)的行终止符。 \n 是代码中的终止符。I/O 层仅在以“文本模式”打开文件时才在它们之间进行转换。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接