【问题标题】:Regex lookahead won't work in .NET正则表达式前瞻在 .NET 中不起作用
【发布时间】:2014-09-09 16:15:58
【问题描述】:

我得到了一个带有前瞻功能的正则表达式,它适用于 Regexr.com,但在 .NET 应用程序中使用时却不行。

这是一些示例输入数据(请注意,我只是为了可读性而创建了换行符,文本实际上只是一长行,因此需要一个正则表达式)。

26. AUG\r\n2014\r\n27.08 Testing 1\r\n -100\r\n
20. AUG\r\n2014\r\n27.08 Testing 2\r\n -90\r\n
15. AUG\r\n2014\r\n27.08 Testing 3\r\n 200\r\n
9. AUG\r\n2014\r\n27.08 Testing 4\r\n 50\r\n
4. AUG\r\n2014\r\n27.08 Testing 5\r\n -200\r\n
25. JUL\r\n2014\r\n27.08 Testing 5\r\n -200\r\n

使用以下正则表达式:

(.+?)(?=(\\r\\n\d{1,2}[.] [A-Z]{3})|$)

,我希望捕获每一行,想用“20.AUG”等来分隔它们。由于分隔符也应该被捕获,所以我使用前瞻。 一切在 Regexr.com 上运行良好,参见此处的示例:http://regexr.com/39fd7

在 .NET 中执行此操作时:

Regex.Matches(input, "(.+?)(?=(\r\n\\d{1,2}[.] [A-Z]{3})|$)")

我只得到这些结果:

-100
-90
200
50
-200
-200

我尝试过各种 RegexOptions,例如多行和其他一些,但没有结果。

非常感谢任何帮助或提示。谢谢

【问题讨论】:

  • 您在该链接上显示的表达式与您在 .NET 中使用的表达式不同。特别是,序列\\r\\n\d 变成了<CRLF>\d,其中<CRLF> 是字符串中的文字回车换行符。
  • 这到底为什么会被否决?它经过充分研究,充分说明了问题,并且清晰简洁。我不知道你认为你还需要什么。
  • 我不确定您的编辑是否正确 @280Z28。这是我使用的确切代码:Regex.Matches(text, "(.+?)(?=(\r\n\\d{1,2}[.] [AZ]{3})|$)" ) 为什么需要转义 \r\n ?我想我在 d 之前忘记了一个双 \ ..

标签: c# .net regex regex-lookarounds


【解决方案1】:

编辑

根据 cmets,很明显原始问题具有误导性。问题源于以下几点:

原始的 C# 代码使用包含精确字符序列的字符串文字\r\n,如下所示:

string input = "Example\r\nText";

字符串的内容随后原封不动地复制到在线正则表达式测试器,因此测试在以下等价物上运行:

string notActuallyTheInput = "Example\\r\\nText"; 

现在很清楚,这个问题意味着input 字符串文字写在一行上,但输入本身确实跨越了多行。因此,问题出在表达式的(.+?) 部分。与Robin mentioned 一样,. 字符默认不匹配换行符。所需的行为是 RegexOptions.Singleline 选项的行为,如以下示例程序所示。

using System;
using System.Text.RegularExpressions;

class Program
{
    private const string Input =
        "26. AUG\r\n2014\r\n27.08 Testing 1\r\n -100\r\n" +
        "20. AUG\r\n2014\r\n27.08 Testing 2\r\n -90\r\n" +
        "15. AUG\r\n2014\r\n27.08 Testing 3\r\n 200\r\n" +
        "9. AUG\r\n2014\r\n27.08 Testing 4\r\n 50\r\n" +
        "4. AUG\r\n2014\r\n27.08 Testing 5\r\n -200\r\n" +
        "25. JUL\r\n2014\r\n27.08 Testing 5\r\n -200\r\n";

    static void Main(string[] args)
    {
        string pattern = @"(.+?)(?=(\r\n\d{1,2}[.] [A-Z]{3})|$)";
        var matches = Regex.Matches(Input, pattern, RegexOptions.Singleline);

        Console.WriteLine("{0} Matches:", matches.Count);
        foreach (Match match in matches)
            Console.WriteLine("  {0}", match.Value.Replace("\r", "\\r").Replace("\n", "\\n"));

        // OUTPUT:
        //
        // 7 Matches:
        //   26. AUG\r\n2014\r\n27.08 Testing 1\r\n -100
        //   \r\n20. AUG\r\n2014\r\n27.08 Testing 2\r\n -90
        //   \r\n15. AUG\r\n2014\r\n27.08 Testing 3\r\n 200
        //   \r\n9. AUG\r\n2014\r\n27.08 Testing 4\r\n 50
        //   \r\n4. AUG\r\n2014\r\n27.08 Testing 5\r\n -200
        //   \r\n25. JUL\r\n2014\r\n27.08 Testing 5\r\n -200\r
        //   \n
    }
}

原答案

问题可能源于将正则表达式错误地转换为 C# 字符串文字。

下面的表达式:

(.+?)(?=(\\r\\n\d{1,2}[.] [A-Z]{3})|$)

将在 C# 字符串文字中写成以下任一形式:

"(.+?)(?=(\\\\r\\\\n\\d{1,2}[.] [A-Z]{3})|$)"

@"(.+?)(?=(\\r\\n\d{1,2}[.] [A-Z]{3})|$)"

由于输入不包含任何引号字符,因此后者肯定是最简单的翻译,因为它是原始表达式的精确副本。

完整的程序重现结果

using System;
using System.Text.RegularExpressions;

class Program
{
    private const string Input =
        "26. AUG\\r\\n2014\\r\\n27.08 Testing 1\\r\\n -100\\r\\n" +
        "20. AUG\\r\\n2014\\r\\n27.08 Testing 2\\r\\n -90\\r\\n" +
        "15. AUG\\r\\n2014\\r\\n27.08 Testing 3\\r\\n 200\\r\\n" +
        "9. AUG\\r\\n2014\\r\\n27.08 Testing 4\\r\\n 50\\r\\n" +
        "4. AUG\\r\\n2014\\r\\n27.08 Testing 5\\r\\n -200\\r\\n" +
        "25. JUL\\r\\n2014\\r\\n27.08 Testing 5\\r\\n -200\\r\\n";

    static void Main(string[] args)
    {
        string pattern = @"(.+?)(?=(\\r\\n\d{1,2}[.] [A-Z]{3})|$)";
        var matches = Regex.Matches(Input, pattern);

        Console.WriteLine("{0} Matches:", matches.Count);
        foreach (Match match in matches)
            Console.WriteLine("  {0}", match.Value);

        // OUTPUT:
        //
        // 6 Matches:
        //   26. AUG\r\n2014\r\n27.08 Testing 1\r\n -100
        //   \r\n20. AUG\r\n2014\r\n27.08 Testing 2\r\n -90
        //   \r\n15. AUG\r\n2014\r\n27.08 Testing 3\r\n 200
        //   \r\n9. AUG\r\n2014\r\n27.08 Testing 4\r\n 50
        //   \r\n4. AUG\r\n2014\r\n27.08 Testing 5\r\n -200
        //   \r\n25. JUL\r\n2014\r\n27.08 Testing 5\r\n -200\r\n
    }
}

【讨论】:

  • 它不起作用。我尝试了两种方法,它只会是一个结果,那就是来自 |$ 的结果。
  • @280Z28 我不认为问题出在不正确的字符转义上。他的正则表达式似乎是正确的
  • @Anirudha 当使用正确的字符串时,C# 输出与他请求的确切输出匹配。
  • @Andreas 当Input 是您在该链接中使用的输入,而pattern 是此答案中的输入,则Regex.Matches(Input, pattern) 返回与您指示为所需结果相同的6 个值从那个链接。
  • 您的程序示例有效。但我的字符串包含 \r\n 而不是 \\r\\n。如果我尝试将您的示例代码修改为该示例代码以及正则表达式,它将给我与以前相同的结果,结果中只有数字(-200 等)。
【解决方案2】:

如果您的文本始终具有相同的格式(4 列,由文字分隔 \r\n),您可以使用这个简单的模式:

string pattern = @"(?:[^\\]+\\r\\n){4}";

example

【讨论】:

  • 看起来不错,我想我可以依靠它。但奇怪的是,我无法让它在 .NET 中工作。但我可以看到它适用于您的示例。在 .NET 中,我只做 Regex.Matches(text, @"(?:[^\]+\r\n){4}") 。它只给出一个结果,所有文本都作为结果。我也试过 \\r\\n 。
  • @Andreas:您在我的答案中看到的模式有很多斜线,无需更改,使用简单的复制/粘贴。
  • 抱歉,没用。见:pastebin.com/yrigAbSW执行之后matches3将没有结果。
  • @Andreas:自然不行,你的原始字符串没有逐字格式!
【解决方案3】:

默认情况下,正则表达式通配符 . 不匹配换行符。

您的字符串显示为“一行”,但包含换行符 (\r\n),一旦在字符串文字中解释,就会阻止点匹配您想要的所有内容。

它将尝试匹配26. AUG,然后是2014...直到-100,当前瞻最终匹配时,您的最终结果。

使用点匹配标志:

(?s).+?(?=\\r\\n\d{1,2}[.] [A-Z]{3}|$)

【讨论】:

  • 对不起,这不起作用。只给出一个实际上是整行的结果。
  • 尽管确切的正则表达式对我不起作用,但您对“一行”的看法是正确的,谢谢。正如 280Z28 回答的那样,我所要做的就是添加 Singleline 选项。
猜你喜欢
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 2017-04-22
  • 1970-01-01
  • 2014-03-31
  • 2019-04-05
  • 2015-09-13
相关资源
最近更新 更多