Regex替换多个组

本文关键字:替换 Regex | 更新日期: 2023-09-27 18:07:54

我想使用正则表达式用相应的替换字符串替换多个组。

替换表:

  • "&" -> "__amp"
  • "#" -> "__hsh"
  • "1" -> "5"
  • "5" -> "6"

例如,对于下面的输入字符串

"a1asda&fj#ahdk5adfls"

对应的输出字符串是

"a5asda__ampfj__hshahdk6adfls"

有办法吗?

Regex替换多个组

给定一个定义您的替换的字典:

IDictionary<string, string> map = new Dictionary<string, string>()
{
    {"&","__amp"},
    {"#","__hsh"},
    {"1","5"},
    {"5","6"},
};

您可以使用它来构造正则表达式,并为每个匹配形成替换:

var str = "a1asda&fj#ahdk5adfls";
var regex = new Regex(String.Join("|",map.Keys));
var newStr = regex.Replace(str, m => map[m.Value]);
// newStr = a5asda__ampfj__hshahdk6adfls

实例:http://rextester.com/rundotnet?code=ADDN57626

使用Regex.Replace重载,允许您为替换指定lambda表达式。


在注释中已经指出,包含regex语法的find模式不会像预期的那样工作。这可以通过使用Regex.Escape和对上面的代码做一个小的修改来克服:

var str = "a1asda&fj#ahdk5adfls";
var regex = new Regex(String.Join("|",map.Keys.Select(k => Regex.Escape(k))));
var newStr = regex.Replace(str, m => map[m.Value]);
// newStr = a5asda__ampfj__hshahdk6adfls

给定与其他答案类似的字典,您可以使用"聚合"将字典中的每个模式映射到替换模式。这将为您提供比其他答案更大的灵活性,因为您可以为每个模式提供不同的正则表达式选项。

例如,下面的代码将希腊文本(https://en.wikipedia.org/w/index.php?title=Romanization_of_Greek&section=3#Modern_Greek, Standard/UN)"罗马化":

var map = new Dictionary<string,string>() {
    {"α[ύυ](?=[άαβγδέεζήηίΐϊιλμνόορύΰϋυώω])", "av"}, {"α[ύυ]", "af"}, {"α[ϊΐ]", "aï"}, {"α[ιί]", "ai"}, {"[άα]", "a"},
    {"β", "v"}, {"γ(?=[γξχ])", "n"}, {"γ", "g"}, {"δ", "d"},
    {"ε[υύ](?=[άαβγδέεζήηίΐϊιλμνόορύΰϋυώω])", "ev"}, {"ε[υύ]", "ef"}, {"ει", "ei"}, {"[εέ]", "e"}, {"ζ", "z"},
    {"η[υύ](?=[άαβγδέεζήηίΐϊιλμνόορύΰϋυώω])", "iv"}, {"η[υύ]", "if"}, {"[ηήιί]", "i"}, {"[ϊΐ]", "ï"},
    {"θ", "th"}, {"κ", "k"}, {"λ", "l"}, {"''bμπ|μπ''b", "b"}, {"μπ", "mb"}, {"μ", "m"}, {"ν", "n"},
    {"ο[ιί]", "oi"}, {"ο[υύ]", "ou"}, {"[οόωώ]", "o"}, {"ξ", "x"}, {"π", "p"}, {"ρ", "r"},
    {"[σς]", "s"}, {"τ", "t"}, {"[υύϋΰ]", "y"}, {"φ", "f"}, {"χ", "ch"}, {"ψ", "ps"}
};
var input = "Ο Καλύμνιος σφουγγαράς ψυθίρισε πως θα βουτήξει χωρίς να διστάζει."; 
map.Aggregate(input, (i, m) => Regex.Replace(i, m.Key, m.Value, RegexOptions.IgnoreCase));

返回(不修改"input"变量)

"o kalymnios sfoungaras psythirise pos tha voutixei choris na distazei."

你当然可以这样写:

foreach (var m in map) input = Regex.Replace(input, m.Key, m.Value, RegexOptions.IgnoreCase);

会修改"input"变量。

你也可以添加这个来提高性能:

var remap = new Dictionary<Regex, string>();
foreach (var m in map) remap.Add(new Regex(m.Key, RegexOptions.IgnoreCase | RegexOptions.Compiled), m.Value);

缓存或将remap字典设为static,然后使用:

remap.Aggregate(input, (i, m) => m.Key.Replace(i, m.Value));

使用string.Replace()如何?

string foo = "a1asda&fj#ahdk5adfls"; 
string bar = foo.Replace("&","__amp")
                .Replace("#","__hsh")
                .Replace("5", "6")
                .Replace("1", "5");

与Jamiec的答案类似,但这允许您使用不完全匹配文本的正则表达式,例如'.不能与Jamiec的答案一起使用,因为您无法在字典中查找匹配。

此解决方案依赖于创建组,查找匹配的组,然后查找替换值。它更复杂,但更灵活。

首先使映射成为KeyValuePairs的列表

var map = new List<KeyValuePair<string, string>>();           
map.Add(new KeyValuePair<string, string>("'.", "dot"));

然后像这样创建你的正则表达式:

string pattern = String.Join("|", map.Select(k => "(" + k.Key + ")"));
var regex = new Regex(pattern, RegexOptions.Compiled);

那么匹配求值器就变得有点复杂了:

private static string Evaluator(List<KeyValuePair<string, string>> map, Match match)
{            
    for (int i = 0; i < match.Groups.Count; i++)
    {
        var group = match.Groups[i];
        if (group.Success)
        {
            return map[i].Value;
        }
    }
    //shouldn't happen
    throw new ArgumentException("Match found that doesn't have any successful groups");
}

然后像这样调用正则表达式replace:

var newString = regex.Replace(text, m => Evaluator(map, m))

只是想分享我使用JamiecCostas解决方案的经验。

如果你有这样的问题:给定的键'<搜索参数>'在字典中不存在。

请记住,将正则表达式模式放入字典键

IDictionary<string, string> map = new Dictionary<string, string>()
{
   {"(?<=KeyWord){","("},
   {"}",")"}
};

并像这样使用

var regex = new Regex(String.Join("|",map.Keys));
var newStr = regex.Replace(str, m => map[m.Value]);

var newStr = Regex.Replace(content, pattern, m => replacementMap[m.Value]);

可能抛出上述异常,因为模式是在替换比较之前执行的,只留下要与字典中的regex键进行比较的匹配项。这样键和匹配可能不同,并抛出异常。

'(?<=KeyWord){' != '{'

所以这是我的解决方案:

我必须替换一个"{"与关键字和相应的"}"之后加上"("answers")";分别。

简而言之

@"some random text KeyWord{"Value1", "Value2"} some more 
random text";

@"some random text KeyWord('"Value1", "Value2"') some more 
    random text";

IDictionary<string, string> map = new Dictionary<string, string>()
{
    {"{","('"},
    {"}","')"}
};
var content = @"some random text KeyWord{"Value1", "Value2"} some more 
    random text";
var pattern = "((?<=KeyWord){)|((?<='")})";
var newStr = Regex.Replace(content, pattern, m => map[m.Value]);

希望这一堆乱七八糟的单词对某人有用