taiwan-id-validator
Version:
中華民國統一編號、外籍人士居留證統一編號、身分證字號驗證規則、電子發票號碼等規則驗證
431 lines (423 loc) • 17.7 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["taiwanIdValidator"] = factory();
else
root["taiwanIdValidator"] = factory();
})(this, function() {
return /******/ (function() { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 607:
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
(function (factory) {
if ( true && typeof module.exports === "object") {
var v = factory(__webpack_require__(875), exports);
if (v !== undefined) module.exports = v;
}
else if (true) {
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__, exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isCreditCard = exports.isDonateCode = exports.isCellPhoneBarcode = exports.isCDC = exports.isOriginalRC = exports.isNewRC = exports.isRC = exports.isNI = exports.isGUI = exports.isCreditCardNumberValid = exports.isEInvoiceDonateCodeValid = exports.isEInvoiceCellPhoneBarcodeValid = exports.isCitizenDigitalCertificateNumberValid = exports.isOriginalResidentCertificateNumberValid = exports.isNewResidentCertificateNumberValid = exports.isResidentCertificateNumberValid = exports.isNationalIdentificationNumberValid = exports.isGuiNumberValid = void 0;
function zipWith(a1, a2, f) {
var length = Math.min(a1.length, a2.length);
var result = [];
for (var i = 0; i < length; i++)
result[i] = f(a1[i], a2[i]);
return result;
}
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
/**
* Verify the input is a valid GUI Number (中華民國統一編號)
*
* @param { string | number } input GUI Number
* @param { boolean } extended check input using extended format: https://www.fia.gov.tw/singlehtml/6?cntId=aaa97a9dcf2649d5bdd317f554e24f75
* @returns { boolean } is `input` a valid GUI number
*/
function isGuiNumberValid(input, extended) {
if (extended === void 0) { extended = false; }
if (typeof input !== 'string' && typeof input !== 'number')
return false;
/**
* Example: 12345675
* Step 1:
* 1 * 1 = 1
* 2 * 2 = 4
* 3 * 1 = 3
* 4 * 2 = 8
* 5 * 1 = 5
* 6 * 2 = 12
* 7 * 4 = 28
* 5 * 1 = 5
*
* Step 2:
* 1 -> 1
* 4 -> 4
* 3 -> 3
* 8 -> 8
* 5 -> 5
* 12 -> 1 + 2 = 3
* 28 -> 2 + 8 = 10
* 5 -> 5
*
* Step 3:
* (1 + 4 + 3 + 8 + 5 + 3 + 10 + 5) % 10 = 9
*/
var GUI_NUMBER_COEFFICIENTS = [1, 2, 1, 2, 1, 2, 4, 1];
var n = input.toString();
var regex = /^\d{8}$/;
if (!regex.test(n))
return false;
/**
* Step 1: 先把統一編號的每個數字分別乘上對應的係數 (1, 2, 1, 2, 1, 2, 4, 1)
* Step 2: 再把個別乘積的十位數與個位數相加,得出八個小於 10 的數字
*/
var intRadix = 10;
var checksum = zipWith(GUI_NUMBER_COEFFICIENTS, n.split('').map(function (c) { return parseInt(c, intRadix); }), multiply)
.map(function (n) { return (n % 10) + Math.floor(n / 10); })
.reduce(add, 0);
/**
* Step 3: 檢查把這 8 個數字相加之後計算此和除以 5 or 10 的餘數
* Step 4:
* 4-1: 若是餘數為 0,則為正確的統一編號
* 4-2: 若是餘數為 9,且原統一編號的第七位是 7,則也為正確的統一編號
*/
var divisor = extended ? 5 : 10;
return (checksum % divisor === 0 ||
(parseInt(n.charAt(6), intRadix) === 7 && (checksum + 1) % divisor === 0));
}
exports.isGuiNumberValid = isGuiNumberValid;
/**
* Verify the input is a valid National identification number (中華民國身分證字號)
*
* @param { string } input National identification number
* @returns { boolean } is `input` a valid national ID number
*/
function isNationalIdentificationNumberValid(input) {
if (typeof input !== 'string')
return false;
var regex = /^[A-Z][1,2]\d{8}$/;
return regex.test(input) && verifyTaiwanIdIntermediateString(input);
}
exports.isNationalIdentificationNumberValid = isNationalIdentificationNumberValid;
/**
* Verify the input is a valid resident certificate number (臺灣地區無戶籍國民、外國人、大陸地區人民及香港或澳門居民之專屬代號)
*
* @param { string } input resident certificate number
* @returns { boolean } is `input` a valid resident certificate number
*/
function isResidentCertificateNumberValid(input) {
if (typeof input !== 'string')
return false;
return (isNewResidentCertificateNumberValid(input) ||
isOriginalResidentCertificateNumberValid(input));
}
exports.isResidentCertificateNumberValid = isResidentCertificateNumberValid;
/**
* Verify the input is a valid new resident certificate number (臺灣地區無戶籍國民、外國人、大陸地區人民及香港或澳門居民之專屬代號)
*
* @param { string } input resident certificate number
* @returns { boolean } is `input` a valid new resident certificate number
*/
function isNewResidentCertificateNumberValid(input) {
if (typeof input !== 'string')
return false;
var regex = /^[A-Z][8,9]\d{8}$/;
return regex.test(input) && verifyTaiwanIdIntermediateString(input);
}
exports.isNewResidentCertificateNumberValid = isNewResidentCertificateNumberValid;
/**
* Verify the input is a original valid resident certificate number (臺灣地區無戶籍國民、外國人、大陸地區人民及香港或澳門居民之專屬代號)
*
* @param { string } input resident certificate number
* @returns { boolean } is `input` a valid original resident certificate number
*/
function isOriginalResidentCertificateNumberValid(input) {
if (typeof input !== 'string')
return false;
var regex = /^[A-Z]{2}\d{8}$/;
return regex.test(input) && verifyTaiwanIdIntermediateString(input);
}
exports.isOriginalResidentCertificateNumberValid = isOriginalResidentCertificateNumberValid;
/**
* Verify the input is a valid citizen digital certificate number (自然人憑證)
*
* @param { string } input citizen digital certificate number
* @returns { boolean } is `input` a valid citizen digital certificate number
*/
function isCitizenDigitalCertificateNumberValid(input) {
if (typeof input !== 'string')
return false;
var n = input.toString();
// 驗證規則為兩碼英文 + 14 碼數字
var regex = /^[A-Z]{2}\d{14}$/;
return regex.test(n);
}
exports.isCitizenDigitalCertificateNumberValid = isCitizenDigitalCertificateNumberValid;
/**
* Verify the input is a valid E-Invoice cell phone barcode (電子發票手機條碼)
*
* @param { string } input E-Invoice cell phone barcode
* @returns { boolean } is `input` a valid e-invoice cell phone barcode
*/
function isEInvoiceCellPhoneBarcodeValid(input) {
if (typeof input !== 'string')
return false;
var n = input.toString();
/**
* 總長度為 8 碼
* 第 1 碼為 /
* 第 2-8 碼由 0-9 (數字), A-Z (大寫英文字母), .(period), -(hyphen), +(plus) 組成
*/
var regex = /^\/[\dA-Z.\-+]{7}$/;
return regex.test(n);
}
exports.isEInvoiceCellPhoneBarcodeValid = isEInvoiceCellPhoneBarcodeValid;
/**
* Verify the input is a valid E-Invoice donate code (電子發票捐贈碼)
*
* @param { string | number } input E-Invoice donate code
* @returns { boolean } is `input` a valid e-invoice donate code
*/
function isEInvoiceDonateCodeValid(input) {
if (typeof input !== 'string' && typeof input !== 'number')
return false;
var n = input.toString();
// 總長度為 3-7 碼 0-9 的數字
var regex = /^[\d]{3,7}$/;
return regex.test(n);
}
exports.isEInvoiceDonateCodeValid = isEInvoiceDonateCodeValid;
/**
* Verify the input is a valid credit card number (信用卡卡號)
*
* @param { string | number } input credit card number
* @param { CreditCardValidationOptions } creditCardValidationOptions credit card validation options
* @returns { boolean } is `input` a valid credit card number
*/
function isCreditCardNumberValid(input, options) {
if (options === void 0) { options = {}; }
if (typeof input !== 'string')
return false;
var regex = /^[0-9]{12,19}$/;
if (!regex.test(input))
return false;
// ref:
// https://stackoverflow.com/questions/9315647/regex-credit-card-number-tests
// https://en.wikipedia.org/wiki/Payment_card_number
var issuerRegexes = [
/^3[47][0-9]{13}$/,
/^(6541|6556)[0-9]{12}$/,
/^389[0-9]{11}$/,
/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
/^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})$/,
/^63[7-9][0-9]{13}$/,
/^(?:2131|1800|35\d{3})\d{11}$/,
/^9[0-9]{15}$/,
/^(6304|6706|6709|6771)[0-9]{12,15}$/,
/^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$/,
/^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$/,
/^(6334|6767)[0-9]{12}|(6334|6767)[0-9]{14}|(6334|6767)[0-9]{15}$/,
/^(4903|4905|4911|4936|6333|6759)[0-9]{12}|(4903|4905|4911|4936|6333|6759)[0-9]{14}|(4903|4905|4911|4936|6333|6759)[0-9]{15}|564182[0-9]{10}|564182[0-9]{12}|564182[0-9]{13}|633110[0-9]{10}|633110[0-9]{12}|633110[0-9]{13}$/,
/^(62[0-9]{14,17})$/,
/^4[0-9]{12}(?:[0-9]{3})?$/,
/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$/ // Visa Master
];
var _a = options.checkIssuerRegexes, checkIssuerRegexes = _a === void 0 ? false : _a;
if (checkIssuerRegexes && !issuerRegexes.some(function (regex) { return regex.test(input); }))
return false;
// Luhn algorithm
// ref: https://en.wikipedia.org/wiki/Luhn_algorithm
var digits = input.split('').map(function (d) { return parseInt(d, 10); });
var sum = digits.reverse().reduce(function (acc, d, i) {
if (i % 2 === 0)
return acc + d;
return acc + (d * 2 > 9 ? d * 2 - 9 : d * 2);
}, 0);
return sum % 10 === 0;
}
exports.isCreditCardNumberValid = isCreditCardNumberValid;
/**
* Verify the intermediate string for isNationalIdentificationNumberValid and isResidentCertificateNumberValid
*
* @param { string } input String to verify
* @returns { boolean } is `input` a valid Taiwan ID intermediate string
*/
function verifyTaiwanIdIntermediateString(input) {
var intRadix = 10;
/**
* A=10 台北市 J=18 新竹縣 S=26 高雄縣
* B=11 台中市 K=19 苗栗縣 T=27 屏東縣
* C=12 基隆市 L=20 台中縣 U=28 花蓮縣
* D=13 台南市 M=21 南投縣 V=29 台東縣
* E=14 高雄市 N=22 彰化縣 W=32 金門縣*
* F=15 台北縣 O=35 新竹市* X=30 澎湖縣
* G=16 宜蘭縣 P=23 雲林縣 Y=31 陽明山
* H=17 桃園縣 Q=24 嘉義縣 Z=33 連江縣*
* I=34 嘉義市* R=25 台南縣
*
* Step 1: 英文字母按照上表轉換為數字之後,十位數 * 1 + 個位數 * 9 相加
*/
var TAIWAN_ID_LOCALE_CODE_LIST = [
1,
10,
19,
28,
37,
46,
55,
64,
39,
73,
82,
2,
11,
20,
48,
29,
38,
47,
56,
65,
74,
83,
21,
3,
12,
30 // Z -> 33 -> 1 * 3 + 9 * 3 = 30
];
var RESIDENT_CERTIFICATE_NUMBER_LIST = [
0,
1,
2,
3,
4,
5,
6,
7,
4,
8,
9,
0,
1,
2,
5,
3,
4,
5,
6,
7,
8,
9,
2,
0,
1,
3 // Z
];
var getCharOrder = function (s, i) {
return s.charCodeAt(i) - 'A'.charCodeAt(0);
};
var firstDigit = TAIWAN_ID_LOCALE_CODE_LIST[getCharOrder(input, 0)];
var secondDigit = isNaN(parseInt(input[1], intRadix)) // if is not a number (舊版居留證編號)
? RESIDENT_CERTIFICATE_NUMBER_LIST[getCharOrder(input, 1)]
: parseInt(input[1], intRadix);
var rest = input
.substring(2)
.split('')
.map(function (n) { return parseInt(n, intRadix); });
var idInDigits = __spreadArray([firstDigit, secondDigit], rest, true);
// Step 2: 第 1 位數字 (只能為 1 or 2) 至第 8 位數字分別乘上 8, 7, 6, 5, 4, 3, 2, 1 後相加,再加上第 9 位數字
var ID_COEFFICIENTS = [1, 8, 7, 6, 5, 4, 3, 2, 1, 1];
var sum = zipWith(idInDigits, ID_COEFFICIENTS, multiply).reduce(add, 0);
// Step 3: 如果該數字為 10 的倍數,則為正確身分證字號
return sum % 10 === 0;
}
exports.isGUI = isGuiNumberValid;
exports.isNI = isNationalIdentificationNumberValid;
exports.isRC = isResidentCertificateNumberValid;
exports.isNewRC = isNewResidentCertificateNumberValid;
exports.isOriginalRC = isOriginalResidentCertificateNumberValid;
exports.isCDC = isCitizenDigitalCertificateNumberValid;
exports.isCellPhoneBarcode = isEInvoiceCellPhoneBarcodeValid;
exports.isDonateCode = isEInvoiceDonateCodeValid;
exports.isCreditCard = isCreditCardNumberValid;
});
/***/ }),
/***/ 875:
/***/ (function(module) {
function webpackEmptyContext(req) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
webpackEmptyContext.keys = function() { return []; };
webpackEmptyContext.resolve = webpackEmptyContext;
webpackEmptyContext.id = 875;
module.exports = webpackEmptyContext;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ !function() {
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
/******/ }();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = __webpack_require__(607);
/******/
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=index.map