【问题标题】:Having a false-match with a regular expression, don't know how to fix与正则表达式错误匹配,不知道如何修复
【发布时间】:2023-04-04 23:10:01
【问题描述】:

我正在尝试检测模式:

字符串 "BP" 后跟 2 个或 4 个双精度值(我稍后要捕获),全部由空格分隔。

例如:

  • BP 1.0 3.5
  • BP -1e-3 0.72 3.7 1.22e2

为了检测 double,我使用了从 here 获得的模式 [+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?

不幸的是,在测试了几个字符串后,我发现我的代码无法区分字符串 BP 后跟 2 个或 4 个数字。这是一些测试用例:

void Main()
{
    var testString = "BP -1.23e4 5.67";

    var mspaces = @"\s*"; // meaning as many spaces as you want
    var cdouble = @"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)"; // meaning capture a double

    var shortPattern = String.Join("",  mspaces, "BP", mspaces, cdouble, mspaces, cdouble, mspaces);
    var longPattern = String.Join("",  mspaces, "BP", mspaces, cdouble, mspaces, cdouble, mspaces, cdouble, mspaces, cdouble, mspaces);

    var bpShort = Regex.Match(testString, shortPattern, RegexOptions.IgnoreCase);
    var bpLong = Regex.Match(testString, longPattern, RegexOptions.IgnoreCase);

    if (bpLong.Success)
    {
        Console.WriteLine("Long pattern detected"); // !!FALSE-MATCH!!
    }
    if (bpShort.Success)
    {
        Console.WriteLine("Short pattern detected");
    }   
}  

在此示例中,即使只有两个数字(-1.23e45.67),代码也会匹配 4 个不同的数字(-1.23e45.67

也许我错误地添加了括号来表示我想要捕获所有数字子元素,或者我是否应该进一步指出双端以空格或字符串结尾,我不知道?

【问题讨论】:

  • 看起来像非贪婪匹配。
  • 附带说明,如果您的分隔符为空,您可以使用string.Concat 而不是Join
  • 为什么不直接匹配cdouble 模式,看看你得到2个还是4个匹配?

标签: c# regex


【解决方案1】:

这很明显。正则表达式总是旨在找到尽可能多的匹配项。因此,如果您查找四个数字,则正则表达式会尽力拆分字符串以匹配四个数字。

要解决此问题,您需要在两个匹配项之间强制使用空格

这可以通过替换来完成:

var mspaces = @"\s*";

作者:

var mspaces = @"\s+";

+ 表示一个或多个,而* 表示零个或多个,因此正则表达式可以决定不在两个数字之间使用空格。)

您还应该删除正则表达式连接中的开头空格。因此替换:

String.Join("",  mspaces, "BP"...

作者:

String.Join("",  "BP"...

还有尾随mspaces。在这种情况下,得到this ideone.com

也许您不想匹配像ABP 1 5 这样的字符串,因为ABP 之间必须有一些空格。在这种情况下,您可以使用 word boundary @"\b"

最后,正如@MattBurland 所说,任何有四个数字的模式当然是一个有两个数字的模式。如果你想让你的字符串结束,你可以在最后使用$。如果希望字符串以BP 开头,可以在前面使用^

【讨论】:

  • 对于 OP 同样值得注意的是,长字符串仍然会匹配短模式,他们可能认为这是一个错误。添加锚点(^$)可以解决这个问题。
  • 非常感谢您的这些清晰的解释,这很有意义。使用$ 也比在较短的字符串之前测试较长的字符串要好得多(这就是我打算区分两者的方式)。
  • 有关信息,我正在解析的字符串是从文件中读取的过滤器描述。我有类似BP 1.0 2.0(带通在 1.0 和 20 之间)或 BR 1.0 1.1 2.0 2.1(带拒绝,第一次转换为1.0 到 1.1 和 2.0 到 2.1 的第二次过渡)。有时在BPBRHP 字母之前会有额外的空格......修剪就足够了..
猜你喜欢
  • 1970-01-01
  • 2017-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多