【问题标题】:Puzzled by output of Regular Expression Replacement对正则表达式替换的输出感到困惑
【发布时间】:2013-12-17 21:35:54
【问题描述】:

我一直在尝试理解 Regex.Replace 调用的输出,但我对它的输出感到困惑。

我有一个字典。我想搜索输入字符串中的键,如果字符串存在于字符串的开头、字符串的结尾或字符串的中间(如果它被一个或每边有更多的空间。

我的输入字符串如下:

North S West N East W South E W S N West South

这段代码中的正则表达式如下:

(^| +?)SOUTH($| +?)|(^| +?)NORTH($| +?)|(^| +?)EAST($| +?)|(^| +?)WEST($| +?)|(^| +?)E($| +?)|(^| +?)W($| +?)|(^| +?)N($| +?)|(^| +?)S($| +?)

我的预期输出是:

N SOUTH W NORTH E WEST S EAST WEST SOUTH NORTH W S

我的实际输出是:

N S W N E W S E WEST S NORTH WEST S

代码如下。 RegEx 模式由字典的键构成。我觉得我只是误解了一些简单的正则表达式。为什么它会提取一些的词而不是所有的词?例如,为什么它不匹配字符串末尾附近的单词 West,但 匹配 匹配字符串开头附近的单词 West?我添加了代码来编写每个匹配项和模式字符串,但我很难过。

void Main()
{
        var directions = new Dictionary<string, string>
        {
            {"SOUTH", "S"},
            {"NORTH", "N"},
            {"EAST", "E"},
            {"WEST", "W"},
            {"E", "EAST"},
            {"W", "WEST"},
            {"N", "NORTH"},
            {"S", "SOUTH"},
        };

        string input = @"North S West N East W South E W S N West South";

        Console.WriteLine(doReplace(input, directions));
}

private string doReplace(string input, Dictionary<string, string> lookup)
{
    string output = null;

    //Construct the regular expression pattern
    string searchPattern = string.Join(@"|", lookup.Select(s => @"(^| +?)" + s.Key + @"($| +?)").ToArray());
    Console.WriteLine(searchPattern);

    //Perform the replace
    output = Regex.Replace(input.ToUpper(), searchPattern, new MatchEvaluator(m =>
    {
        //Write out each match found
        Console.WriteLine("[{0}]", m.Value);

        string tmp = m.Value.Trim();
        string result = tmp;
        lookup.TryGetValue(tmp, out result);

        //This return statement is for the lambda not the method.
        return m.Value.Replace(tmp, result);
    }), RegexOptions.ExplicitCapture|RegexOptions.Singleline);

    return output;
}

【问题讨论】:

  • @user2864740 - 实际的正则表达式是在代码中构造的,并使用 Console.WriteLine 输出,但我已经用值更新了问题。
  • @user2864740 - 我不知道你还想要什么。我发布了常规表达式、输入、预期输出和实际输出。我还发布了一个简短但完整的程序,可以产生相同的结果。请让我知道我还能提供什么。
  • 使用@"(?:^|\s*)SOUTH|NORTH|EAST|WEST|E|W|N|S(?:$|\s*)"作为正则表达式会发生什么?
  • @user2864740 - 这似乎产生了正确的输出。我认为我构造的正则表达式有问题,但你知道它为什么表现得那么奇怪吗?谢谢,我会继续测试的。

标签: c# regex


【解决方案1】:

您的问题是您的正则表达式的元素(除非匹配位于字符串的开头/结尾)在匹配前后至少需要一个空格:

(^| +?)SOUTH($| +?)

匹配一个空格,然后是SOUTH,然后是另一个空格。现在,如果下一个可能的匹配在此之后立即开始,则必须有一个 second 空格字符才能开始下一个匹配。但是单词之间只有一个空格,所以最多每个其他单词都可以匹配。

例如,您可以将这个here 可视化。

如果您的目标是只匹配整个单词而不是子字符串,请使用 \b word boundary anchors\bSOUTH\b 将匹配 SOUTH 但不匹配 SOUTHERN

【讨论】:

  • 我将尝试使用单词边界锚点。我的目标之一是用一个替换 3 个单独的 RegEx。因此,如果我有三个不同的正则表达式:'^SOUTH' 和'SOUTH' 和'SOUTH$',我将如何实现呢? (单引号仅供评论)
  • @ChrisDunaway: \bSOUTH\b 会处理这三个问题。试试\b(SOUTH|NORTH|WEST|EAST|S|N|W|E)\b - 涵盖所有情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-05
  • 2012-03-14
  • 1970-01-01
  • 2016-04-06
  • 1970-01-01
相关资源
最近更新 更多