Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Удалить подстроку из списка строк

Автор вопроса: SkoderОтветов: 4

У меня есть список строк, содержащих запрещенные слова. Какой эффективный способ проверить, содержит ли строка какие-либо запрещенные слова, и удалить их из строки? На данный момент у меня так:

cleaned = String.Join(" ", str.Split().Where(b => !bannedWords.Contains(b,
                            StringComparer.OrdinalIgnoreCase)).ToArray());

Это отлично работает для отдельных запрещенных слов, но не для фраз (например, more than one word). Любой экземпляр more than one word также должен быть удален. Альтернативой, которую я хотел попробовать, является использование метода List из списка, но он возвращает только логическое значение, а не индекс соответствующего слова. Если бы я мог получить индекс подходящего слова, я мог бы просто использовать String.Replace(bannedWords[i],"");

  • В чем эффективность? Представление? Длина кода? zmbq 08.04.2012
  • Проблема сводится к простому поиску и замене, пока вы не сделаете ключевую ошибку: thedailywtf.com/Articles/The-Clbuttic-Mistake-.aspx Kendall Frey 08.04.2012
  • что не так с вашим решением в отношении "более одного слова" - если оно перекрывается, вы можете отсортировать их по длине, от большего к меньшему? Более эффективным было бы "перечислить" до конца, но вам все равно нужно быть осторожным с "перекрытиями". NSGaga-mostly-inactive 08.04.2012

listregexlinqreplace

Ответы

Ответ 1 · рейтинг 2 · Olivier Jacot-Descombes

Простой String.Replace не будет работать, так как он удалит части слова. Если "секс" - запрещенное слово, а у вас есть слово "секстет", которое не запрещено, вы должны оставить его как есть.

С помощью Regex вы можете найти целые слова и фразы в тексте с

string text = "A sextet is a musical composition for six instruments or voices.".
string word = "sex";
var matches = Regex.Matches(text, @"(?<=\b)" + word + @"(?=\b)");

В этом случае коллекция спичек будет пустой.

Вы можете использовать метод Regex.Replace

foreach (string word in bannedWords) {
    text = Regex.Replace(text, @"(?<=\b)" + word + @"(?=\b)", "")
}

Примечание. Я использовал следующий шаблон Regex

(?<=prefix)find(?=suffix)

где "префикс" и "суффикс" равны \b, что обозначает начало и конец слова.

Если ваши запрещенные слова или фразы могут содержать специальные символы, было бы безопаснее экранировать их с помощью Regex.Escape(word).


Используя идею @zmbq, вы можете создать шаблон Regex один раз с помощью

string pattern =
    @"(?<=\b)(" +
    String.Join(
        "|",
        bannedWords
            .Select(w => Regex.Escape(w))
            .ToArray()) +
     @")(?=\b)";
var regex = new Regex(pattern); // Is compiled by default

а затем многократно применять его к разным текстам с помощью

string result = regex.Replace(text, "");

Ответ 2 · рейтинг 2 · Henk Holterman

Это не работает, потому что у вас противоречивые определения.

Когда вы хотите искать подпредложения, такие как more than one word, вы больше не можете разбивать по пробелам. Вам придется вернуться к String.IndexOf()

Ответ 3 · рейтинг 1 · zmbq

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

Затем я попытался бы сопоставить его с текстом и заменить каждое совпадение пробелом или чем-то, чем вы хотите его заменить.

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

Ответ 4 · Zafer

Почему бы вам не просмотреть список запрещенных слов и не найти каждое из них в строке с помощью метода string.IndexOf. Например, вы можете удалить запрещенные слова и фразы с помощью следующего фрагмента кода:

myForbWords.ForEach(delegate(string item) {
    int occ = str.IndexOf(item);
    if(occ > -1) str = str.Remove(occ, item.Length);
});

Тип myForbWords List<string>.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы