refactor: подтянуть Legal NER, переформатировать код и добавить тесты
Слияние с 685ec97 (третья ступень NER для юридических реквизитов),
код приведён к google-java-format, добавлены юнит-тесты
AdaptiveConcurrencyLimiter/SystemsConfig/PayloadCipher.
This commit is contained in:
@@ -6,80 +6,102 @@ import ru.pdguard.detect.Validators;
|
||||
/**
|
||||
* Правдоподобные подставные значения вместо настоящих.
|
||||
*
|
||||
* <p>Модель получает текст, который выглядит естественно, и качество ответа
|
||||
* страдает меньше, чем от звёздочек. Значения детерминированы: одно и то же
|
||||
* исходное значение всегда даёт одну и ту же подстановку.
|
||||
* <p>Модель получает текст, который выглядит естественно, и качество ответа страдает меньше, чем от
|
||||
* звёздочек. Значения детерминированы: одно и то же исходное значение всегда даёт одну и ту же
|
||||
* подстановку.
|
||||
*/
|
||||
final class Synthetic {
|
||||
|
||||
private static final String[] SURNAMES =
|
||||
{"Лаврентьев", "Мещеряков", "Тихомиров", "Ясенев", "Бурмистров", "Кольцов"};
|
||||
private static final String[] NAMES = {"Артём", "Никита", "Глеб", "Тимур", "Марк", "Лев"};
|
||||
private static final String[] PATRONYMICS =
|
||||
{"Артёмович", "Никитич", "Глебович", "Тимурович", "Маркович", "Львович"};
|
||||
private static final String[] DOMAINS = {"example.com", "example.org", "example.net"};
|
||||
private static final String[] SURNAMES = {
|
||||
"Лаврентьев", "Мещеряков", "Тихомиров", "Ясенев", "Бурмистров", "Кольцов"
|
||||
};
|
||||
private static final String[] NAMES = {"Артём", "Никита", "Глеб", "Тимур", "Марк", "Лев"};
|
||||
private static final String[] PATRONYMICS = {
|
||||
"Артёмович", "Никитич", "Глебович", "Тимурович", "Маркович", "Львович"
|
||||
};
|
||||
private static final String[] DOMAINS = {"example.com", "example.org", "example.net"};
|
||||
|
||||
private Synthetic() {
|
||||
}
|
||||
private Synthetic() {}
|
||||
|
||||
static String forType(String type, String value, int ordinal) {
|
||||
int seed = value.hashCode() & Integer.MAX_VALUE;
|
||||
return switch (type) {
|
||||
case PdTypes.FIO -> pick(SURNAMES, seed) + " " + pick(NAMES, seed >> 3)
|
||||
+ " " + pick(PATRONYMICS, seed >> 6);
|
||||
case PdTypes.CARDHOLDER -> "IVAN PETROV";
|
||||
case PdTypes.EMAIL -> "user" + ordinal + "@" + pick(DOMAINS, seed);
|
||||
case PdTypes.PHONE -> "+7 9" + digits(seed, 2) + " " + digits(seed >> 4, 3)
|
||||
+ "-" + digits(seed >> 8, 2) + "-" + digits(seed >> 12, 2);
|
||||
case PdTypes.CARD -> luhnCard(seed);
|
||||
case PdTypes.PASSPORT, PdTypes.DRIVER_LICENSE, PdTypes.FOREIGN_PASSPORT,
|
||||
PdTypes.MILITARY_ID -> digits(seed, 4) + " " + digits(seed >> 6, 6);
|
||||
case PdTypes.INN -> digits(seed, 12);
|
||||
case PdTypes.MEDICAL_POLICY -> digits(seed, 16);
|
||||
case PdTypes.SNILS -> digits(seed, 3) + "-" + digits(seed >> 4, 3)
|
||||
+ "-" + digits(seed >> 8, 3) + " " + digits(seed >> 12, 2);
|
||||
case PdTypes.BIRTH_DATE, PdTypes.PASSPORT_DATE, PdTypes.DATE -> syntheticDate(seed);
|
||||
case PdTypes.ADDRESS_CITY -> "Зареченск";
|
||||
case PdTypes.ADDRESS_STREET -> "Сосновая";
|
||||
case PdTypes.ADDRESS_HOUSE -> String.valueOf(1 + Math.floorMod(seed, 90));
|
||||
case PdTypes.ADDRESS_FLAT -> String.valueOf(1 + Math.floorMod(seed, 200));
|
||||
case PdTypes.ADDRESS_POSTCODE -> digits(seed, 6);
|
||||
case PdTypes.ADDRESS_COUNTRY -> "Заречье";
|
||||
case PdTypes.ADDRESS_REGION -> "Заречная область";
|
||||
case PdTypes.ADDRESS_DISTRICT -> "Сосновый район";
|
||||
case PdTypes.CVV -> digits(seed, 3);
|
||||
case PdTypes.PIN -> digits(seed, 4);
|
||||
// Для остальных типов правдоподобной замены нет — отдаём токен.
|
||||
default -> "[" + type + "_" + ordinal + "]";
|
||||
};
|
||||
}
|
||||
static String forType(String type, String value, int ordinal) {
|
||||
int seed = value.hashCode() & Integer.MAX_VALUE;
|
||||
return switch (type) {
|
||||
case PdTypes.FIO ->
|
||||
pick(SURNAMES, seed) + " " + pick(NAMES, seed >> 3) + " " + pick(PATRONYMICS, seed >> 6);
|
||||
case PdTypes.CARDHOLDER -> "IVAN PETROV";
|
||||
case PdTypes.EMAIL -> "user" + ordinal + "@" + pick(DOMAINS, seed);
|
||||
case PdTypes.PHONE ->
|
||||
"+7 9"
|
||||
+ digits(seed, 2)
|
||||
+ " "
|
||||
+ digits(seed >> 4, 3)
|
||||
+ "-"
|
||||
+ digits(seed >> 8, 2)
|
||||
+ "-"
|
||||
+ digits(seed >> 12, 2);
|
||||
case PdTypes.CARD -> luhnCard(seed);
|
||||
case PdTypes.PASSPORT,
|
||||
PdTypes.DRIVER_LICENSE,
|
||||
PdTypes.FOREIGN_PASSPORT,
|
||||
PdTypes.MILITARY_ID ->
|
||||
digits(seed, 4) + " " + digits(seed >> 6, 6);
|
||||
case PdTypes.INN -> digits(seed, 12);
|
||||
case PdTypes.MEDICAL_POLICY -> digits(seed, 16);
|
||||
case PdTypes.SNILS ->
|
||||
digits(seed, 3)
|
||||
+ "-"
|
||||
+ digits(seed >> 4, 3)
|
||||
+ "-"
|
||||
+ digits(seed >> 8, 3)
|
||||
+ " "
|
||||
+ digits(seed >> 12, 2);
|
||||
case PdTypes.BIRTH_DATE, PdTypes.PASSPORT_DATE, PdTypes.DATE -> syntheticDate(seed);
|
||||
case PdTypes.ADDRESS_CITY -> "Зареченск";
|
||||
case PdTypes.ADDRESS_STREET -> "Сосновая";
|
||||
case PdTypes.ADDRESS_HOUSE -> String.valueOf(1 + Math.floorMod(seed, 90));
|
||||
case PdTypes.ADDRESS_FLAT -> String.valueOf(1 + Math.floorMod(seed, 200));
|
||||
case PdTypes.ADDRESS_POSTCODE -> digits(seed, 6);
|
||||
case PdTypes.ADDRESS_COUNTRY -> "Заречье";
|
||||
case PdTypes.ADDRESS_REGION -> "Заречная область";
|
||||
case PdTypes.ADDRESS_DISTRICT -> "Сосновый район";
|
||||
case PdTypes.CVV -> digits(seed, 3);
|
||||
case PdTypes.PIN -> digits(seed, 4);
|
||||
// Для остальных типов правдоподобной замены нет — отдаём токен.
|
||||
default -> "[" + type + "_" + ordinal + "]";
|
||||
};
|
||||
}
|
||||
|
||||
private static String pick(String[] options, int seed) {
|
||||
return options[Math.floorMod(seed, options.length)];
|
||||
}
|
||||
private static String pick(String[] options, int seed) {
|
||||
return options[Math.floorMod(seed, options.length)];
|
||||
}
|
||||
|
||||
private static String syntheticDate(int seed) {
|
||||
int day = 1 + Math.floorMod(seed, 28);
|
||||
int month = 1 + Math.floorMod(seed >> 5, 12);
|
||||
int year = 1960 + Math.floorMod(seed >> 9, 45);
|
||||
return String.format("%02d.%02d.%d", day, month, year);
|
||||
}
|
||||
private static String syntheticDate(int seed) {
|
||||
int day = 1 + Math.floorMod(seed, 28);
|
||||
int month = 1 + Math.floorMod(seed >> 5, 12);
|
||||
int year = 1960 + Math.floorMod(seed >> 9, 45);
|
||||
return String.format("%02d.%02d.%d", day, month, year);
|
||||
}
|
||||
|
||||
private static String digits(int seed, int count) {
|
||||
StringBuilder sb = new StringBuilder(count);
|
||||
int value = Math.abs(seed);
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append((char) ('0' + Math.floorMod(value, 10)));
|
||||
value = value / 10 + (i + 1) * 7;
|
||||
}
|
||||
return sb.toString();
|
||||
private static String digits(int seed, int count) {
|
||||
StringBuilder sb = new StringBuilder(count);
|
||||
int value = Math.abs(seed);
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append((char) ('0' + Math.floorMod(value, 10)));
|
||||
value = value / 10 + (i + 1) * 7;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** Номер карты, проходящий проверку алгоритмом Луна: подстановка должна выглядеть настоящей. */
|
||||
private static String luhnCard(int seed) {
|
||||
StringBuilder body = new StringBuilder("4").append(digits(seed, 14));
|
||||
body.append(Validators.luhnCheckDigit(body.toString()));
|
||||
return body.substring(0, 4) + " " + body.substring(4, 8) + " "
|
||||
+ body.substring(8, 12) + " " + body.substring(12);
|
||||
}
|
||||
/** Номер карты, проходящий проверку алгоритмом Луна: подстановка должна выглядеть настоящей. */
|
||||
private static String luhnCard(int seed) {
|
||||
StringBuilder body = new StringBuilder("4").append(digits(seed, 14));
|
||||
body.append(Validators.luhnCheckDigit(body.toString()));
|
||||
return body.substring(0, 4)
|
||||
+ " "
|
||||
+ body.substring(4, 8)
|
||||
+ " "
|
||||
+ body.substring(8, 12)
|
||||
+ " "
|
||||
+ body.substring(12);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user