package ru.pdguard.detect; import java.util.Locale; import java.util.Set; /** * Словарь населённых пунктов России — проверка того, что значение, пойманное правилом {@code * ADDRESS_CITY}, действительно похоже на существующий город, село, посёлок или другой населённый * пункт, а не на произвольное слово с заглавной буквы после якоря. * *
Не только официальные города (~1100 по классификатору): перепись добавляет сёла, деревни, * хутора, станицы — «рп. Ильинское», «с. Кукуево» из ТЗ находятся ровно за счёт неё. Какой * конкретно тип населённого пункта стоит перед названием, определяет якорь самого правила в {@link * RuleRegistry}, а не этот словарь — он только подтверждает, что название реальное. * *
Сравнение по началу слова, а не точным совпадением: падежные окончания («в Москве», «из
* Казани») тем самым покрываются без отдельного разбора морфологии, как и у известных людей в
* {@link NameDictionary}.
*/
public final class ToponymDictionary {
private static final Set Названия на согласную склоняются добавлением окончания («Тамбов» → «Тамбове»), поэтому
* начало слова из словаря — уже достаточный признак. Названия на гласную меняют последнюю букву
* («Москва» → «Москве»), для них сравнение идёт по основе без неё — так же, как с личными именами
* в {@link NameDictionary}.
*
* Проверяются префиксы значения по множеству, а не каждая из ~80 000 основ по значению:
* перебор списка на каждое совпадение правила был бы на порядки дороже, чем нужно — префиксов у
* слова не больше, чем в нём букв.
*/
public static boolean isKnownSettlement(String value) {
String lower = value.strip().toLowerCase(Locale.ROOT);
for (int length = lower.length(); length > 0; length--) {
if (SETTLEMENT_STEMS.contains(lower.substring(0, length))) {
return true;
}
}
return false;
}
}