Init
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
package ru.pdguard.detect;
|
||||
|
||||
/**
|
||||
* Проверки контрольных сумм. Отсекают случайные числовые последовательности,
|
||||
* которые по форме похожи на ПД, но ими не являются.
|
||||
*/
|
||||
public final class Validators {
|
||||
|
||||
private static final int[] INN_10 = {2, 4, 10, 3, 5, 9, 4, 6, 8};
|
||||
private static final int[] INN_12_A = {7, 2, 4, 10, 3, 5, 9, 4, 6, 8};
|
||||
private static final int[] INN_12_B = {3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8};
|
||||
|
||||
private Validators() {
|
||||
}
|
||||
|
||||
/** Алгоритм Луна: номер платёжной карты, 13–19 цифр. */
|
||||
public static boolean luhn(String value) {
|
||||
int sum = 0;
|
||||
int digits = 0;
|
||||
boolean doubled = false;
|
||||
for (int i = value.length() - 1; i >= 0; i--) {
|
||||
char c = value.charAt(i);
|
||||
if (!Character.isDigit(c)) {
|
||||
continue;
|
||||
}
|
||||
int d = c - '0';
|
||||
digits++;
|
||||
if (doubled) {
|
||||
d *= 2;
|
||||
if (d > 9) {
|
||||
d -= 9;
|
||||
}
|
||||
}
|
||||
sum += d;
|
||||
doubled = !doubled;
|
||||
}
|
||||
return digits >= 13 && digits <= 19 && sum % 10 == 0;
|
||||
}
|
||||
|
||||
/** Контрольная сумма ИНН: 10 знаков у юрлица, 12 у физлица. */
|
||||
public static boolean inn(String value) {
|
||||
int[] d = digits(value);
|
||||
if (d.length == 10) {
|
||||
return d[9] == checksum(d, INN_10);
|
||||
}
|
||||
if (d.length == 12) {
|
||||
return d[10] == checksum(d, INN_12_A) && d[11] == checksum(d, INN_12_B);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Контрольная сумма СНИЛС: 11 знаков, последние два — контрольные. */
|
||||
public static boolean snils(String value) {
|
||||
int[] d = digits(value);
|
||||
if (d.length != 11) {
|
||||
return false;
|
||||
}
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
sum += d[i] * (9 - i);
|
||||
}
|
||||
int control = sum < 100 ? sum : (sum == 100 || sum == 101 ? 0 : sum % 101 % 100);
|
||||
return control == d[9] * 10 + d[10];
|
||||
}
|
||||
|
||||
/**
|
||||
* Дата в числовой записи при любом порядке частей: {@code 12.05.1985},
|
||||
* {@code 05/12/1985}, {@code 1985-05-12}. Отсекает похожие по форме
|
||||
* последовательности вроде {@code 192.168.1}.
|
||||
*/
|
||||
public static boolean date(String value) {
|
||||
// Запись с названием месяца словом в дополнительной проверке не нуждается:
|
||||
// «мая» само по себе однозначно указывает на дату.
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
if (Character.isLetter(value.charAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
String[] parts = value.split("[.\\-/]");
|
||||
if (parts.length != 3) {
|
||||
return false;
|
||||
}
|
||||
int[] n = new int[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (parts[i].isEmpty() || parts[i].length() > 4) {
|
||||
return false;
|
||||
}
|
||||
n[i] = Integer.parseInt(parts[i]);
|
||||
}
|
||||
for (int y = 0; y < 3; y++) {
|
||||
if (parts[y].length() == 4) {
|
||||
return n[y] >= 1900 && n[y] <= 2100 && dayAndMonth(n[(y + 1) % 3], n[(y + 2) % 3]);
|
||||
}
|
||||
}
|
||||
// Год записан двумя цифрами: достаточно, чтобы день и месяц нашлись в любой паре.
|
||||
return dayAndMonth(n[0], n[1]) || dayAndMonth(n[1], n[2]) || dayAndMonth(n[0], n[2]);
|
||||
}
|
||||
|
||||
/** Пара чисел похожа на «день и месяц» в любом порядке. */
|
||||
private static boolean dayAndMonth(int a, int b) {
|
||||
return (a >= 1 && a <= 31 && b >= 1 && b <= 12) || (b >= 1 && b <= 31 && a >= 1 && a <= 12);
|
||||
}
|
||||
|
||||
private static int checksum(int[] d, int[] weights) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < weights.length; i++) {
|
||||
sum += d[i] * weights[i];
|
||||
}
|
||||
return sum % 11 % 10;
|
||||
}
|
||||
|
||||
private static int[] digits(String value) {
|
||||
int[] out = new int[value.length()];
|
||||
int n = 0;
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (Character.isDigit(c)) {
|
||||
out[n++] = c - '0';
|
||||
}
|
||||
}
|
||||
int[] trimmed = new int[n];
|
||||
System.arraycopy(out, 0, trimmed, 0, n);
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user