日本郵便番号

北海道

因為工作的關係,要做日本郵遞區號和地址間的自動補完,還因此開始維護 japan-postal-code-oasis 這個套件,它的前身其實是另外一套叫 japan-postal-code 的,但是它很久沒更新了,所以我就簡單修改一些設計,在研究套件設計的同時就有機會比較深入了解日本的郵遞區號(郵便番号)系統,發現不少有趣的細節,這篇文章特別來紀錄一下。

首先,第一點就是,日本郵遞區號的資料是有整理好並開放下載的,而且下載路徑、檔案格式都是固定的沒什麼變動過,也因此可以找到不少使用這些資料的程式語言套件(包含下載腳本),japan-postal-code 就是透過這份資料來實作從郵遞區號抓地址資訊的功能,雖然不是很想和台灣比,但是這點台灣真的是輸很多,台灣其實到 3+2 郵遞區號都還可以在郵局網站下載的到,但是那個下載連結不是固定的,然後也看不出來是不是固定更新,所以你不會知道你下載的資料是不是最新的,至於最新的 3+3 郵遞區號,就沒有開放大眾下載,取而代之的是提供 Web Service、Windows 應用程式,如果真的要下載資料檔,要特別申請(參照:本公司3+3郵遞區號系統使用規範說明事項),另外就是台灣是一季更新一次,日本則是一個月更新一次。

其實我會注意到日本每個月都更新郵遞區號,是從另外一件事情發現的,在繼續之前,先來介紹一下日本郵遞區號內不同數字的意義,這在日本郵局網站有很詳細的說明,前三碼稱為郵便區番号,後四碼是町域番号,其中的前兩碼是大 block 番号,第三碼則是小 block 番号,基本上都是這樣規劃,理論上不會需要到每個月更新,直到有一天我發現到六本木森大樓,每一層樓都有自己的郵遞區號,例如用 Google Map 搜尋Google Japan (Roppongi Hills),然後查看地址就會發現他的郵遞區號是 106-6126,其中的後兩碼就是 26 樓的意思,然後搜尋Apple Japan合同会社,就會發現郵遞區號是 106-6140,就是 40 樓的意思。後來我才知道,這是屬於 個別番号 之中的超高層大樓番号,除了大樓之外,還有其他種個別番号,像是大型機構(醫院、電視台、公家單位等)也可以申請,而這種個別番号也就是資料內最常會變動的地方,所以他們才有這麼頻繁的資料更新。

其實我還有在一些第三方資料,看到說前三碼的郵便區番号,還可以再更細分成兩組:前兩碼是地域番号,第三碼則是地域調整番号,町域番号的最後一碼則是町域調整番号,另外就是第一版的日本郵遞區號是三碼為主,然後有部分地區有 3+2 碼的設計,網路上還找的到當時(1968、昭和43年)第一版的郵遞區號的清單

再來印在信封上的,手寫郵遞區號的格子,其實在日本郵局網站上也有仔細的定義它的尺寸,甚至連手寫的字體也有提供範例(基本上就是要你不要寫的太潦草),台灣郵局網站我找到的最接近的就是只有信封書寫範例了,其實日本的規範這麼仔細,有一個原因是為了自動化作業。

郵便番号枠

這個自動化作業,其實遠超我的預期,不只是根據郵遞區號分類而已,日本郵局其實定義了一套地址的數位化編碼系統,轉換邏輯也不困難,也就是說,日本國內的任意地址,都可以用一串數字(看情況加上英文字母)來表示,日本地址可以簡單的轉為英數編碼,有一個很大的原因是他們的地址是從大範圍(ex: X丁目X番X号)到小範圍這樣,而不像是其他地方用路加上號碼(ex: XX路X號)的方式,所以其實編碼機制也很簡單,大部分的地址,就是郵遞區號加上後面的三碼,然後再加上可能樓層、房號就可以組成,例如東京鳩居堂 銀座本店,地址是:

〒104-0061 東京都中央区銀座5丁目7−4

轉成編碼就是:

10400615-7-4

前七碼固定式郵便番号,所以不用處理分隔符號的問題。

另外日本地址有個天字第一號(我取名的),大家可以猜猜看是哪個地方的地址,沒錯,就是皇居,郵遞區號是 100-0001,地址是 1 丁目 1 番(沒有号),編碼就是:

10000011-1

而且這套編碼系統還有一組專用的 barcode 系統,可以用掃描的方式輸入,非常方便,barcode 的定義也蠻有趣的,不是用粗細,而是用長短和位置來表達不同意義,一條 bar 有四種(4-state)可能的變化(1-4),所以是 2bit,然後一個字元是三條 bar,所以是 6bit,可以有單一字元或是雙字元,理論上單字元有 64 種組合,雙字元是 12bit 共 4096 種組合,不過其實雙字元的第一個字元固定是控制碼,所以實際上變化沒這麼多,目前也只有定義英數、hyphen 和一些控制字元而已,日本郵局內部似乎還有其他用途,而不是只有標記收件人地址而已,不過細節沒有網站上沒有公開,這部份有分為局內 barcode 和 ID barcode,而自己用這組 barcode 系統標注地址的部分,則是稱為 custom barcode。

郵便番号 カスタマバーコード

至於要如何產生住址的 custom barcode 呢,日本郵局網站是有蠻詳細的說明,包括怎樣拆解地址、怎樣編碼、檢查碼怎樣算等等都有說明。而也還有提供一個 custom barcode 產生程式可以下載,抓下來解開後可以發現是網頁應用程式,上一個世代的,編碼也不是 UTF-8 的,現在還可以正常運作,其實還蠻厲害。

PS. 後來發現其實有蠻多國家的郵務系統是使用類似的 4-state barcode 的。

接下來算是不相關的資訊了,其實我在查資料時,有想研究看看郵便番號有沒有和其他標準相似或是共通的地方,首先是有注意到 ISO 3166-2 這個標準,是每個國家自己有一個子集,定義了各自國家的行政區,例如日本的是 ISO 3166-2:JP,裡面就是用 01-47 從北到南把日本的都道府縣編碼了一遍,而且直接對應到 JIS X 0401,最初是在好奇 JIS 的編碼和郵便番号前兩碼的地域番号有沒有相通,結果當然是沒有。其實我還蠻羨慕日本有 JIS 標準統整各種規範的單位,台灣也是有相關的編碼,只是就是像是 ISO 3166-2:TW Wikipedia 條目裡面列出的,就是各單位各自為政這樣。

另外一套標準(?)則是日本導航系統幾乎都會有支援的 MAPCODE,這個編碼系統就不是官方標準了,而是民間企業 日本電装 (前身是 Toyota 自動車的一個部門)開發的定位系統,是針對日本境內的,用類似 quadtree 的方式,把地圖分割成一小塊一小塊,然後每一塊下去編碼,不過和 quadtree 不一樣的是,不是統一分成四塊,而是分成三個層級,第一級是 Zone 全日本被分為 1203 個 Zone,然後每個 Zone 再細分成 30x30 個 Block,每個 Block 一樣再細分成 30x30 個 Unit,如果還要更細,還可以再細分成 Core 和 S Core,大約可以到 3 公尺的精細度,最後就是當然,這套系統的大分區也和郵遞區號完全不相通。


Archlinux 修復紀錄

Universal Studio Singapore

之前我在推特上有說過我不小心把我放 blog 的主機搞壞,當時就是用 pacman 更新過後,出現一些錯誤,我快速的重跑pacman -Syu然後就開始一直出現錯誤了,當時想說是因為我太久沒更新,然後有相依性錯誤造成系統幾乎爛掉,一度要放棄,不過因為網站相關的 instance 都還跑著,所以我就想說暫時放著,等有空把資料弄出來再重建系統,然後十一月中去了一趟新加坡,這趟行程要邊顧小孩其實很累,然後就在回來當天晚上就收到 Linode 的緊急維護,已經把我的 Linode 主機重開了,網站當然也死了,真的是晴天霹靂,不過實在太累了我也只能先放著不管。

過了幾天終於比較有力氣來看看看問題,我當時的狀況是,無法使用 pacman,然後更進一步發現是 curl 就死掉,curl 死掉會造成很多東西一起掛掉,像是 git、wget 也都掛了,結果我能使用的工具和手段就變的很少,總之先來看看錯誤訊息吧:

/usr/lib/libcurl.so.4: undefined symbol: BrotliDecoderCreateInstance

由此可知基本上問題就是動態連結 Brotli 的 library 時出錯,我還記得我當初裝機器時,Archlinux 還沒有正式 Brotli 的套件,所以我還自己編譯了一版給 nginx 用,而我的 nginx 也是自己編譯的,沒想到不知不覺 Archlinux 已經有正式的 Brotli 套件,而且 curl 還相依於它。

接著我就開始各種嘗試,想辦法重新裝 Brotli 套件,curl 雖然不能動,但是我還可以用 scp 傳檔案上去,不過就算傳上去 pacman 也還是完全無法跑起來,即使我只是想要他安裝本地的檔案,而不是要連網路,然後我也去看了/use/local/裡面 brotli 套件的 header 檔案,查看內容,發現真的沒有BrotliDecoderCreateInstance,不過這個 symbol 在 Brotli 的 repo 內是有的,而且已經存在了有四年之久,所以顯然,我系統內安裝的版本很有問題,雖然確定問題在哪,但是還是一直沒有解決方法,重裝套件需要 pacman,但是 pacman 需要修好 brotli 才能動,陷入死結當中,更糟的是,我在網路上搜尋就是找不到有一樣問題的人。

然後我就開始研究 pacman 掛掉要怎麼辦,找了許久終於找到有一個 pacman-static 的工具,是預先編譯好,並且是靜態連結的 pacman 執行檔,抓下來後發現真的可以用,真的是感動的痛哭流涕,然後我立馬執行pacman -Syu,一切執行順利,感動QQ,然後我執行了curl想確認有沒有修好,結果我再次看到了那個一樣的,熟悉的錯誤訊息...

這時我百思不得其解,我用 pacman 看安裝的套件版本確實是新的,我去解開套件來看也是新的,但是我去系統的/usr/local/下看裡面的檔案卻是舊的,重新裝了很多次也都是一樣狀況,就這樣鬼打牆很久之後,我突然察覺,/usr/local/下的東西,其實是我們手動編譯安裝的,也是路徑中優先權較高的,然後我在前面有提過,我很久以前有手動編譯安裝 Brotli 套件,終於,一切真相大白,我手動裝的時間點是五年前,所以該版本沒有BrotliDecoderCreateInstance,然後 Archlinux 用的是四年前版本,所以系統中其他需要 Brotli 的東西都會因此而掛掉,解決方法就是把手動裝的全部砍光光就好了。

不過砍掉我手動編譯的 Brotli,也同時造成我的 nginx 再起不能,因為在設定檔內它是需要我手動編譯安裝的那那個套件,解決方法是很簡單,就把需要的 module 路徑改到 pacman 安裝的套件那邊,然後我的 nginx 就可以起來了,不過我的 blog 還是死的,非 blog 的部分倒是活著,我一開始想說是 php-fpm 的問題,看錯誤訊息發現有 permission 問題,就去改 socket file permisson 成 666,然後網站還是起不來,我研究了很久,想要看看 PHP 的錯誤訊息,但是一直看不到東西,也去看 nginx error log,journalctl 也是看沒錯誤,還以為 php-fpm 是死的,還用了

<? echo phpinfo(); ?>

然後開瀏覽器看到原始碼直接回回來,搞了一陣子想起要改用<?php,改下去結果又發現一切正常,最後才發現,問題是因為我在用 pacman 更新整個系統時,把 PHP 7 升級到 8,然後我的程式碼裡面有個地方寫死大版號不對的話會回錯誤訊息,但是我沒有把錯誤訊息寫到 log 中,結果就造成我一直找不到問題點。

PHP 的問題解決後,我的 blog 就回到線上了,不過其實,這時候我的 mariadb 還是死的,透過 journalctl 看 log

sudo journalctl -xeu mariadb.service

有一行寫著:

Plugin 'InnoDB' registration as a STORAGE ENGINE failed.

一開始想說是安裝失敗,後來往上找發現還有另外一行:

InnoDB: Upgrade after a crash is not supported. The redo log was created with MariaDB 10.4.8

意思就是如果你的 DB crash 後,沒有正常關閉的狀態下,去更新 mariadb,就會有這個錯誤,不過一開始我不以為意,因為我認為我只有 upgrade,但是不知道是何時 crash 過,後來回想,應該是 brotli 爛掉時,mariadb 就跟著起不來了,總之,這個問題的解決方法,就是退回舊的 10.4.8 然後重新啟動 DB,所以就研究了一下 Archlinux 怎樣安裝舊版的套件,基本上 pacman 是不能指定版本的,有兩個方法可以裝舊版,一個是透過系統內的 pacman cache,不過我之前在修理的時候已經清掉了,所以就只能從 Arch Linux Package Archive 那邊下載特定版本的 package tar 檔案,下來用pacman -U安裝,然後因為有相依性問題,所以要把幾個需要的套件都抓下來,一起安裝:

pacman -U mariadb-10.4.8-2-x86_64.pkg.tar.xz \
  mariadb-clients-10.4.8-2-x86_64.pkg.tar.xz \
  mariadb-libs-10.4.8-2-x86_64.pkg.tar.xz

反正如果啟動失敗,也會有訊息提示你要看 log,結果把 mariadb 三個都裝下去後還真的有問題,說找不到 openssl 1.1 的檔案,所以也去抓下來手動安裝:

pacman -S openssl-1.1

至此,總算是修好了,接下來就是有時間要把我的 blog 系統容器化吧,有太多不是很好安裝的東西了。

PS. 這篇發的出去表示真的修好了。


更之前的文章