UNPKG

taiwan-id-validator

Version:

中華民國統一編號、外籍人士居留證統一編號、身分證字號驗證規則、電子發票號碼等規則驗證

431 lines (423 loc) 17.7 kB
(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