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