如何将整个字符串与单个正则表达式匹配为两种格式之一?

问题描述 投票:5回答:1

我需要验证可以具有两种格式之一的值,并且尝试使用单个正则表达式执行此操作,但无法弄清楚它为什么不起作用。

第一种格式恰好是17个字母数字字符,表达式^[A-Za-z0-9]{17}$正确匹配测试值5UXWX7C56BA123456但不是缩短值5UXWX7C56BA12345或加长值5UXWX7C56BA1234569

第二种格式恰好是8个字母数字字符,后跟星号或下划线,另外还有两个字母数字字符。表达式^[A-Za-z0-9]{8}[*_][A-Za-z0-9]{2}$正确匹配测试值5UXWX7C5*BA但不是缩短值5UXWX7C5*B或加长值5UXWX7C5*BA1

但是,当我尝试组合表达式时,我会得到不同的意外结果,具体取决于我首先放置的子表达式。以下代码片段演示了

var pattern1 = new Regex(@"^([A-Za-z0-9]{17})|([A-Za-z0-9]{8}[*_][A-Za-z0-9]{2})$");
var pattern2 = new Regex(@"^([A-Za-z0-9]{8}[*_][A-Za-z0-9]{2})|([A-Za-z0-9]{17})$");

var values = new string[] 
{ 
    "5UXWX7C56BA12345", "5UXWX7C56BA123456", "5UXWX7C56BA1234569", 
    "5UXWX7C5*B", "5UXWX7C5*BA", "5UXWX7C5*BA1" 
};

Console.WriteLine($"Using {pattern1}\n");
Console.WriteLine($"  {"Value",-20}{"IsMatch",-9}{"Expected",-10}");
Console.WriteLine($"  {new string('-', 37)}");
values
    .Select(x => new { Value = x, Result = pattern1.IsMatch(x), ExpectedResult = x.Length == 11 || x.Length == 17 })
    .Select(x => $"  {x.Value,-20}{x.Result,-9}{x.ExpectedResult} {(x.Result == x.ExpectedResult ? "" : "UNEXPECTED")}")
    .WithEach(Console.WriteLine);

Console.WriteLine($"\n\nUsing {pattern2}\n");
Console.WriteLine($"  {"Value",-20}{"IsMatch",-9}{"Expected",-10}");
Console.WriteLine($"  {new string('-', 37)}");
values
    .Select(x => new { Value = x, Result = pattern2.IsMatch(x), ExpectedResult = x.Length == 11 || x.Length == 17 })
    .Select(x => $"  {x.Value,-20}{x.Result,-9}{x.ExpectedResult} {(x.Result == x.ExpectedResult ? "" : "UNEXPECTED")}")
    .WithEach(Console.WriteLine);

产生以下结果

Using ^([A-Za-z0-9]{17})|([A-Za-z0-9]{8}[*_][A-Za-z0-9]{2})$

  Value               IsMatch  Expected  
  -------------------------------------
  5UXWX7C56BA12345    False    False 
  5UXWX7C56BA123456   True     True 
  5UXWX7C56BA1234569  True     False UNEXPECTED
  5UXWX7C5*B          False    False 
  5UXWX7C5*BA         True     True 
  5UXWX7C5*BA1        False    False 


Using ^([A-Za-z0-9]{8}[*_][A-Za-z0-9]{2})|([A-Za-z0-9]{17})$

  Value               IsMatch  Expected  
  -------------------------------------
  5UXWX7C56BA12345    False    False 
  5UXWX7C56BA123456   True     True 
  5UXWX7C56BA1234569  True     False UNEXPECTED
  5UXWX7C5*B          False    False 
  5UXWX7C5*BA         True     True 
  5UXWX7C5*BA1        True     False UNEXPECTED

我希望有人能够在我的表达中指出错误。似乎虽然我正在使用^和$来尝试强制匹配整个行/值,但是当某个匹配被发现更长时,即使存在进一步不匹配的字符,我本来希望它会导致整个值不是匹配。

虽然我使用LINQPad运行上面的代码片段,但我看到regex101.com的结果相同。

c# .net regex
1个回答
3
投票

您的正则表达式未正确锚定:

^([A-Za-z0-9]{17})|([A-Za-z0-9]{8}[*_][A-Za-z0-9]{2})$
 ^               ^ ^                                ^                

在这里,([A-Za-z0-9]{17})仅锚定在字符串的开头(并且在该模式之后可以有任何内容)并且([A-Za-z0-9]{8}[*_][A-Za-z0-9]{2})仅锚定在字符串的末尾(并且在该模式之前可以存在任何内容)。

同样的问题是第二种模式,你只是换了替代品。

使用

var pattern1 = new Regex(@"^(?:[A-Za-z0-9]{17}|[A-Za-z0-9]{8}[*_][A-Za-z0-9]{2})$");
                            ^                 ^                                ^

否则,您的替代方案不会固定在双方。

regex demo

© www.soinside.com 2019 - 2024. All rights reserved.