Подтвердить что ты не робот

Regex заменить несколько групп

Я хотел бы использовать регулярные выражения для замены нескольких групп соответствующей заменой.

Таблица замены:

  • & → __amp
  • # → __hsh
  • 1 → 5
  • 5 → 6

Например, для следующей строки ввода

a1asda & FJ # ahdk5adfls

соответствующая строка вывода

a5asda__ampfj__hshahdk6adfls

Есть ли способ сделать это?

4b9b3361

Ответ 1

Учитывая словарь, который определяет ваши замены:

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

В этом случае используется Replace (docs) которая позволяет вам указать лямбда-выражение для замена.


В комментариях указано, что шаблон поиска с синтаксисом регулярного выражения в нем не будет работать должным образом. Это можно преодолеть, используя 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

Ответ 2

Как насчет использования string.Replace()?

string foo = "a1asda&fj#ahdk5adfls"; 

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

Ответ 3

Подобно Jamiec answer, но это позволяет использовать регулярные выражения, которые не соответствуют тексту точно, например. \. не может использоваться с ответом 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");
}

Затем вызовите регулярное выражение так:

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

Ответ 4

Учитывая словарь, подобный другим ответам, вы можете использовать "совокупность" для сопоставления каждого шаблона в словаре с заменой. Это даст вам гораздо большую гибкость, чем другие ответы, поскольку у вас могут быть разные варианты регулярных выражений для каждого шаблона.

Например, следующий код будет "руналировать" греческий текст (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.Aggregate(input, (i, m) => m.Key.Replace(i, m.Value));