【问题标题】:Regular expression with specific word boundary具有特定单词边界的正则表达式
【发布时间】:2016-05-26 18:05:15
【问题描述】:

假设我有一个类型的字符串

(Price+Discounted_Price)*2-Max.Price

以及包含每个元素要替换的内容的字典

价格:A1 Discounted_Price:A2 Max.Price:A3

我怎样才能准确地替换每个短语,而不触及另一个。意思是搜索Price 不应修改Discounted_Price 中的Price。结果应该是 (A1+A2)*2-A3 而不是 (A1+Discounted_A1) - Max.A1 或其他任何东西

谢谢。

【问题讨论】:

    标签: c# regex word-boundary


    【解决方案1】:

    如果您的变量可以由字母数字/下划线/点字符组成,您可以将它们与[\w.]+ 正则表达式模式匹配,并添加包含. 的边界:

    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    public class Test
    {
        public static void Main()
        {
            var s = "(Price+Discounted_Price)*2-Max.Price";
            var dct = new Dictionary<string, string>();
            dct.Add("Price", "A1");
            dct.Add("Discounted_Price", "A2");
            dct.Add("Max.Price","A3");
            var res = Regex.Replace(s, @"(?<![\w.])[\w.]+(?![\w.])",     // Find all matches with the regex inside s
                x => dct.ContainsKey(x.Value) ?   // Does the dictionary contain the key that equals the matched text?
                      dct[x.Value] :              // Use the value for the key if it is present to replace current match
                      x.Value);                   // Otherwise, insert the match found back into the result
            Console.WriteLine(res);
        }
    }
    

    IDEONE demo

    如果匹配前面有一个单词或点字符,(?&lt;![\w.]) 否定前瞻将导致匹配失败,如果后面有一个单词或点字符,(?![\w.]) 否定前瞻将导致匹配失败。

    请注意,[\w.]+ 允许在前导和尾随位置使用点,因此,您可能希望将其替换为 \w+(?:\.\w+)* 并用作 @"(?&lt;![\w.])\w+(?:\.\w+)*(?![\w.])"

    更新

    由于您已经将要替换的关键字提取为列表,因此您需要使用更复杂的单词边界,不包括点:

    var listAbove = new List<string> { "Price", "Discounted_Price", "Max.Price" };
    var result = s;
    foreach (string phrase in listAbove)
    {
        result = Regex.Replace(result, @"\b(?<![\w.])" + Regex.Escape(phrase) +  @"\b(?![\w.])", dct[phrase]);
    }
    

    IDEONE demo

    【讨论】:

    • 我不太明白 lambda x => dct.ContainsKey(x.Value) 吗? dct[x.Value] :字典中的 x.Value。它还会引发编译错误“无法将 lambda 转换为类型“int”,因为它不是委托类型”。我们能否以某种方式将其重写为更易于理解的方式以供以后的代码维护者使用?谢谢
    • 为什么是int?请提供您在问题中的输入数据和 a;;您的代码也相关。正如您在 IDEONE 上看到的,我的代码可以编译并且运行良好。您使用的是静态Regex.Replace,还是Regex 对象Replace 方法?
    • 我在问题的代码中添加了对 lambda 的解释。
    • 我的错。因为似乎我的同事似乎按照以下方式进行:放置一个解析器来尝试提取每个短语(Price,Discounted_Price,Max.Price)并遍历所有短语,foreach(listAbove中的字符串短语){result = Regex(inStr,短语,dic[短语])}。我认为解析器不起作用;我得看看他的代码。
    • 你是老板。非常感谢 Wiktor。
    【解决方案2】:

    对于单词边界,您可以使用 \b 使用:\b价格\b

    但这将取代 Max.Price 中的 Price。

    也许您想使用常规字符串替换:

    "价格+" --> A1 + "+"

    例子:

    string test = "(Price+Discounted_Price)*2-Max.Price";
    string a1 = "7";
    string a2 = "3";
    string a3 = "4";
    
    test = test.Replace("(Price", "(" + a1);
    test = test.Replace("Discounted_Price", a2);
    test = test.Replace("Max.Price", a3);
    

    结果:

    测试是:(7+3)*2-4

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-07
      • 2011-04-14
      • 2011-03-28
      • 2012-09-24
      • 1970-01-01
      相关资源
      最近更新 更多