#c# #regex
#c# #регулярное выражение
Вопрос:
Используя пример фразы:
Всем мужчинам нравятся виджеты, но некоторым мужчинам нравятся виджеты больше, чем другим
Пример содержит два использования слова виджеты. То, что я пытаюсь сделать, это сопоставить биты снаружи. Обратите внимание, что, хотя виджеты — это одно слово, я ищу решение для регулярных выражений, которое также будет работать с несколькими словами.
Учитывая приведенный выше пример, вывод будет содержать 3 совпадения:
- Всем мужчинам нравится
- но некоторым людям нравится
- больше, чем другие
Пока у меня есть следующее регулярное выражение, которое работает только частично:
@"(?!widgetsb)bw "
Ограничения заключаются в том, что он не может справиться с фразами из нескольких слов — он также соответствует каждому отрицательному слову, а не всей строке слов, которые предшествуют / следуют за ним, поэтому «все», «мужчины» и «нравится», а не «всем мужчинам нравится».
У меня есть другое решение, которое включает в себя более простое регулярное выражение и некоторые дополнительные изменения в коде c #, но это не то решение, которым я доволен:
string EmboldenString(string text, string termToExclude)
{
var pattern = $@" ?{termToExclude} ?";
var tagStart = "<b>";
var tagEnd = "</b>";
var result = Regex.Replace($"{tagStart}{text}{tagEnd}", pattern, (match) =>
{
return $"{tagEnd}{match}{tagStart}";
});
var emptyTag = tagStart tagEnd;
if (result.StartsWith(emptyTag))
result = result.TrimStart(emptyTag.ToCharArray());
if (result.EndsWith(emptyTag))
result = result.TrimEnd(emptyTag.ToCharArray());
return resu<
}
Как вы можете видеть из приведенного выше кода, цель состоит в том, чтобы добавить теги ко всем несовпадающим битам.
Кто-нибудь поможет с лучшим регулярным выражением.
Комментарии:
1. Используйте
Regex.Split()
вместо этого. Например,b(?:widgets|foo|bar)b
.2. В приведенном выше коде я добавляю теги <b></b> вокруг совпадений, но возвращаю всю строку — как это возможно сделать, если я использую Regex.Split?
Ответ №1:
Вы можете использовать Regex.Split
, а затем обернуть каждый нечетный элемент в результирующем массиве / списке любыми тегами, которые вам нравятся:
var s = "All men like widgets but some men like widgets more than others";
var chunks = Regex.Split(s, @"(s*bwidgetsbs*)");
var result = string.Concat(chunks.Select((i, index) => index % 2 == 0 ? $"<b>{i}</b>" : i));
Console.WriteLine(result);
// => <b>All men like</b> widgets <b>but some men like</b> widgets <b>more than others</b>
Смотрите демонстрацию C #.
(s*bwidgetsbs*)
Шаблон соответствует и захватывает в группу 1 0 пробелов, целое слово widgets
и снова 0 пробелов. Эти совпадения сохраняются в результирующем массиве, поскольку они фиксируются. Каждый нечетный элемент является несогласованной подстрокой.
Если вы не хотите оборачивать пустые несоответствия тегами, добавьте дополнительную !string.IsNullOrWhiteSpace(i)
проверку:
var chunks = Regex.Split(s, @"(s*bwidgetsbs*)");
var result = string.Concat(
chunks.Select((i, index) =>
index % 2 == 0 amp;amp; !string.IsNullOrWhiteSpace(i) ?
$"<b>{i}</b>" : i));
Смотрите эту демонстрацию C #.
Комментарии:
1. Фантастический код Wiktor — но это работает не во всех случаях! Если слово «виджеты» помещается в начале или в конце, а не в середине, добавляется дополнительный набор пустых тегов.
2. @JohnOhara Это правильно как есть: там будут пустые строки. При рендеринге
<b></b>
конечный пользователь не увидит здесь никаких проблем. Если вы хотите, вы можете просто удалить их все на этапе последующей обработки.result = result.Replace("<b></b>", "");
3. @JohnOhara Кроме того, вы не можете написать регулярное выражение, не соответствующее некоторой произвольной многозначной строке в .NET regex. Regex.Split — самое простое решение.
4. @JohnOhara Пожалуйста, также проверьте ideone.com/llY3gi . Кажется, это может работать так, как вам нужно, если вы не обертываете пустые / незаполненные элементы тегами.
5. Спасибо — это здорово.
Ответ №2:
Как предложил Ахмед, вы должны использовать Regex.Spilt()
Вот пример для вашего варианта использования
var op = Regex.Split("All men like widgets but some men like widgets more than others", @"widgets");
Вывод
//All men like
//but some men like
//more than others
Обновить
Вы можете использовать приведенный ниже код
string op = GetTagsAroud("All men like widgets but some men like widgets more than others", @"widgets");
Метод
static string GetTagsAroud(string input, string splitText)
{
var matches = Regex.Split(input, splitText);
StringBuilder output = new StringBuilder();
foreach (string match in matches)
{
output.Append("<b>");
output.Append(match.Trim());
output.Append("</b>");
}
return output.ToString();
}
Комментарии:
1. Спасибо за ответ. Я просто пытаюсь понять, как добавить теги <b></b> вокруг выходных данных. Нет делегата в Regex.Split и не может обновить содержимое ForEach.
2. Итак, вы хотите добавить теги <b> вокруг каждой строки? как <b>Всем мужчинам нравится</b> <b>но некоторым мужчинам нравится</b>?
3. Это правильно, но мне нужно вернуть всю исходную строку после внесения поправок: <b>Всем мужчинам нравятся</b> виджеты <b>, но некоторым мужчинам нравятся</b> виджеты <b> больше, чем другим</b>
4. Спасибо за ваш вклад — не совсем сработало. Теперь принят другой ответ, но вы можете захотеть проверить свой код для собственного любопытства.