Regex: как получить слова из строки (С#)

Мой вход состоит из строк, помещенных пользователем.

Что я хочу сделать, так это создать словарь со словами и как часто они используются. Это означает, что я хочу разобрать строку, удалить весь мусор и получить список слов в качестве вывода.

Например, скажем, что вход "#@[email protected] YOU'VE BEEN \***PWN3D*** ! :') !!!1einszwei drei !"

Мне нужен следующий вывод:

  • "LOLOLOL"
  • "YOU'VE"
  • "BEEN"
  • "PWN3D"
  • "einszwei"
  • "drei"

Нет никакого героя в регулярных выражениях и был Googling, но мои швы Google-kungfu были слабыми & hellip;

Как я могу перейти от ввода к желаемому результату?

Ответ 1

Простое выражение:

\w+

Это соответствует строке символов "word". Это почти то, что вы хотите.

Это немного более точно:

\w(?<!\d)[\w'-]*

Он соответствует любому количеству символов слова, гарантируя, что первый символ не был цифрой.

Вот мои совпадения:

1 LOLOLOL
2 YOU'VE
3 BEEN
4 PWN3D
5 einszwei
6 drei

Теперь, это больше похоже на него.

EDIT:
Причина негативного внешнего вида заключается в том, что некоторые ароматы регулярных выражений поддерживают символы Unicode. Использование [a-zA-Z] пропустит довольно много символов "слова", которые желательны. Разрешение \w и запрет \d включает в себя все символы Unicode, которые предположительно запустили бы слово в любом блоке текста.

РЕДАКТИРОВАТЬ 2:
Я нашел более сжатый способ получить эффект отрицательного lookbehind: двойной отрицательный класс символов с одним отрицательным исключением.

[^\W\d][\w'-]*(?<=\w)

Это то же самое, что и выше, за исключением того, что он также гарантирует, что слово заканчивается символом слова. И, наконец, есть:

[^\W\d](\w|[-']{1,2}(?=\w))*

Обеспечение того, чтобы в строке было не более двух символов, отличных от слов. Aka, Он соответствует "word-up", но не "word-up", что имеет смысл. Если вы хотите, чтобы он соответствовал "word-up", но не "word-up", вы можете изменить 2 на a 3.

Ответ 2

Вы должны посмотреть на обработку естественного языка (NLP), а не на регулярные выражения, и если вы ориентируетесь на несколько разговорных языков, вам необходимо также учитывать это. Поскольку вы используете С#, посмотрите проект SharpNLP.

Изменить. Этот подход необходим только в том случае, если вы заботитесь о семантическом содержании слов, которые вы пытаетесь разделить.

Ответ 3

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

Ответ 4

Используя следующий

var pattern = new Regex(
  @"( [^\W_\d]              # starting with a letter
                            # followed by a run of either...
      ( [^\W_\d] |          #   more letters or
        [-'\d](?=[^\W_\d])  #   ', -, or digit followed by a letter
      )*
      [^\W_\d]              # and finishing with a letter
    )",
  RegexOptions.IgnorePatternWhitespace);

var input = "#@[email protected] YOU'VE BEEN *PWN3D* ! :') !!!1einszwei drei foo--bar!";

foreach (Match m in pattern.Matches(input))
  Console.WriteLine("[{0}]", m.Groups[1].Value);

выводит вывод

[LOLOLOL]
[YOU'VE]
[BEEN]
[PWN3D]
[einszwei]
[drei]
[foo]
[bar]

Ответ 5

Мое чувство кишки не должно было бы использовать регулярные выражения, а просто сделать цикл или два.

Итерации по каждому char в строке, если не действительный char, замените его пробелом Затем используйте String.Split() и разделите пробелы.

Аппострофы и дефисы могут быть более сложными, чтобы определить, являются ли они нежелательными или легальными. Но если вы используете цикл for для итерации по строке, тогда вам нужно обращать внимание назад и вперед от текущего символа.

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

EDIT: я упомянул только словарь, потому что думал, что вас могут заинтересовать только законные слова, то есть не "asdfasdf", но игнорировать это последнее утверждение, если это не то, что вам нужно.

Ответ 6

Я написал расширение для String следующим образом:

    private static string[] GetWords(string text)
    {
        List<string> lstreturn = new List<string>();
        List<string> lst = text.Split(new[] { ' ' }).ToList();
        foreach (string str in lst)
        {
            if (str.Trim() == "")
            {
                lstreturn.Add(str);
            }
        }
        return lstreturn.ToArray();
    }