没有将RegexOptions参数传递给Regex编译器的默认点行为

时间:2018-06-28 01:52:12

标签: .net regex

正则表达式的“ ^”和“ $”,see the documentation

  

^默认情况下,匹配必须从字符串的开头开始;在多行模式下,它必须从行的开头开始。

  

$默认情况下,匹配必须发生在字符串末尾或\ n之前。在多行模式下,它必须发生在行尾之前或行尾\ n之前。

这样,我希望当我们指定没有 RegexOptions 参数的 Regex(pattern)时,会产生与 Regex(pattern, RegexOptions.Singleline)

鉴于上述情况,任何人都可以解释以下代码的结果:

var text = $"{Environment.NewLine}a{Environment.NewLine}b";

var patN = @"^.*$";
var reN = new Regex(patN);
var msN = reN.Matches(text);
Console.WriteLine($"Begin and end specified: {msN.Count}");
Console.WriteLine();

var patB = @"^.*";
var reB = new Regex(patB);
var msB = reB.Matches(text);
foreach (var mB in msB)
    Console.WriteLine($"Begin specified only   : {string.Join(" ", mB.ToString().Select(c => (int)c))}");
Console.WriteLine();

var patE = @".*$";
var reE = new Regex(patE);
var msE = reE.Matches(text);
foreach (var mE in msE)
    Console.WriteLine($"End specified only     : {string.Join(" ", mE.ToString().Select(c => (int)c))}");

结果:

Begin and end specified: 0

Begin specified only   : 13

End specified only     : 98
End specified only     : 

字符98为“ b”

2 个答案:

答案 0 :(得分:3)

摘自Regex constructor的文档:

  

调用Regex(String)构造函数等效于为options参数调用值为None的Regex(String,RegexOptions)构造函数。

因此,您对默认行为是SingleLine的期望是错误的。

Default options中所述:

  

^$语言元素与输入字符串的开头和结尾匹配。

第一个示例返回零,因为...来自Quick language reference

  

.通配符:匹配\ n以外的任何单个字符。

答案 1 :(得分:1)

问题的第一部分只是对正则表达式标志m | multiline和s | singleline的常见误解。由于这对于几乎所有正则表达式而言都是很常见的,因此我想引用perlretut
(我将\n替换为newline(稍后再说)和其他小调整)

  

当我们计算和匹配字符时,我们通常希望忽略换行符   排成一行。但是,有时我们想跟踪换行符。我们   甚至可能希望^$锚定在   字符串中的行,而不仅仅是行的开头和结尾   串。 [实现这些修改的大多数正则表达式引擎允许]   在忽略和关注换行之间选择,方法是使用   sm修饰符。 sm代表单行,   多行,并确定是否将一个字符串视为一个   连续的字符串或一组线。这两个修饰符会影响两个   regexp的解释方式:

     
      
  1. .字符如何   类已定义,并且
  2.   
  3. 锚点^$能够匹配的地方。
  4.   
     

以下是四种可能的组合:

     
      
  • 无修饰符:默认行为。 .newline以外的任何字符匹配。 ^仅匹配字符串的开头,$仅匹配字符串   在末尾或在换行符之前。
  •   
  • s修饰符(?s):将字符串视为单个长行。 .匹配任何字符,甚至newline^仅在开始时匹配   字符串和$仅在末尾或在换行符末尾匹配。
  •   
  • m修饰符(?m):将字符串视为一组多行。 .newline以外的任何字符匹配。 ^$能够在   字符串中任何行的开头或结尾。
  •   
  • s和m修饰符(?sm):将字符串视为单个长行,但检测到多行。 .匹配任何字符,甚至newline^   和$,但是可以在任何行的开头或结尾进行匹配   在字符串中。
  •   

由于新的Regex(String)的constructor没有添加任何RegexOptions,因此您肯定处于第一种情况,如前所述。

现在输出。这里的问题是:正则表达式引擎的换行符是什么?如果是Windows或其他操作系统,这是否取决于您的环境(如代码所建议)? .NET documentation on anchors很清楚:regex中的换行符是:\n

引用End of String or Line: $中的一段内容:

  

如果将$与RegexOptions.Multiline选项一起使用,则匹配项可以   也发生在行尾。请注意,$\n匹配,但与   不匹配 \r\n(回车符和换行符或CR / LF的组合)。要匹配CR / LF字符组合,   在正则表达式模式中包含\r?$。 (已添加突出显示)

因此,由于示例代码将Windows环境中的输入文本定义为:\r\na\r\nb,这说明了您的输出:^.*与字符串第一行中的\r相匹配。如果您在Linux环境上运行相同的代码,则不会得到匹配:Sample

运行b的{​​{1}}的匹配现在应该很明显。以下空匹配可能会令人惊讶。但是,由于.*$匹配零个或多个字符,并且.NET regex .*方法的行为类似于全局,因此可以在Matches()之后的位置再次匹配。

奖金:

如果使用b,则以 字符串仍然可以与(?m)start of the string only)匹配,并且字符串的末尾仍可以与锚点\Amatches both the end and the newline before, like $)和{{1} }(matches only the end of the string)。