Skip to content

Commit

Permalink
feat: add isChineseIDCardNumber
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed May 28, 2020
1 parent c52e5ec commit bad0b2b
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from 'lodash-es'
export * from './utils/dedent'
export * from './utils/EventBus'
export * from './utils/indent'
export * from './utils/isChineseIDCardNumber'
export * from './utils/isPossibleChineseMobilePhoneNumber'
export * from './utils/isUrl'
export * from './utils/wait'
Expand Down
31 changes: 31 additions & 0 deletions src/utils/isChineseIDCardNumber.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { isChineseIDCardNumber } from './isChineseIDCardNumber'

describe(isChineseIDCardNumber.name, () => {
test('不是合法的身份证号', () => {
for (const value of [
'2000',
'190101881101231',
'110101881301231',
'110101198811214398',
'11010119881101331a',
'469001399208187005',
'46900119925818180x',
'530627199508918277',
'110106100001019457', // 1000 年
'140425900001017773', // 9000 年
]) {
expect(isChineseIDCardNumber(value)).toBeFalse()
}
})

test('是合法的身份证号', () => {
for (const value of [
'110101198811014398',
'11010119881101331X',
'469001199208187005',
'46900119920818180x',
]) {
expect(isChineseIDCardNumber(value)).toBeTrue()
}
})
})
67 changes: 67 additions & 0 deletions src/utils/isChineseIDCardNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const testRegExp = /^[1-9][0-9]{16}[0-9Xx]$/
// prettier-ignore
const areaMap = [11, 12, 13, 14, 15, 21, 22, 23, 31, 32, 33, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 71, 81, 82]
const weightMap = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
const codeMap = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']

const isValidDate = (year: number, month: number, day: number): boolean => {
const date = new Date(year, month - 1, day)
return (
date.getFullYear() === year &&
date.getMonth() + 1 === month &&
date.getDate() === day &&
date.getTime() < new Date().getTime() &&
year > 1900
)
}

/**
* 检测传入的值是否是合法的中国大陆居民 `18` 位身份证号码。
*
* ```
* isChineseIDCardNumber('123456') // => false
* ```
*
* @param value 要检测的值
* @returns 返回检测结果
*/
export function isChineseIDCardNumber(value: string): boolean {
const len = value.length

// 长度错误
if (len !== 18) {
return false
}

// 模式校验
if (!testRegExp.test(value)) {
return false
}

// 地区校验
if (areaMap.indexOf(+value.substr(0, 2)) === -1) {
return false
}

// 出生日期
if (
!isValidDate(
+value.substr(6, 4),
+value.substr(10, 2),
+value.substr(12, 2),
)
) {
return false
}

// 校验码
const sum = value
.split('')
.slice(0, 17)
.reduce((s, num, index) => {
s += +num * weightMap[index]
return s
}, 0)
const code = codeMap[sum % 11]
return code === value[17].toUpperCase()
}
4 changes: 3 additions & 1 deletion src/utils/isPossibleChineseMobilePhoneNumber.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const re = /^1[3-9][0-9]{9}$/

/**
* 检测传入的值是否可能是中国的手机号码。
*
Expand All @@ -10,5 +12,5 @@
* @returns 返回检测结果
*/
export function isPossibleChineseMobilePhoneNumber(value: string | number) {
return /^1[3-9][0-9]{9}$/.test(String(value))
return re.test(String(value))
}
5 changes: 3 additions & 2 deletions src/utils/isUrl.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// http://urlregex.com/ ==> Ruby
const re = /^(?:(?:https?):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i

/**
* 检测传入值是否是 URL。
*
Expand All @@ -10,7 +13,5 @@
* @returns 返回检测结果
*/
export function isUrl(value: string) {
// http://urlregex.com/ ==> Ruby
const re = /^(?:(?:https?):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i
return re.test(value)
}

0 comments on commit bad0b2b

Please sign in to comment.