Регулярное выражение для инкапсуляции любых несоответствующих разделов

#c# #regex

#c# #регулярное выражение

Вопрос:

Используя пример фразы:

Всем мужчинам нравятся виджеты, но некоторым мужчинам нравятся виджеты больше, чем другим

Пример содержит два использования слова виджеты. То, что я пытаюсь сделать, это сопоставить биты снаружи. Обратите внимание, что, хотя виджеты — это одно слово, я ищу решение для регулярных выражений, которое также будет работать с несколькими словами.

Учитывая приведенный выше пример, вывод будет содержать 3 совпадения:

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