Слияние с 685ec97 (третья ступень NER для юридических реквизитов),
код приведён к google-java-format, добавлены юнит-тесты
AdaptiveConcurrencyLimiter/SystemsConfig/PayloadCipher.
172 lines
9.1 KiB
Java
172 lines
9.1 KiB
Java
package ru.pdguard.detect;
|
||
|
||
import static ru.pdguard.detect.RulePatterns.CITIZENSHIP_GAP;
|
||
import static ru.pdguard.detect.RulePatterns.CITIZENSHIP_VALUE;
|
||
import static ru.pdguard.detect.RulePatterns.ORGANISATION_NEARBY;
|
||
import static ru.pdguard.detect.RulePatterns.ROLE_GAP;
|
||
import static ru.pdguard.detect.RulePatterns.STREET_NAME;
|
||
import static ru.pdguard.detect.RuleRegistry.ADDRESS_NEARBY;
|
||
|
||
import java.util.List;
|
||
|
||
/** Правила распознавания органа выдачи паспорта, места рождения, гражданства и адреса. */
|
||
final class AddressRules {
|
||
|
||
private AddressRules() {}
|
||
|
||
static final List<Rule> RULES =
|
||
List.of(
|
||
|
||
// «выдан ОУФМС России по г. Москве 12.05.2015» — дата в состав органа не входит,
|
||
// её забирает отдельное правило. Приоритет выше городского, иначе от органа
|
||
// осталась бы замаскированной только его часть.
|
||
// Перечень форм, не голая основа «выда»: она зацепила бы и «выдающийся»
|
||
// (обычное слово, не про выдачу документа).
|
||
Rule.of(
|
||
PdTypes.PASSPORT_ISSUER,
|
||
"(?iu:выдан|выдал[аио]?|выдали|выдач[аи]|выдаче)"
|
||
+ "\\W{0,3}([^,;\\n]{3,90}?)"
|
||
+ "(?=\\s*\\d{1,2}[.\\-/]\\d{1,2}[.\\-/]\\d{2,4}|[,;\\n]|\\s*$)",
|
||
78)
|
||
.groups(1)
|
||
.anchoredBy("выдан", "выдал", "выдач"),
|
||
|
||
// «совпадает с указанным в анкете: X» — второе упоминание органа выдачи
|
||
// под собственным якорем, без бэкреференса на первое.
|
||
Rule.of(
|
||
PdTypes.PASSPORT_ISSUER,
|
||
"(?iu:указанн\\w*\\s+в\\s+анкете)\\W{0,5}([^,;.\\n]{3,90}?)"
|
||
+ "(?=[,;.\\n]|\\s*$)",
|
||
78)
|
||
.groups(1)
|
||
.anchoredBy("указанн"),
|
||
|
||
// «Орган выдачи УФМС России по Республике Татарстан» — орган после якоря,
|
||
// до слова «совпадает» или конца фразы.
|
||
Rule.of(
|
||
PdTypes.PASSPORT_ISSUER,
|
||
"(?iu:орган\\s+выдачи)\\W{0,5}([^,;:\\n]{3,90}?)"
|
||
+ "(?=\\s*(?iu:совпадает|указанн)|[,;:\\n]|\\s*$)",
|
||
78)
|
||
.groups(1)
|
||
.anchoredBy("орган выдачи"),
|
||
Rule.of(
|
||
PdTypes.BIRTH_PLACE,
|
||
"(?iu:мест\\w*\\s+рождения)\\W{0,5}([^,;\\n]{3,60}?)(?=\\s*[,;\\n]|\\s*$)",
|
||
76)
|
||
.groups(1)
|
||
.anchoredBy("рождения"),
|
||
Rule.of(
|
||
PdTypes.BIRTH_PLACE,
|
||
"(?iu:родил(?:ся|ась))[^,;\\n]{0,40}?\\s+в\\s+"
|
||
+ "([^,;\\n]{3,40}?)(?=\\s*[,;\\n]|\\s*$)",
|
||
76)
|
||
.groups(1)
|
||
.anchoredBy("родил"),
|
||
|
||
// ROLE_GAP, не \W{0,5}: «Гражданство бенефициара по договору страхования: Х» —
|
||
// между якорем и значением бывает несколько слов, не только пунктуация.
|
||
// Список через запятую/слэш — вторая опциональная группа тем же шаблоном.
|
||
Rule.of(
|
||
PdTypes.CITIZENSHIP,
|
||
"(?iu:гражданств)\\w*"
|
||
+ CITIZENSHIP_GAP
|
||
+ "("
|
||
+ CITIZENSHIP_VALUE
|
||
+ ")(?:\\s*[,/]\\s*("
|
||
+ CITIZENSHIP_VALUE
|
||
+ "))?",
|
||
80)
|
||
.groups(1, 2)
|
||
.validatedBy(CountryDictionary::isKnownCountry)
|
||
.anchoredBy("гражданств"),
|
||
|
||
// ин/ка/ина/ки — именительный/родительный; ином/кой — творительный
|
||
// («гражданином», «гражданкой»).
|
||
Rule.of(
|
||
PdTypes.CITIZENSHIP,
|
||
"(?iu:граждан(?:ин|ка|ина|ки|ином|кой))\\b\\s+"
|
||
+ "("
|
||
+ CITIZENSHIP_VALUE
|
||
+ ")(?:\\s*[,/]\\s*("
|
||
+ CITIZENSHIP_VALUE
|
||
+ "))?",
|
||
75)
|
||
.groups(1, 2)
|
||
.validatedBy(CountryDictionary::isKnownCountry)
|
||
.anchoredBy("граждан"),
|
||
|
||
// --- Адрес: каждая составляющая настраивается отдельно ---
|
||
|
||
Rule.of(PdTypes.ADDRESS_POSTCODE, "(?iu:индекс)\\w*" + ROLE_GAP + "(\\d{6})\\b", 74)
|
||
.groups(1)
|
||
.vetoedBy(ORGANISATION_NEARBY)
|
||
.anchoredBy("индекс"),
|
||
Rule.of(
|
||
PdTypes.ADDRESS_POSTCODE,
|
||
"\\b(\\d{6})(?=\\s*,?\\s*(?iu:г\\.|город|обл\\.|область|респ|край))",
|
||
74)
|
||
.groups(1)
|
||
.vetoedBy(ORGANISATION_NEARBY),
|
||
|
||
// Не только «г.»: перепись, на которой проверяется словарь, покрывает
|
||
// сёла, посёлки, деревни, хутора и станицы — «рп. Ильинское», «с. Кукуево»
|
||
// из ТЗ без этих якорей не нашлись бы вообще, город там ни при чём.
|
||
Rule.of(
|
||
PdTypes.ADDRESS_CITY,
|
||
"(?iu:\\bг\\.|\\bгор\\.|\\bгород|\\bрп\\.|\\bпгт\\.?|\\bп\\.|\\bс\\.|\\bсело\\b"
|
||
+ "|\\bд\\.|\\bдеревня\\b|\\bдер\\.|\\bх\\.|\\bхутор\\b|\\bст-ца|\\bстаница|\\bаул\\b"
|
||
+ "|\\bсл\\.|\\bслобода\\b|\\bаал\\b)\\s?(\\p{Lu}[\\p{L}-]{1,30})\\b",
|
||
73)
|
||
.groups(1)
|
||
.validatedBy(ToponymDictionary::isKnownSettlement)
|
||
.vetoedBy(ORGANISATION_NEARBY)
|
||
.anchoredBy(
|
||
"г.", "гор", "город", "рп.", "пгт", "п.", "с.", "село", "д.", "деревня", "дер.",
|
||
"х.", "хутор", "ст-ца", "станица", "аул", "сл.", "слобода", "аал"),
|
||
Rule.of(
|
||
PdTypes.ADDRESS_STREET,
|
||
"(?iu:\\bул\\.|\\bулиц\\p{L}*|\\bпр-т|\\bпроспект\\p{L}*|\\bпер\\.|\\bпереул\\p{L}*"
|
||
+ "|\\bш\\.|\\bшоссе|\\bб-р|\\bбульвар\\p{L}*|\\bнаб\\.|\\bнабережн\\p{L}*)"
|
||
+ "\\W{0,3}("
|
||
+ STREET_NAME
|
||
+ ")",
|
||
73)
|
||
.groups(1)
|
||
.vetoedBy(ORGANISATION_NEARBY)
|
||
.requiringNear(ADDRESS_NEARBY)
|
||
.anchoredBy("ул", "просп", "пр-т", "пер.", "шоссе", "ш.", "бульвар", "б-р", "наб"),
|
||
|
||
// «Невский пр-т» — указатель после названия. Форма слишком общая, поэтому
|
||
// принимается только рядом с другими частями адреса: иначе под маску попал бы
|
||
// любой рассказ про Невский проспект.
|
||
Rule.of(
|
||
PdTypes.ADDRESS_STREET,
|
||
"\\b(\\p{Lu}[\\p{L}-]{2,30})\\s+"
|
||
+ "(?iu:пр-т|проспект|улиц\\p{L}*|шоссе|бульвар|переул\\p{L}*|набережн\\p{L}*)\\b",
|
||
73)
|
||
.groups(1)
|
||
.vetoedBy(ORGANISATION_NEARBY)
|
||
.requiringNear(ADDRESS_NEARBY)
|
||
.anchoredBy("пр-т", "проспект", "улиц", "шоссе", "бульвар", "переул", "набережн"),
|
||
Rule.of(
|
||
PdTypes.ADDRESS_HOUSE,
|
||
"(?iu:\\bд\\.|\\bдом)\\s?(\\d+\\p{L}?(?:\\s?(?iu:к\\.|корп\\.?|стр\\.)\\s?\\d+)?)\\b",
|
||
72)
|
||
.groups(1)
|
||
.vetoedBy(ORGANISATION_NEARBY)
|
||
.anchoredBy("д.", "дом"),
|
||
Rule.of(PdTypes.ADDRESS_FLAT, "(?iu:\\bкв\\.|\\bквартир\\p{L}*)\\s?(\\d+\\p{L}?)\\b", 72)
|
||
.groups(1)
|
||
.vetoedBy(ORGANISATION_NEARBY)
|
||
.anchoredBy("кв"),
|
||
Rule.of(
|
||
PdTypes.ADDRESS_COUNTRY,
|
||
"(?iu:стран\\p{L}*(?:\\s+(?:регистрации|проживания|гражданства))?)"
|
||
+ "\\W{0,5}(\\p{Lu}[\\p{L}-]{2,30})\\b",
|
||
71)
|
||
.groups(1)
|
||
.vetoedBy(ORGANISATION_NEARBY)
|
||
.anchoredBy("стран"));
|
||
}
|