---
title: ID驗證系列|身分證字號驗證
date: 2021-03-10
is_modified: true
disqus: cynthiahackmd
categories:
- "先備知識"
tags:
- "編碼規則"
- "Javascript"
- "regexp"
- "臺灣ID驗證系列"
- "Published"
---
{%hackmd @CynthiaChuang/Github-Page-Theme %}
<br>
最近看到一則[有趣的新聞](https://www.ctwant.com/article/61090),原來身分字號 `A123456789` 真有其人阿!決定來稍微了解一下,身分證字號是怎產生出來的,順便寫寫身分證字號檢查器...原本想寫產生器的,但想想還是算了 XD
<!--more-->
<p class="illustration">
<img src="https://i.imgur.com/ggfZhwS.png" alt="中華民國身分證">
中華民國身分證
</p>
## 編號規則
目前現行的身分證字號一共有 **10 碼**,包括起首的大寫的英文字母與接續的九個阿拉伯數字(如:A123456789),大抵可以將身分證字號分成五區:**區域碼**、**性別碼**、**身分碼**、**流水碼**跟**檢核碼**。
<table>
<tbody>
<tr>
<th>區域碼</th>
<th>性別碼</th>
<th>身分碼</th>
<th colspan="6">流水碼 </th>
<th>檢核碼</th>
</tr>
<tr>
<td>A-Z</td>
<td>男:1<br>
女:2</td>
<td>其他:0-5<br>
取得國籍之外國人:6<br>
無戶籍國民:7<br>
港澳居民:8<br>
大陸地區人民:9
</td>
<td colspan="6">阿拉伯數字 </td>
<td>阿拉伯數字</td>
</tr>
</tbody>
</table>
其中首碼的縣市代碼是以報戶口的地區來區分的、而性別代碼則是指首位數字,其中男性為1、女性為2,最後第三碼是身分碼,其中 0-5 是保留給國人,6-9 則是保留給歸化的外國人與中港澳人民使用。
關於第三碼的**身分碼**,在我 2020-08 第一次寫這篇的時候,我並沒有注意到身分碼的資料,但在今天為了寫[《【臺灣ID驗證系列】居留證驗證》](
https://hackmd.io/@CynthiaChuang/Check-Resident-Certificate-Number)在[查資料](http://www.academic.fcu.edu.tw/wSite/public/Attachment/f1582594331972.pdf)的時候,發現了這東西。不過再細查資料,這條規則是在內政部 92 年 4 月 24 日台內戶字第 0920063929 號函規定就被定下了,所以應該是我上次資料漏看了!?
<br>
整體來說,一個完整的身份證字號如下:
<table>
<tbody>
<tr>
<th>區域碼</th>
<th>性別碼</th>
<th>身分碼</th>
<th colspan="6">流水碼 </th>
<th>檢核碼</th>
</tr>
<tr>
<td>A </td>
<td>1 </td>
<td>2 </td>
<td>3 </td>
<td>4 </td>
<td>5 </td>
<td>6 </td>
<td>7 </td>
<td>8 </td>
<td>9 </td>
</tr>
</tbody>
</table>
<br>
在進行編碼檢查時,會將縣市代碼轉換成相對應的數值,如 A 就會被轉換成 `10`:
|A|B|C|D|E|F|G|H|I|J|
|---|---|---|---|---|---|---|---|---|---|
|10|11|12|13|14|15|16|17|34|18|
|K|L|M|N|O|P|Q|R|S|T|
|---|---|---|---|---|---|---|---|---|---|
|19|20|21|22|35|23|24|25|26|27|
|U|V|W|X|Y|Z|
|---|---|---|---|---|---|
|28|29|32|30|31|33|
<br>
將轉換完成的數值,乘上相對應的權重後進行加總:
|Index|$n_0$|$n_1$|$n_2$|$n_3$|$n_4$|$n_5$|$n_6$|$n_7$|$n_8$|$n_9$|$n_{10}$|
|---|---|---|---|---|---|---|---|---|---|---|---|
|權重|1|9|8|7|6|5|4|3|2|1|1|
若總和為 **10 的倍數**,即為有效的驗證碼。
<br>
若改寫成數學判斷式:
$$
(n_0\times 1+n_1\times 9+n_2\times 8+n_3\times 7+n_4\times 6+n_5\times 5+n_6\times 4+n_7\times 3+n_8\times 2+n_9\times 1+n_{10}\times 1)\%10 = 0
$$
<br>
將 `A123456789` 轉換成 `10123456789` 後套入公式如下:
$$
\begin{aligned}
&(1\times 1+0\times 9+1\times 8+2\times 7+3\times 6+4\times 5+5\times 4+6\times 3+7\times 2+8\times 1+9\times 1)\%10 \\
&= (1+0+8+14+18+20+20+18+14+8+9)\%10\\
&= 130\%10\\
&= 0
\end{aligned}
$$
餘數為 0,表有效的 ID。
## 程式碼
有點久沒寫 js 了,順便寫寫 js 練練手好了。把上面的規則寫成程式,如下:
```javascript=
function verifyId(id) {
id = id.trim();
if (id.length != 10) {
console.log("Fail,長度不正確");
return false
}
let countyCode = id.charCodeAt(0);
if (countyCode < 65 | countyCode > 90) {
console.log("Fail,字首英文代號,縣市不正確");
return false
}
let genderCode = id.charCodeAt(1);
if (genderCode != 49 && genderCode != 50) {
console.log("Fail,性別代碼不正確");
return false
}
let serialCode = id.slice(2)
for (let i in serialCode) {
let c = serialCode.charCodeAt(i);
if (c < 48 | c > 57) {
console.log("Fail,數字區出現非數字字元");
return false
}
}
let conver = "ABCDEFGHJKLMNPQRSTUVXYWZIO"
let weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1]
id = String(conver.indexOf(id[0]) + 10) + id.slice(1);
checkSum = 0
for (let i = 0; i < id.length; i++) {
c = parseInt(id[i])
w = weights[i]
checkSum += c * w
}
verification = checkSum % 10 == 0
if (verification) {
console.log("Pass");
} else {
console.log("Fail,檢核碼錯誤");
}
return verification
}
console.log(verifyId("A123456789"));
```
<br>
是說如果不要顯示 log , Regular Expression 可以涵蓋前半段的檢查:
```javascript=
function verifyId(id) {
id = id.trim();
<!-- 在 js 中遇到反斜線要跳脫,所以這邊用兩個反斜線 -->
<!-- 如果你看到四個反斜線,那是我為了讓 NexT.Mist 主題順利渲染所再做跳脫 -->
verification = id.match("^[A-Z][12]\\d{8}$")
if(!verification){
return false
}
let conver = "ABCDEFGHJKLMNPQRSTUVXYWZIO"
let weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1]
id = String(conver.indexOf(id[0]) + 10) + id.slice(1);
checkSum = 0
for (let i = 0; i < id.length; i++) {
c = parseInt(id[i])
w = weights[i]
checkSum += c * w
}
return checkSum % 10 == 0
}
console.log(verifyId("A123456789"));
```
## 進一步驗證規則
因為上述的驗證規則是用於**僅輸入身分證字號的情境**,若使用情境中有輸入性別、戶籍地與出生日期的情況,可在新增:
1. **性別**:
當然就是檢查第二碼來確認啦。
2. **縣市代碼**與戶籍地的對照:
不過這個用到的機會不大,鮮少有情境是輸入戶籍地,多數時候都是輸入通訊地 XD
3. **縣市代碼**與出生日期的比較:
因為縣市合併的關係,目前有部份**縣市代碼**已不再賦配。所以可以比較出生日期與停發日期做進一步檢查。
| 縣市代碼 | 原行政區 | 停發日期 |
| -------- | ------------ | ---------- |
| L | 臺中縣 | 2010/12/25 |
| R | 臺南縣 | 2010/12/25 |
| S | 高雄縣 | 2010/12/25 |
| Y | 陽明山管理局 | 1974/01/01 |
## 參考資料
1. 林姸君 (2020-07-10)。[身分證A123456789真有人 一條龍伯「信用破產」冤跑法庭:別再害我了](https://www.ctwant.com/article/61090)。檢自 ctwant (2020-07-10)。
2. (2006-02-17)。[身分證「A123456789」老被冒用](https://blog.xuite.net/sinner66/blog/5201507-%E8%BA%AB%E5%88%86%E8%AD%89%E3%80%8CA123456789%E3%80%8D%E8%80%81%E8%A2%AB%E5%86%92%E7%94%A8)。檢自 ctwant阿特拉斯的部落格 (2020-07-10)。
3. 協同撰寫。[中華民國國民身分證](https://zh.wikipedia.org/wiki/%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E5%9C%8B%E6%B0%91%E8%BA%AB%E5%88%86%E8%AD%89#%E9%A9%97%E8%AD%89%E8%A6%8F%E5%89%87)。檢自 維基百科 (2020-07-10)。
4. 內政部 (2019-10)。[「外來人口統一證號格式專案」修正計畫(核定本)](http://www.academic.fcu.edu.tw/wSite/public/Attachment/f1582594331972.pdf)。檢自 內政部 (2021-03-10)。
## 更新紀錄
:::spoiler 最後更新日期:2021-03-10
- 2021-03-10 更新:新增身分碼資料
- 2020-08-25 更新:新增 Regular expression
- 2020-08-10 發布
- 2020-07-13 完稿
- 2020-07-10 起稿
:::
{%hackmd @CynthiaChuang/Github-Page-Footer %}