Я хочу заменить значения строки словарем, который у меня есть, но только если они соответствуют условию регулярного выражения.
Вот что у меня есть:
string input = @"A.4 AND ([10] A.4 OR A.4) OR [10]A.4 A.5 [10]A.5";
Dictionary <string, string> dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
{"A.4", "Test"},
{"A.5", "Test2"},
};
var output = dict.Aggregate(input, (current, value) => current.Replace(value.Key, value.Value));
//current output = "Test AND ([10] Test OR Test) OR [10]Test Test2 [10]Test2"
//wished output = "Test AND ([10] A.4 OR Test) OR [10]A.4 Test2 [10]A.5"
Я не хочу заменять текст, если перед текстом стоит "[10]" или "[10] ". Я думаю, что мне следует использовать регулярное выражение или что-то подобное, но я не знаю, как это сделать.
Как выглядят теги? Если у них есть шаблон, вы можете использовать его в одном регулярном выражении, например, (?<!\[10\]\s?)A\.\d+ будет соответствовать всем значениям A.n без префикса.





Вы можете использовать регулярное выражение для выполнения операции замены:
var output = dict.Aggregate(input, (current, sub) => Regex.Replace(current, $@"(?<!\[10\]\s?){Regex.Escape(sub.Key)}", sub.Value));
Отрицательное утверждение просмотра назад (?<!\[10\]\s?) гарантирует, что совпадающий термин никогда не следует за [10] или [10] .
Как отмечает Панайотис Канавос, вы можете полностью пропустить вызов Aggregate, передав делегату, который выполняет поиск в словаре, Regex.Replace:
var replacePattern = $@"(?<!\[10\]\s?)(?:{string.Join('|', dict.Keys.Select(Regex.Escape))})";
var output = Regex.Replace(input, replacePattern, (m) => dict[m.Value]);
Нет необходимости в Aggregate, по крайней мере, для замены. Regex.Replace имеет перегрузку с делегатом, который возвращает значение замены.
@PanagiotisKanavos Хороший вопрос, добавлено к ответу
@Mathias R. Jessen Большое спасибо, это того стоит. Однако я буду использовать решение с Aggregate, потому что у меня есть такие ключи, как (A.4 и A.41), а во втором решении A.41 не заменяется правильным значением, оно заменяется значением A.4, а затем это 1 в конце. Итак, я использую первый с dict.Reverse().Aggregate(... будучи dict SortedDictionary, поэтому сначала будут проверены самые длинные ключи.
@EvilMorty добавьте \b после последнего ) в replacePattern, чтобы это исправить :)
Regex.Replace имеет перегрузку с делегатом, который создает замещающие значения. Если теги имеют шаблон, можно использовать одно регулярное выражение, чтобы сопоставить их и заменить их значениями словаря.
Это регулярное выражение соответствует тегам в форме A.n, где n число:
var regex=new Regex(@"(?<!\[10\]\s?)A\.\d+");
var output=regex.Replace(input,match=>dict[match.Value]);
Console.WriteLine(output);
Это производит
Test AND ([10] A.4 OR Test) OR [10]A.4 Test2 [10]A.5
(?<!...) — это отрицательный ретроспективный паттерн. Он соответствует строкам, которые не начинаются с инвертированного шаблона. (?<!\[10\]\s?) соответствует строкам, которые не начинаются с [10] и необязательного пробела.
Вы уже упомянули регулярное выражение. Вы пытались использовать Regex.Replace вместо этого? Или, по крайней мере, напишите регулярное выражение, которое соответствует нужным вам частям?