Regex заменить несколько групп - PullRequest
19 голосов
/ 08 сентября 2011

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

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

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

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

a1asda & fj # ahdk5adfls

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

a5asda__ampfj__hshahdk6adfls

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

Ответы [ 4 ]

38 голосов
/ 08 сентября 2011

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

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

Liveпример: 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
6 голосов
/ 08 сентября 2011

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

string foo = "a1asda&fj#ahdk5adfls"; 

string bar = foo.Replace("&","__amp")
                .Replace("#","__hsh")
                .Replace("5", "6")
                .Replace("1", "5");
3 голосов
/ 15 сентября 2011

Аналогично ответу 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");
}

Затем вызовите регулярное выражение для замены следующим образом:

var newString = regex.Replace(text, m => Evaluator(map, m))
2 голосов
/ 12 июня 2015

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

Например, следующий код будет «романизировать» греческий текст (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));
...