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

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

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

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

выход мне нужен список:

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

Я не герой в регулярных выражениях и гуглил, но мои швы Google-kungfu должны быть слабыми ...

как мне перейти от ввода к требуемому выходу?

6 ответов


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

\w+

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

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

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

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

вот мои матчи:

1 на компьютере
2 ТЫ
3 был
4 PWN3D
Пять einszwei
6 drei

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

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

EDIT 2:
У меня есть нашел более краткий способ получить эффект отрицательного lookbehind: двойной отрицательный класс символов с одним отрицательным исключением.

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

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

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

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


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

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


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


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

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]

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

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

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

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

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


Я написал расширение для строки вроде этого:

    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();
    }