Skip to content

实现 身份证校验与解析 工具

分类:developer | 标签:身份证、ID、校验 校验 18 位身份证,解析籍贯、生日、性别、年龄

2.1 功能说明

校验 18 位身份证,解析籍贯、生日、性别、年龄

2.1.1 使用指南

功能说明

校验 18 位身份证校验位,解析省 / 市 / 区、出生日期、性别、年龄,支持 15 位升 18 位、批量校验与脱敏打码。全部在本地浏览器完成,不上传任何数据。

使用场景

表单校验、用户实名信息解析、批量数据清洗。

2.2 代码实现

2.2.1 组件结构

本工具是一个基于 Vue 3 <script setup> 语法的单文件组件(SFC),统一包裹在 ToolPageShell 组件内,由它提供页面标题、工具 ID、分类与「使用指南」插槽等通用外壳;核心业务逻辑(响应式状态、计算属性、事件处理函数)全部写在 <script setup> 中,输入/输出通过 el-inputel-button 等 Element Plus 组件与用户交互,所有数据均在浏览器本地处理,不会上传服务器。

2.2.2 核心逻辑概览

<script setup> 中定义的主要函数/方法:

  • regionOf()
  • parseCore()
  • parseOne()
  • maskOne()
  • parseBatch()
  • downloadBatch()

2.2.3 关键实现代码

以下是该工具的完整 <script setup> 实现(核心代码)。模板(<template>)与样式(<style>)已省略。

vue
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import regionMap from '@/vendor/regions/region-map.json'
import ToolPageShell from '@/components/ToolPageShell.vue'

const tab = ref('one')
const id = ref('')
const err = ref('')
const cur = ref(null)
const batch = ref('')
const batchRows = ref([])

const WEIGHTS = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
const CHECK = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']

function regionOf(code6) {
  const area = regionMap[code6]
  const city = regionMap[code6.slice(0, 4) + '00']
  const prov = regionMap[code6.slice(0, 2) + '0000']
  return [prov, city, area].filter(Boolean).join(' / ')
}

function parseCore(raw) {
  let s = raw.trim().toUpperCase()
  // 15 -> 18
  let upgraded = ''
  if (/^\d{15}$/.test(s)) {
    const y = '19' + s.slice(6, 8)
    let base = s.slice(0, 6) + y + s.slice(8)
    let sum = 0
    for (let i = 0; i < 17; i++) sum += parseInt(base[i], 10) * WEIGHTS[i]
    base += CHECK[sum % 11]
    upgraded = base
    s = base
  }
  if (!/^\d{17}[\dX]$/.test(s)) return { raw, valid: false, reason: '位数或格式不正确' }
  let sum = 0
  for (let i = 0; i < 17; i++) sum += parseInt(s[i], 10) * WEIGHTS[i]
  const valid = CHECK[sum % 11] === s[17]
  const y = +s.slice(6, 10), mo = +s.slice(10, 12), d = +s.slice(12, 14)
  const birth = `${y}-${String(mo).padStart(2, '0')}-${String(d).padStart(2, '0')}`
  const gender = (+s[16] % 2 === 1) ? '男' : '女'
  const now = new Date()
  let age = now.getFullYear() - y
  if (now.getMonth() + 1 < mo || (now.getMonth() + 1 === mo && now.getDate() < d)) age--
  return {
    raw, valid, upgraded: upgraded || undefined,
    region: regionOf(s.slice(0, 6)),
    birth, gender, age
  }
}

function parseOne() {
  err.value = ''; cur.value = null
  if (!id.value.trim()) { err.value = '请输入身份证号'; return }
  const r = parseCore(id.value)
  if (!r.valid && !r.reason) ElMessage.warning('校验位不匹配,请检查号码')
  cur.value = r
}
function maskOne() {
  if (!cur.value) return
  const raw = cur.value.raw
  const masked = raw.length === 18 ? raw.slice(0, 6) + '********' + raw.slice(14) : raw
  cur.value = { ...cur.value, raw: masked, masked: true }
  ElMessage.success('已脱敏:' + masked)
}

function parseBatch() {
  err.value = ''; batchRows.value = []
  const list = batch.value.split(/\r?\n/).map(s => s.trim()).filter(Boolean)
  if (!list.length) { err.value = '请输入身份证号'; return }
  batchRows.value = list.map(parseCore)
  const ok = batchRows.value.filter(r => r.valid).length
  ElMessage.success(`共 ${list.length} 条,校验通过 ${ok} 条`)
}
function downloadBatch() {
  if (!batchRows.value.length) return
  const header = '号码,校验,归属地,出生日期,性别,年龄\n'
  const body = batchRows.value.map(r => [r.raw, r.valid ? '通过' : '失败', r.region || '', r.birth || '', r.gender || '', r.age ?? ''].join(',')).join('\n')
  const blob = new Blob([header + body], { type: 'text/csv;charset=utf-8' })
  const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'idcard-check.csv'; a.click(); URL.revokeObjectURL(a.href)
}

2.3 效果截图

身份证校验与解析 效果截图

工具访问地址:https://www.i91tools.com/tools/id-card