Regex: как получить слова из строки (C #) - PullRequest
12 голосов
/ 29 января 2010

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

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

Например, скажем, ввод "#@!@LOLOLOL YOU'VE BEEN \***PWN3D*** ! :') !!!1einszwei drei !"

Вывод, который мне нужен, это список:

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

Я не герой в регулярных выражениях, и я гуглюсь, но мой гугл-кунгфу кажется слабым и хэллип;

Как мне перейти от ввода к желаемому выводу?

Ответы [ 6 ]

18 голосов
/ 29 января 2010

Простое регулярное выражение:

\w+

Соответствует строке символов «слово». Это почти что вы хотите.

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

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

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

Вот мои спички:

1 LOLOLOL
2 ВЫ
3 БЫЛ
4 PWN3D
5 einszwei
6 дрей

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

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

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

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

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

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

Обеспечение наличия в строке не более двух несловесных символов. Ака, это соответствует «слово вверх», но не «слово вверх», что имеет смысл. Если вы хотите, чтобы оно совпадало со словом «вверх», но не со словом «вверх», вы можете изменить 2 на 3.

5 голосов
/ 29 января 2010

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

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

2 голосов
/ 29 января 2010

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

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 = "#@!@LOLOLOL 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]
2 голосов
/ 29 января 2010

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

0 голосов
/ 28 октября 2017

Я написал расширение для 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();
    }
0 голосов
/ 29 января 2010

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

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

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

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

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

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