.NET的Regex类和换行符

6
为什么.NET正则表达式不将\n视为行结束符?
示例代码:
string[] words = new string[] { "ab1", "ab2\n", "ab3\n\n", "ab4\r", "ab5\r\n", "ab6\n\r" };
Regex regex = new Regex("^[a-z0-9]+$");
foreach (var word in words)
{
    Console.WriteLine("{0} - {1}", word, regex.IsMatch(word));
}

这是我收到的响应:

ab1 - True
ab2
 - True
ab3

 - False
 - False
ab5
 - False
ab6
 - False

为什么正则表达式匹配 ab2\n
更新: 我不认为使用多行模式是一个好的解决方案,也就是说,我想要验证登录以仅匹配指定字符,并且它必须是单行。如果我改变构造函数为MultiLine选项,则ab1、ab2、ab3和ab6都匹配该表达式,而ab4和ab5不匹配。

为什么ab4没有出现在输出中? - Michael Myers
我猜这是因为\r的缘故 - 这是从控制台精确输出的。 - empi
6个回答

10
.NET 正则表达式引擎将 \n 视为行尾。如果字符串具有 Windows 样式的 \r\n 行分隔符,则会出现问题。当 RegexOptions.Multiline 开启时,$ 匹配 \r\n 之间而不是在 \r 之前,这是一个问题。 $ 在字符串的末尾也进行匹配,就像 \z 一样。区别在于,\z 只能匹配字符串的结尾,而 $ 还可以匹配带有尾部 \n 的字符串的末尾。使用 RegexOptions.Multiline 时,$ 还会在任何 \n 之前进行匹配。
如果遇到换行符的问题,一个技巧是首先进行搜索和替换,将所有的 \r 替换为空,以确保所有行仅以 \n 结尾。

2
我更喜欢用"\n"替换"\r\n",以防万一某些疯狂的文档只有"\r"作为行尾。 - Jimmy

10

如果字符串以换行符结尾,则 RegexOptions.Multiline 将不会起作用。由于最后没有内容,$ 只会忽略最后的换行符。

如果希望匹配至字符串的最后,并忽略任何换行符,请使用 \z

Regex regex = new Regex(@"^[a-z0-9]+\z", RegexOptions.Multiline);

这适用于多行和单行,没有关系。


Smazy,你是对的。我忘了\Z \z元字符(+1)。 - eu-ge-ne
它可以工作,但你知道这种方法是否会引起其他问题吗?\z和$?之间有什么区别? - empi
\z 只匹配字符串的结尾,无论是否有换行符。 - eu-ge-ne

1

使用正则表达式选项,System.Text.RegularExpressions.RegexOptions

string[] words = new string[] { "ab1", "ab2\n", "ab3\n\n", "ab4\r", "ab5\r\n", "ab6\n\r" }; 
Regex regex = new Regex("^[a-z0-9]+$"); 
foreach (var word in words) 
{ 
    Console.WriteLine("{0} - {1}", word,
        regex.IsMatch(word,"^[a-z0-9]+$",
            System.Text.RegularExpressions.RegexOptions.Singleline |
            System.Text.RegularExpressions.RegexOptions.IgnoreCase |
            System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace)); 
}

1

来自RegexOptions

多行模式。更改了 ^ 和 $ 的含义,使它们分别与任何行的开头和结尾匹配,而不仅仅是整个字符串的开头和结尾。

因此,如果您将 RegexOptions.Multiline 传递给 Regex 构造函数,则指示该实例将最终的$视为换行符的匹配项 - 而不仅仅是字符串本身的结尾。


据我所知,我正在指定字符串中可能出现的所有字符,这些字符是[a-z0-9]范围内的字符。我不允许\n出现在字符串中,但是正则表达式仍然匹配带有\n的字符串。我不明白多行模式与此有何关系。 - empi

0

可能是常见的Windows/Linux换行符差异。但仍然很奇怪,这样\n\n会得到一个错误...你尝试过设置RegexOptions.Multiline标志吗?


0

只是为了给Smazy的答案提供更多细节。这是从《正则表达式食谱》(Jan Goyvaerts和Steven Levithan著,版权所有2009年Jan Goyvaerts和Steven Levithan,978-0-596-2068-7)中提取的内容。

‹\Z›和‹\z›之间的区别在于当您的主题文本中的最后一个字符是换行符时,它们就会发挥作用。在这种情况下,‹\Z›可以匹配主题文本的末尾,即最终换行符之后,也可以在该行换行符之前立即匹配。好处是您可以搜索 ‹omega\Z› 而不必担心剥离主题文本末尾的换行符。当逐行读取文件时,有些工具包括行末的换行符,而其他工具则不包括;‹\Z›掩盖了这种差异。‹\z›仅在主题文本的最末端匹配,因此如果跟随一个尾随的换行符,则不会匹配文本。锚点‹$›等同于‹\Z›,只要您没有打开“^和$匹配换行符”选项。默认情况下,所有正则表达式都不支持此选项,除了Ruby。Ruby没有提供关闭此选项的方法。与‹\Z›一样,‹$›匹配主题文本的末尾,以及最终换行符之前(如果有)。

当然,如果没有 Smazy 的答案,我是找不到它的。


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