Как привести все слова к нижнему регистру и очистить от знаков препинания
Что проверяют
Умеете ли вы работать со строками без привязки к латинице и локали машины. Код в две строки напишет любой, поэтому смотрят на детали: что станет с кириллицей, апострофом и дефисом. Следом часто просят разбить результат на слова и посчитать частоты.
Как отвечать
Рабочий вариант:
private static final Pattern PUNCT = Pattern.compile("\\p{P}+");
String clean = PUNCT.matcher(text.toLowerCase(Locale.ROOT)).replaceAll(" ");
String[] words = clean.trim().split("\\s+");Что стоит проговорить:
toLowerCase(Locale.ROOT): вызов без аргумента берёт локаль JVM по умолчанию. В турецкой локали"TITLE".toLowerCase()даёт"tıtle"с бесточечной «ı», и сравнение строк ломается. Для технической обработки локаль фиксируют явно;\p{P}: класс Unicode-пунктуации, ловит и ёлочки, и длинное тире, и многоточие.\p{Punct}в Java по умолчанию покрывает только ASCII, а шаблон[^a-zA-Z0-9\s]из многих ответов молча вырезает всю кириллицу;- замена на пробел, а не на пустую строку: иначе «привет,мир» склеится в одно слово. Лишние пробелы потом уберут
trim()иsplit("\\s+"); - прекомпиляция:
String.replaceAllкомпилирует регулярное выражение на каждом вызове. В цикле по миллиону строк держитеPatternв полеstatic final; - спорные символы: апостроф и дефис внутри слова («don't», «из-за») формально пунктуация. Спросите, должны ли они оставаться, и при необходимости исключите их из класса.
Без регулярок подойдёт проход по символам с Character.isLetterOrDigit и StringBuilder: быстрее и без сюрпризов с классами символов.
Где спотыкаются
Пишут [^a-zA-Z\s] и не замечают, что на русском тексте от строки останутся одни пробелы.
Вызывают toLowerCase() без локали. На машине разработчика всё работает, а на сервере с турецкой или азербайджанской локалью ключи и сравнения ломаются, и баг всплывает только в проде.
Путают \p{Punct} и \p{P}. Первый не видит типографских кавычек и тире, и текст, скопированный из документа или с сайта, остаётся грязным.