Регулярное выражение для поиска и удаления повторяющихся слов - PullRequest
7 голосов
/ 29 июня 2009

Используя регулярные выражения в C #, есть ли способ найти и удалить повторяющиеся слова или символы в строке, содержащей множество слов и символов?

Пример.

Начальная строка слов:

«Мне нравится окружающая среда. Окружающая среда хорошая.»

Желаемая строка:

«Мне нравится окружающая среда. Это хорошо»

Удалены дубликаты:"the", "environment", "."

Ответы [ 9 ]

13 голосов
/ 29 июня 2009

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

var words = new HashSet<string>();
string text = "I like the environment. The environment is good.";
text = Regex.Replace(text, "\\w+", m =>
                     words.Add(m.Value.ToUpperInvariant())
                         ? m.Value
                         : String.Empty);
11 голосов
/ 31 июля 2009

Мне кажется, это работает

(\b\S+\b)(?=.*\1)

Совпадает так же

<b>apple</b> apple orange  
<b>orange</b> red <b>blue</b> <b>green</b> orange green blue  
<b>pirates</b> <b>ninjas</b> cowboys ninjas pirates  
4 голосов
/ 29 июня 2009

Ну, Джефф показал мне, как использовать магию обратных ссылок в выражениях и глобальный модификатор, чтобы это произошло, поэтому мой первоначальный ответ не работает. Вы все должны проголосовать за ответ Джеффа. Тем не менее, для потомков я отмечу, что в этом вопросе есть небольшая проблема с чувствительностью движка регулярных выражений, и если бы вы использовали регулярное выражение со вкусом Perl, вам нужно сделать следующее:

\b(\S+)\b(?=.*\b\1\b.*)

вместо ответа Джеффа, потому что регулярное выражение C # будет эффективно захватывать \b в \1, но PCRE не будет.

2 голосов
/ 29 июня 2009

Посмотрите обратные ссылки:
http://msdn.microsoft.com/en-us/library/thwdfzxy(VS.71).aspx

Это регулярное выражение, которое найдет двойные слова. Но это будет соответствовать только одному слову за матч. Таким образом, вы должны использовать его более одного раза.

new Regex( @"(.*)\b(\w+)\b(.*)(\2)(.*)", RegexOptions.IgnoreCase );

Конечно, это не лучшее решение (см. Другие ответы, в которых предлагается вообще не использовать регулярное выражение). Но вы попросили регулярное выражение - вот один. Может быть, просто идея помогает вам ...

1 голос
/ 29 июня 2009

Регулярные выражения были бы плохим выбором «инструментов» для решения этой проблемы. Возможно, может сработать следующее:

HashSet<string> corpus = new HashSet<string>();
char[] split = new char[] { ' ', '\t', '\r', '\n', '.', ';', ',', ':', ... };

foreach (string line in inputLines)
{
    string[] parts = line.Split(split, StringSplitOptions.RemoveEmptyEntries);
    foreach (string part in parts)
    {
        corpus.Add(part.ToUpperInvariant());
    }
}

// 'corpus' now contains all of the unique tokens

РЕДАКТИРОВАТЬ: Это я делаю большое предположение, что вы "лексуете" для какого-то анализа, например поиска.

0 голосов
/ 31 июля 2009

Некоторые люди, сталкиваясь с проблемой, думают: «Я знаю, я буду использовать регулярные выражения. »Теперь у них есть две проблемы.

См. Когда не использовать Regex в C # (или Java, C ++ и т. Д.)

Конечно, использование регулярного выражения для разбиения строки на слова может быть полезным первым шагом, однако String.Split () понятен и легко выполняет все, что вам нужно.

0 голосов
/ 29 июня 2009

Вы не сможете использовать регулярные выражения для этой проблемы, потому что регулярное выражение соответствует только обычным языкам. Шаблон, которому вы пытаетесь соответствовать, является контекстно-зависимым и, следовательно, не «регулярным».

К счастью, написать парсер достаточно просто. Посмотрите на код Пера Эрика Стендаля.

0 голосов
/ 29 июня 2009

Как уже отмечали другие, это выполнимо с обратными ссылками. См. http://msdn.microsoft.com/nb-no/library/thwdfzxy(en-us).aspx для получения подробных сведений об использовании обратных ссылок в .Net.

Ваша конкретная проблема, связанная с удалением знаков препинания, также усложняет задачу, но я думаю, что код в этих строках (пробел не имеет значения в этом регулярном выражении) должен помочь:

(\b\w+(?:\s+\w+)*)\s+\1

Я вообще не проверял регулярное выражение, но это должно соответствовать одному или нескольким словам, разделенным пробелом, которые повторяются. Вам нужно будет добавить еще немного логики, чтобы учесть пунктуацию и т. Д.

0 голосов
/ 29 июня 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...