feat: add formatter and check function

This commit is contained in:
Methapon Metanipat 2024-10-02 15:02:12 +07:00
parent d4ef35c220
commit 5d292c5a5c

View file

@ -1,55 +1,76 @@
import moment from 'moment';
type MRZ = { type MRZ = {
type: 'TD1' | 'TD2' | 'TD3'; type: 'TD1' | 'TD2' | 'TD3';
zone: string[]; zone: string[];
}; };
const FIELD_LIST = {
name: {
field: 'full_name',
format: (value: string) => value.replace(/0/, 'O'),
},
country: {
field: 'country',
format: (value: string) => value.replace(/0/, 'O'),
},
birthDate: {
field: 'birth_date',
format: (value: string) => moment(value, 'YYMMDD').format('YYYY-MM-DD'),
},
expireDate: {
field: 'expireDate',
format: (value: string) => moment(value, 'YYMMDD').format('YYYY-MM-DD'),
},
};
const MRZ_TD_1 = [ const MRZ_TD_1 = [
new RegExp( new RegExp(
[ [
'(?<doc_type>[0-9A-Z<]{1})', `(?<doc_type>[0-9A-Z<]{1})`,
'(?<doc_subtype>[A-Z<]{1})', `(?<doc_subtype>[A-Z<]{1})`,
'(?<country>[0-9A-Z<]{3})', `(?<${FIELD_LIST.country.field}>[0-9A-Z<]{3})`,
'(?<doc_number>[0-9A-Z<]{9})', `(?<doc_number>[0-9A-Z<]{9})`,
'(?<doc_number_check>[0-9A-Z<]{1})', `(?<doc_number_check>[0-9A-Z<]{1})`,
'(?<complement>[0-9A-Z<]{15})', `(?<optional_data>[0-9A-Z<]{15})`,
].join(''), ].join(''),
), ),
new RegExp( new RegExp(
[ [
'(?<birth_date>[0-9A-Z<]{6})', `(?<${FIELD_LIST.birthDate.field}>[0-9A-Z<]{6})`,
'(?<birth_date_check>[0-9A-Z<]{1})', `(?<birth_date_check>[0-9A-Z<]{1})`,
'(?<sex>[mfMF<]{1})', `(?<sex>[mfMF<]{1})`,
'(?<expire_date>[0-9A-Z<]{6})', `(?<${FIELD_LIST.expireDate.field}>[0-9A-Z<]{6})`,
'(?<expire_date_check>[0-9A-Z<]{1})', `(?<expire_date_check>[0-9A-Z<]{1})`,
'(?<nationality>[0-9A-Z<]{3})', `(?<nationality>[0-9A-Z<]{3})`,
'(?<optional_data>[A-Z0-9<]{11})', `(?<optional_data>[A-Z0-9<]{11})`,
'(?<linecheck>[0-9A-Z<]{1})', `(?<line_check>[0-9A-Z<]{1})`,
].join(''), ].join(''),
), ),
new RegExp(['(?<full_name>[A-Z<]{30})'].join('')), new RegExp([`(?<${FIELD_LIST.name.field}>[A-Z<]{30})`].join('')),
]; ];
const MRZ_TD_2 = [ const MRZ_TD_2 = [
new RegExp( new RegExp(
[ [
'(?<doc_type>[0-9A-Z<]{1})', `(?<doc_type>[0-9A-Z<]{1})`,
'(?<doc_subtype>[A-Z<]{1})', `(?<doc_subtype>[A-Z<]{1})`,
'(?<country>[0-9A-Z<]{3})', `(?<${FIELD_LIST.country.field}>[0-9A-Z<]{3})`,
'(?<full_name>[A-Z<]{31})', `(?<${FIELD_LIST.name.field}>[A-Z<]{31})`,
].join(''), ].join(''),
), ),
new RegExp( new RegExp(
[ [
'(?<doc_number>[0-9A-Z<]{9})', `(?<doc_number>[0-9A-Z<]{9})`,
'(?<doc_numbercheck>[0-9A-Z<]{1})', `(?<doc_numbercheck>[0-9A-Z<]{1})`,
'(?<nacionality>[0-9A-Z<]{3})', `(?<nationality>[0-9A-Z<]{3})`,
'(?<birth_date>[0-9A-Z<]{6})', `(?<birth_date>[0-9A-Z<]{6})`,
'(?<birth_date_check>[0-9A-Z<]{1})', `(?<birth_date_check>[0-9A-Z<]{1})`,
'(?<sex>[mfMF]{1})', `(?<sex>[mfMF]{1})`,
'(?<expire_date>[0-9A-Z<]{6})', `(?<expire_date>[0-9A-Z<]{6})`,
'(?<expire_date_check>[0-9A-Z<]{1})', `(?<expire_date_check>[0-9A-Z<]{1})`,
'(?<optional_data>[A-Z0-9<]{7})', `(?<optional_data>[A-Z0-9<]{7})`,
'(?<line_check>[0-9A-Z<]{1})', `(?<line_check>[0-9A-Z<]{1})`,
].join(''), ].join(''),
), ),
]; ];
@ -57,26 +78,26 @@ const MRZ_TD_2 = [
const MRZ_TD_3 = [ const MRZ_TD_3 = [
new RegExp( new RegExp(
[ [
'(?<doc_type>[A-Z0-9<]{1})', `(?<doc_type>[A-Z0-9<]{1})`,
'(?<doc_subtype>[A-Z0-9<]{1})', `(?<doc_subtype>[A-Z0-9<]{1})`,
'(?<country>[A-Z0-9]{3})', `(?<${FIELD_LIST.country.field}>[0-9A-Z<]{3})`,
'(?<full_name>[A-Z0-9<]{39})', `(?<${FIELD_LIST.name.field}>[A-Z0-9<]{39})`,
].join(''), ].join(''),
), ),
new RegExp( new RegExp(
[ [
'(?<doc_number>[0-9A-Z<]{9})', `(?<doc_number>[0-9A-Z<]{9})`,
'(?<doc_number_check>[0-9A-Z<]{1})', `(?<doc_number_check>[0-9A-Z<]{1})`,
'(?<nationality>[0-9A-Z<]{3})', `(?<nationality>[0-9A-Z<]{3})`,
'(?<birth_date>[0-9A-Z<]{6})', `(?<${FIELD_LIST.birthDate.field}>[0-9A-Z<]{6})`,
'(?<birth_date_check>[0-9A-Z<]{1})', `(?<birth_date_check>[0-9A-Z<]{1})`,
'(?<sex>[mfMF<]{1})', `(?<sex>[mfMF<]{1})`,
'(?<expire_date>[0-9A-Z<]{6})', `(?<${FIELD_LIST.expireDate.field}>[0-9A-Z<]{6})`,
'(?<expire_date_check>[0-9A-Z<]{1})', `(?<expire_date_check>[0-9A-Z<]{1})`,
'(?<personal_number>[A-Z0-9<]{14})', `(?<optional_data>[A-Z0-9<]{14})`,
'(?<personal_number_check>[0-9A-Z<]{1})', `(?<optional_data_check>[0-9A-Z<]{1})`,
'(?<linecheck>[0-9A-Z<]{1})', `(?<line_check>[0-9A-Z<]{1})`,
].join(''), ].join(''),
), ),
]; ];
@ -88,9 +109,27 @@ function mrzCleanResult(obj: Record<string, string>) {
.replace(/\s{2,}/, ' ') .replace(/\s{2,}/, ' ')
.trim(); .trim();
}); });
for (const value of Object.values(FIELD_LIST)) {
if (obj[value.field]) obj[value.field] = value.format(obj[value.field]);
}
return obj; return obj;
} }
export function checkData(data: string, num: number) {
const sum = data.split('').reduce((a, v, i) => {
const num = Number(v);
const weight = [7, 3, 1][i % 3];
if (Number.isNaN(num)) {
return a + (v.charCodeAt(0) - 55) * weight;
}
return a + num * weight;
}, 0);
return sum % 10 === num;
}
export function parseType1(mrz: MRZ) { export function parseType1(mrz: MRZ) {
const result: Record<string, string> = {}; const result: Record<string, string> = {};