feat: denylist streets named after people, fix adjectival surname declension

"Богдана Хмельницкого" and "Великие Луки" (a real city, misread as the
given name "Лука") were already handled by the ORGANISATION_NEARBY veto
added earlier — but only when an organization word is nearby. A street
name with no such word close by ("Живу на улице Карла Маркса") had no
protection, since single-word commemorative streets ("улица Ленина")
never matched the two-word FIO patterns to begin with — it's only the
two-word ones (person's first + last name) that are at risk. Added
~24 of Russia's most common commemorative street-name surnames
(Rosreestr's own ranking: Lenin is #1, Gagarin #2, Kirov #3, ...) to
the existing well-known-people denylist, reusing the mechanism already
built for Pushkin/Tolstoy.

Testing it surfaced a real gap in Declension: surnames declining as an
adjective ("Дзержинский" → "Дзержинского", "-ий" replaced by "-ого"
wholesale, not extended) weren't matching at all in genitive case —
and genitive is the ONLY case a street name is ever written in
("улица Дзержинского", never "улица Дзержинский"). Single-vowel
stripping fixed regular surnames (Пушкин → Пушкина) but not this
pattern. Now strips the whole "-ск-" ending down to the "ск" stem
before falling back to the vowel-strip. Adjectives without "-ск-"
("Толстой" → "Толстого") remain a known, documented limitation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Максименко Никита Владимирович
2026-09-21 22:22:22 +03:00
co-authored by Claude Sonnet 5
parent c25ab9c99f
commit 7f8e0d2d2e
4 changed files with 169 additions and 1 deletions
@@ -10,19 +10,41 @@ import java.util.Locale;
* «Пушкин» → «Пушкина») — там основы из списка достаточно как есть. Слова на
* гласную меняют последнюю букву («Москва» → «Москве», «Ольга» → «Ольге») —
* для них сравнение идёт по основе без неё.
*
* <p>Фамилии на «-ский» склоняются как прилагательное: окончание меняется
* целиком («Дзержинский» → «Дзержинского», «-ий» на «-ого», а не дописывается),
* поэтому для них отсечения одной буквы недостаточно — основа обрезается сразу
* до «ск». Для улиц в честь людей это не редкий случай, а основной: «улица
* Дзержинского», «улица Островского» пишутся только в родительном падеже,
* именительный там не встречается вообще.
*/
final class Declension {
/**
* Падежные окончания прилагательного склонения на «-ск-»: мужской, женский
* и средний род, все падежи. Проверяются от длинных к коротким — «-ского»
* не должно потеряться из-за более короткого совпадения на «-ким» и т.п.
*/
private static final String[] ADJECTIVE_ENDINGS = {
"ского", "скому", "ским", "ском", "скую", "ской", "скою", "ская", "ский"
};
private Declension() {
}
/**
* Отбрасывает у основы конечную гласную, которая меняется по падежам.
* Отбрасывает у основы окончание, которое меняется по падежам: гласную —
* у обычных слов, целиком «-ск-»-окончание — у прилагательных фамилий.
* Слова короче четырёх букв не трогает — короткая основа и так шире
* большинства падежных форм.
*/
static String withoutInflectedEnding(String word) {
String lower = word.toLowerCase(Locale.ROOT);
for (String ending : ADJECTIVE_ENDINGS) {
if (lower.length() > ending.length() && lower.endsWith(ending)) {
return lower.substring(0, lower.length() - ending.length() + 2);
}
}
if (lower.length() >= 4 && "аяйь".indexOf(lower.charAt(lower.length() - 1)) >= 0) {
return lower.substring(0, lower.length() - 1);
}