更新紀錄(僅初版,2026年08月20日 發布)
- 初次發布
引用本文(DOI(已登錄存檔): 10.5281/zenodo.22176471)
以下 DOI 指向先前登錄的存檔,內容可能與目前正文不同。引用目前正文時,請使用本頁網址。
Go Komura(2026)。〈日文字型與字元的陷阱 ── 業務應用裡的 JIS2004、異體字選擇器、外字〉。小村軟體有限公司。 https://comcomponent.com/zh-TW/blog/japanese-fonts-jis2004-ivs-gaiji-business-apps/
- DOI(已登錄存檔)
- 10.5281/zenodo.22176471
- DOI(上次登錄版本)
- 10.5281/zenodo.22176472
「明明是同一個姓名,畫面與報表上字的形狀卻不一樣。」「換了 PC 之後,以前顯示得出來的字變成 □。」── 在處理日文的業務系統裡,這類諮詢時常出現。
最先要確認的是:字元的資料變了,還是同一份資料只有外觀變了。 不把這一點分開,就當成「亂碼」去修,調查的入口就會走錯。
本文以兩個諮詢為入口:客戶名冊裡的「葛」在畫面與列印出來的報表上看起來不同;以及要送交公所的文件上的姓名,在換 PC 之後顯示不出來。
這裡談的兩個諮詢,與編碼不一致造成的亂碼是不同的問題。第一個是資料一個位元都沒變、只有外觀變了;第二個是只存在於那台 PC 的「外字」不見了。
flowchart TB
accTitle: 兩種常見諮詢的真正原因
accDescr: 畫面與報表上葛的形狀不同的諮詢,是資料沒變、只有外觀變了;換 PC 後字變成 □ 的諮詢,是只存在於那台 PC 的外字不見了;兩者都與編碼不一致造成的亂碼是不同的問題
c1["諮詢 1:畫面與報表的形狀不同"] --> r1["資料沒變,只有外觀改變"]
c2["諮詢 2:換 PC 後變成 □"] --> r2["只屬於那台 PC 的外字不見了"]
r1 --> diff["與編碼造成的亂碼是不同問題"]
r2 --> diff
圖 1: 常被叫成「亂碼」的兩個諮詢,都與編碼不一致是不同的問題。
只要把字元編碼(資料層)與字型(外觀層)分開思考,日文的字元問題大半都能整理清楚。 本文寫給業務系統的開發者與資訊部門人員,依序說明症狀的釐清、JIS2004 與 IVS 與外字的機制、受理字元的範圍,以及報表與 PDF 的設計。
Shift_JIS 與 UTF-8 轉換時發生的「亂碼」本身已由既有文章處理,因此本文集中在「碼正確地來回轉換,但外觀或能否顯示卻偏掉」的問題。
1. 先講結論
「要儲存哪一段位元組序列」是資料設計的問題,「它看起來怎樣」是字型設計的問題。 決定對策時,把下面三件事分開思考。
先確認資料是否相同
「亂碼」是資料層把位元組序列解讀錯誤的問題。另一方面,即使 Unicode 碼位相同,字型不同,字形也會不同。JIS2004 變更了葛、辻、飴等 168 個字的例示字形,Windows 的 MS Gothic/MS Mincho 也從 Vista 起以 JIS2004 字形為預設。12
不要把字形的指定與外字的攜帶混為一談
把字形當成資料來指定的標準手段是 IVS。不過它需要支援的字型與支援的應用程式,在不支援的環境,忽略選擇器、顯示基底字元的預設字形才是正確行為。看起來的一個字在 UTF-16 最多佔四個碼元,因此影響的不只是顯示,還有字數計算與切片。34
外字(EUDC)則是另一回事:私人使用區的號碼沒有全世界共通的意義。eudc.tte 裡的字形不會隨著資料一起交到對方手上,因此遷移時需要調查並建立到替代字元的對應。56
把受理的字元與輸出的環境寫成規格
處理姓名的系統要決定並寫明受理的字集。與政府機關互通時,也要留意以戶籍統一文字與文字資訊基盤為基礎的行政事務標準文字的動向。789 報表與 PDF 的基本做法是與畫面使用同一字型,並在確認授權後嵌入。有長期保存需求時考慮 PDF/A。1011
另外,不要輕易對姓名的原始資料套用 NFKC 正規化。 全形半形與相容字元的替換,會讓應該保留的區別消失。12
依症狀與目的選擇要讀的段落
| 你的困擾或要做的決定 | 最先要確認的事 | 要讀的段落 |
|---|---|---|
| 分不清是亂碼還是字形差異 | 碼位是否相同。「�」與「□」的差別是什麼 | 第 2 章:資料與外觀 |
| 遷移前後、或畫面與報表上葛、辻等字的形狀不同 | JIS90 與 JIS2004 的字形差異、使用的字型 | 第 3 章:JIS2004、第 7 章:報表與 PDF |
| 想連姓名的字形都用資料區分 | 顯示、列印、下游系統是否都支援 IVS | 第 4 章:IVS、第 4.2 節:對實作的影響 |
| 有些字只有舊 PC 才顯示得出來 | 私人使用區用在哪些地方,以及原本的外字字型 | 第 5 章:外字、第 5.1 節:遷移程序 |
| 想決定姓名要受理到多廣 | 下游系統的規定,以及範圍外字元的處理 | 第 6 章:字集的設計 |
| 只有一部分字體變了,或是變成 □ | 指定字型與後備對象裡有沒有那個字形 | 第 8 章:後備 |
| 想確認實作或遷移有沒有遺漏 | 輸入、正規化、儲存、顯示、列印、互通各層 | 第 9 章:檢查清單 |
想理解全貌就從第 2 章依序讀;想查眼前的症狀,就從表中對應的段落讀起。實作對策時,最後請用第 9 章確認對其他層的影響。
圖中實線表示始終成立的關係,虛線表示附帶條件的關係(成立條件寫在詳細頁面中各關係的說明中)。關係的完整清單(共 14 條,附依據與可信度)以及主要概念的定義,彙整在知識地圖詳細頁面(日文)。資料:JSON-LD / Turtle
2. 把資料與外觀分開思考 ── 碼位與字形
號碼與畫出來的形狀是兩回事
在 Unicode,字元以稱為碼位(code point)的號碼表示。葛是 U+845B,這個號碼在任何一台 PC 上都相同。
另一方面,那個號碼要在畫面或紙上怎麼畫,由字型持有的字形(glyph)決定。同樣是 U+845B,在字型 A 與字型 B 上細部形狀不同,是正常行為。
依症狀決定要查哪一層
以這兩層為前提,現場的症狀可以這樣區分。
| 層 | 會發生的問題 | 典型症狀 | 主要對策 |
|---|---|---|---|
| 資料層(字元編碼) | 編碼解讀錯誤、轉換時遺失 | 縺ッ 這類亂碼、被換成 ? 或 〓、U+FFFD(�) |
找出並修正轉換路徑 |
| 外觀層(字型) | 字型造成的字形差異、缺少字形 | 同一份資料形狀卻不同、變成 □(豆腐) | 統一或更換字型、嵌入 |
作為區分的線索,記住 「�」與「□」的差別 很有用。
「�」是轉換失敗留下的痕跡。 一旦被換成 U+FFFD(REPLACEMENT CHARACTER),原本的字元就已經沒了。這時要查資料層。
「□」多半是找不到字形時的顯示。 如果資料還在、只是字型沒有那個字形,換字型就有機會顯示出來。這時要查外觀層。
flowchart TB
accTitle: 用 � 與 □ 區分症狀
accDescr: 字顯示不正確時,� 是資料層轉換失敗、原本字元已經遺失的痕跡;□ 只是資料還在但字型沒有那個字形,換字型就有機會顯示出來
symptom["字顯示不正確"] --> which{"看到的是什麼?"}
which -->|看到 �| datalayer["資料層的問題"]
datalayer -.-> lost["轉換失敗的痕跡(原本的字元已經遺失)"]
which -->|看到 □| viewlayer["外觀層的問題"]
viewlayer -.-> noglyph["只是字型沒有那個字形"]
noglyph --> fixable["換字型就有機會顯示"]
圖 2: � 是資料層問題的訊號,□ 是外觀層問題的訊號,調查的入口因此不同。
編碼本身的基礎(CP932 與 UTF-8、BOM、換行碼)寫在〈釐清 Windows 的文字編碼 - 亂碼為什麼會發生,尤其是與 Linux 搭配時什麼地方會偏掉〉與〈整理 Windows 的字元編碼與換行符 - Shift_JIS / UTF-8 / UTF-16、亂碼、CRLF / LF,為何混亂〉。接下來談的是外觀層,以及發生在它邊界上的問題。
3. 從 JIS90 到 JIS2004 ── 碼沒變,字形變了
開頭「畫面與報表上『葛』的形狀不同」的真正原因,多半就在這裡。
變了的東西:字型的預設字形
依 2000 年國語審議會提出的「表外漢字字體表」,2004 年修訂的 JIS X 0213:2004(通稱 JIS2004)把 168 個漢字的例示字形改成接近所謂康熙字典體的印刷標準字體。葛、辻、飴、芦、溢、餅等是代表例子。1
Windows 配合這項變更,從 Windows Vista 起讓 MS Gothic/MS Mincho(以及新增的 Meiryo)以 JIS2004 字形為預設。現在的 MS Gothic 預設字形也以 JIS2004 為基礎,並可透過 OpenType 的 jp90 功能存取 JIS90 時代的字形。21
flowchart TB
accTitle: 現在 MS Gothic 的字形架構
accDescr: 從 Vista 起的 MS Gothic 以 JIS2004 字形為預設,透過 OpenType 的 jp90 功能則可存取 JIS90 時代的字形
msg["MS Gothic(Vista 以後)"] --> def["預設字形:以 JIS2004 為基礎"]
msg --> feat["透過 jp90 功能"]
feat --> old["JIS90 時代的字形"]
圖 3: 現在的 MS Gothic 以 JIS2004 字形為預設,可用 jp90 功能切換成 JIS90 字形。
沒變的東西:字元的碼位
這裡的重點是:變的只有字型,資料一點也沒變。
- 葛的碼位在 XP 與 Windows 11 上都一樣是 U+845B
- 在 XP(JIS90 字形)顯示成勹裡面簡化為「ヒ」的形狀,從 Vista 起(JIS2004 字形)顯示成裡面連「人」都寫出來的形狀
- 因此舊系統列印的報表掃描影像,與新 PC 的畫面顯示,字的形狀會不一致。但資料比對完全相符
辻的辵部是一點還是兩點、飴的食部形狀等等也一樣。不知道這段歷史,調查就容易往「遷移把資料弄壞了」這個錯誤方向走。
調查的順序是:先比對遷移前後的碼位 → 若相符,就懷疑是字型的字形差異。請不要只憑外觀不同就判斷資料壞了。
flowchart TB
accTitle: 碼位相同,字形仍會因字型而異
accDescr: 葛的碼位 U+845B 在 XP 與 Windows 11 上都一樣,只有 JIS90 字形字型與 JIS2004 字形字型顯示出來的形狀不同,資料比對則完全相符
cp["碼位 U+845B(葛)"] --> f90["JIS90 字形的字型(XP)"]
cp --> f04["JIS2004 字形的字型(Vista 以後)"]
f90 --> g90["勹裡面簡化為 ヒ 的形狀"]
f04 --> g04["裡面連人都寫出來的印刷標準字體"]
g90 -.-> same["資料比對完全相符"]
g04 -.-> same
圖 4: 變的只有字型,碼位 U+845B 在任何環境都一樣。
另外,因為字體本身並沒有改變,兩種字形都是「同一個字」。不過在姓名上,當事人或公所有時會堅持特定的形狀;要把那個區別「當成資料」來回應的,就是接下來的 IVS。
4. 異體字選擇器(IVS)── 用資料指定字形
本章分成三件事來看:指定字形的機制、能顯示出來的條件,以及對實作的影響。
IVS(Ideographic Variation Sequence)是在漢字正後方放一個稱為「異體字選擇器」的不可見碼位,把字形的變體當成資料來指定的機制。選擇器使用 U+E0100–U+E01EF(VS17–VS256)。3
字形的對應由 IVD 的登錄決定
哪一組「基底字元+選擇器」的序列指向哪個字形,由 Unicode Consortium 管理、稱為 IVD(Ideographic Variation Database) 的登錄簿決定。
主要的收藏如下。13
| 收藏 | 登錄 | 由來與用途 |
|---|---|---|
| Adobe-Japan1 | 2007 年 | Adobe 的日文字元收藏。商用字型切換異體字形的基礎 |
| Hanyo-Denshi(汎用電子) | 2010 年 | 汎用電子資訊交換環境整備計畫。對應戶籍、住基等行政文字 |
| Moji_Joho | 2014 年 | 對應文字資訊基盤(MJ)。用於 IPAmj 明朝。2026 年 8 月也有追加登錄 |
例如 Microsoft 的文件舉出的例子是:單獨的 U+845B(葛)用於西葛西站的寫法,U+845B+U+E0100(VS17)用於奈良縣葛城市的寫法。同樣是葛,也能用資料區分是哪一種字形。3
flowchart TB
accTitle: 用 IVS 把同一個葛當成資料區分的例子
accDescr: 單獨的 U+845B 葛用於西葛西站的寫法,U+845B 後面加上 VS17 的序列用於葛城市的寫法,哪一組序列指向哪個字形由 IVD 這個登錄簿決定
seq1["單獨的 U+845B"] --> gl1["西葛西站寫法的字形"]
seq2["U+845B + VS17"] --> gl2["葛城市寫法的字形"]
ivd["IVD(登錄簿)"] -.-> gl1
ivd -.-> gl2
圖 5: 同樣是葛,也能依有無選擇器把字形當成資料區分。
4.1. 在不支援的環境裡的行為
字型這一側,是在 OpenType 的 cmap 表(format 14)實作 IVS 與字形的對應。4 支援的字型(如 IPAmj 明朝)與支援的應用程式都到齊,就會出現指定的字形。
沒到齊時,指定的字形不一定保得住。 分成下面兩種情況來看。
- 規格上正確的行為:選擇器被忽略,以基底字元的預設字形顯示(選擇器本身看不見)
- 較舊的應用程式或部分繪製堆疊:選擇器被當成獨立的未知字元,多顯示一個 □
也就是說,IVS 的設計是「即使降級,基底字元仍讀得出來」,但「一定會以指定的字形顯示」這個保證取決於接收端的環境。
政府的住民紀錄與戶籍系統會使用「文字資訊基盤系字型+IVS」的組合;但一般業務系統若輕易接受,字形會在顯示、列印或下游系統的某一處掉下來。
flowchart TB
accTitle: 帶 IVS 的資料會怎麼顯示
accDescr: 支援的字型與應用程式都到齊時會以指定的字形顯示,沒到齊時選擇器被忽略而以基底字元的預設字形顯示,較舊的應用程式或部分繪製堆疊則把選擇器當成未知字元而多顯示一個 □
ivs["基底字元+異體字選擇器"] --> env{"支援的字型與應用程式都到齊?"}
env -->|是| ok["以指定的字形顯示"]
env -->|否| ignore["選擇器被忽略,以預設字形顯示"]
env -->|較舊的應用程式或部分繪製堆疊| tofu["多顯示一個 □"]
ignore -.-> spec["規格上這才是正確行為"]
圖 6: IVS 即使降級,基底字元仍讀得出來,但會不會以指定字形顯示取決於接收端的環境。
4.2. 實作上的注意 ──「一個字」最多四個碼元
IVS 的選擇器 U+E0100 以後屬於補充平面的碼位,因此在 UTF-16 一律是代理對(兩個碼元)。若基底字元是補充平面的漢字(例如 JIS2004 新增的 𠮟(U+20B9F)),光基底就佔兩個碼元,使用者認知為「一個字」的序列在 UTF-16 最多四個碼元,在 UTF-8 最多八個位元組。
字數與切片:不要把看起來的一個字切開
C# 的 "葛󠄀"(葛+VS17)其 string.Length == 3。用 Substring 或固定長度切片,有把基底字元與選擇器拆散的風險。
字數的驗證與切片要以字素為單位(StringInfo 之類的 API),而不是碼元。
儲存:確認欄長的單位
SQL Server 的 nvarchar(n) 以 UTF-16 碼元計。若要接受 IVS,資料庫的欄長要預估為看起來字數的二到四倍。
搜尋與比對:決定要不要區分選擇器
有沒有選擇器,就是不同的字串。用「葛」搜尋會不會命中「葛+VS17」,必須當成需求決定後再實作。
flowchart TB
accTitle: 帶 IVS 的一個字與 UTF-16 碼元
accDescr: 使用者認知為一個字的基底字元與異體字選擇器序列,選擇器一律是代理對,基底字元若是補充平面的漢字還要再加兩個碼元,在 UTF-16 最多四個碼元
one["使用者認知的一個字"] --> base["基底字元"]
one --> vs["異體字選擇器"]
base -.-> bnote["補充平面的漢字則為兩個碼元"]
vs -.-> vnote["一律是代理對(兩個碼元)"]
base --> total["UTF-16 最多四個碼元"]
vs --> total
total -.-> risk["固定長度切片有拆散的風險"]
圖 7: 帶 IVS 的一個字在 UTF-16 最多四個碼元,依碼元切片很危險。
5. 外字(EUDC)── 只在那台 PC 顯示得出來的字
外字是使用者自行把字形指派到 Unicode 私人使用區(PUA:U+E000–U+F8FF 等)碼位的機制。私人使用區的碼位沒有全世界共通的意義,同樣是 U+E000,也可能依 PC、依組織被指派到不同的字。5
字形留在外字字型裡,資料裡留下的是號碼
在 Windows 用私人字元編輯器(eudcedit.exe)製作字形,存進名為 eudc.tte 的字型檔。
這個檔案以隱藏字型的形式安裝,並在 HKEY_CURRENT_USER\EUDC 登錄檔中與各字型建立關聯。6 Shift_JIS(CP932)時代 0xF040–0xF9FC 是外字區,轉成 Unicode 時對應到私人使用區。
資料裡有號碼,不代表對方也有同樣的字形。 這個機制會引發下列問題。
- eudc.tte 屬於那台 PC(那位使用者),不會隨著資料交到對方手上
- 一旦交到郵件、PDF、Web 或其他系統,就會變成 □,或看起來像對方端的另一個外字
- OS 遷移或換 PC 時忘了搬移 eudc.tte,就會發生「以前那台 PC 顯示得出來的字現在顯示不出來」
開頭第二個諮詢的真正原因就是這個。
flowchart TB
accTitle: 外字為什麼只在那台 PC 顯示得出來
accDescr: 用私人字元編輯器製作的字形存進 eudc.tte 並在那台 PC 的登錄檔中與字型建立關聯,因此只有私人使用區的碼交到郵件或 PDF 或其他系統時,就會變成 □ 或看起來像別的字
edit["用私人字元編輯器製作字形"] --> tte["存進 eudc.tte"]
tte --> reg["在登錄檔中與字型建立關聯"]
reg --> local["在那台 PC 上顯示得出來"]
tte -.-> stay["eudc.tte 不會跟著資料一起走"]
send["只有私人使用區的碼交到對方"] --> dest["郵件、PDF、其他系統"]
dest --> broken["變成 □ 或看起來像別的字"]
圖 8: 字形在 eudc.tte 裡,資料裡只剩私人使用區的號碼,因此外字一離開那台 PC 就看起來壞掉。
5.1. 已經收下外字的系統的務實作法
問題在於從舊系統接手的資料裡已經混入外字。本公司在遷移專案中建議的是調查 → 識別 → 置換 → 阻斷四個階段。
1. 調查:收集使用中的號碼與原本的字形
用私人使用區(U+E000–U+F8FF)的正規表示式掃描資料庫與檔案,盤點使用中的外字碼與件數。從各據點的 PC 回收 eudc.tte 並確認字形。
2. 識別:製作替代字元對應表
逐一檢視每個外字,調查「能不能用正規的 Unicode 字元表示」「能不能用 IVS 表示」「文字資訊基盤(MJ)有沒有對應的字」,做出替代字元對應表。實務上,大多數情況只是把舊字體做成了 JIS 外字而已。
3. 置換:依對應表替換資料
依對應表替換資料。只有實在找不到對應字元時,才以影像保留,或在該筆記錄上加註記。
4. 阻斷:不再增加新的外字
新系統以驗證擋掉私人使用區的輸入,不再新做外字。
flowchart TB
accTitle: 含外字資料的遷移程序
accDescr: 用私人使用區的掃描與 eudc.tte 的回收盤點使用中的外字,做出替代字元對應表後替換,新系統則以驗證擋掉私人使用區的輸入、不再新做外字
st1["調查:掃描私人使用區"] --> st2["識別:製作替代字元對應表"]
st2 --> st3["置換:依對應表替換"]
st3 --> st4["阻斷:不再新做外字"]
st1 -.-> tte["從各據點回收 eudc.tte"]
st2 -.-> nomap["沒有對應時才用影像或註記"]
圖 9: 外字的遷移依調查、識別、置換、阻斷四階段推進,不再新做外字。
政府這邊的方向也一樣:已提出方針,要把各自治體自行製作的外字(據說全國約有兩百萬字)唯一識別到後述的行政事務標準文字,並停止使用。9「不增加外字,改為識別到標準化的字集」,正在成為公私部門共通的遷移標準做法。
6. 政府的文字基盤 ── 從戶籍統一文字到行政事務標準文字
設計處理姓名的系統時,先了解政府這邊的文字基盤,就能作為「要受理到多廣」的判斷依據。
先分清各文字基盤的名稱與角色
| 名稱 | 主管 | 概要 |
|---|---|---|
| 戶籍統一文字 | 法務省 | 為戶籍電子化而整理的約 5 萬 6 千字。可在法務省網站上搜尋7 |
| 住基網統一文字 | 地方公共團體資訊系統機構 | 住民基本台帳網路使用的約 2 萬 1 千字 |
| 文字資訊基盤(MJ) | 文字資訊技術促進協議會 | 整備行政事務使用的約 6 萬字。以 MJ 文字圖形名管理,並公開 IPAmj 明朝字型與 MJ 文字資訊一覽表。原為 IPA 的事業,現已移交該協議會8 |
| 行政事務標準文字(MJ+) | 數位廳 | 在文字資訊基盤之上,加入無法識別到 MJ 的戶籍文字等擴充而成的字集。符合標準系統的姓名等使用這個字集,字元編碼則使用 JIS X 0221:20209 |
區分政府內部的互通與一般外部環境的互通
在自治體的核心業務系統(符合標準的系統),標準規格採兩段式:姓名等資訊的互通使用行政事務標準文字,與智慧型手機這類沒有統一互通規定的外部系統,則在 JIS X 0213:2012 的範圍內互通。9
「內部保有較寬的字集,對外則在一般環境顯示得出來的範圍內交換」,這個結構本身對民間系統也很有參考價值。
flowchart TB
accTitle: 符合標準系統的兩段式互通
accDescr: 自治體的符合標準系統對姓名等資訊的互通使用行政事務標準文字,與沒有統一互通規定的智慧型手機等外部系統則在 JIS X 0213:2012 的範圍內互通
sys["自治體的符合標準系統"] --> renkei["姓名等資訊的互通"]
sys --> gaibu["與外部系統的互通"]
renkei --> mjp["行政事務標準文字"]
gaibu --> jis["JIS X 0213:2012 的範圍"]
gaibu -.-> sumaho["智慧型手機等沒有規定的對象"]
mjp -.-> naibu["內部保有較寬的字集"]
圖 10: 政府內互通用行政事務標準文字,沒有規定的外部互通用 JIS X 0213:2012 的兩段式架構。
決定自己的系統要受理的範圍
對一般業務系統的實務指引,我們建議如下。
- 決定受理的字集,並在規格書與輸入驗證兩邊都寫明。例如「JIS X 0213:2012 的範圍」「不接受私人使用區與結合字元」「不接受 IVS(或接受,但只在 IPAmj 明朝環境保證顯示)」等
- 不要無上限地接受。「反正是 Unicode,什麼都放得進去」的設計,一定會在顯示、列印或互通的某一處破功
- 事先決定範圍外字元的處理方式。替換成替代寫法(新字體、片假名)的規則,以及向當事人說明的文案,都屬於系統規格
- 當政府、金融等下游系統訂有字集規定時,以那份規定為準來對齊
flowchart TB
accTitle: 受理字集的設計與維運
accDescr: 決定受理的字集並在規格書與輸入驗證兩邊都寫明,範圍內的字元予以接受,範圍外的字元則連替換成替代寫法的規則與向當事人說明的文案都先決定好
decide["決定受理的字集"] --> spec["在規格書中寫明"]
decide --> valid["在輸入驗證中寫明"]
valid --> range{"在範圍內?"}
range -->|是| ok["接受"]
range -->|否| alt["替換成替代寫法"]
alt -.-> word["向當事人說明的文案也是規格"]
圖 11: 受理字集要在規格書與輸入驗證兩邊都寫明,連範圍外的處理方式也先決定好。
7. 字型的選定與嵌入 ── 讓畫面與報表一致
這裡依序思考:確認要用的環境有沒有那個字型 → 讓畫面與報表一致 → 確認授權後嵌入 PDF。
7.1. 常見字型的性格
| 字型 | 收錄 | 性格與適用場合 |
|---|---|---|
| MS Gothic/MS Mincho | Windows 標準 | 為低解析度畫面設計的老將。預設字形以 JIS2004 為基礎2。為維持與舊報表的相容性,至今仍在服役 |
| Meiryo | Vista 以後 | 以 ClearType 為前提的現代畫面字體。與 Vista 世代的 JIS2004 遷移同時登場1 |
| Yu Gothic/Yu Mincho | Windows 8.1 以後 | Windows 與 macOS 雙方都有收錄的系列,容易讓文件外觀一致 |
| BIZ UD Gothic/BIZ UD Mincho | Windows 10 1809 以後 | 森澤製的通用設計字體。重視報表與畫面可讀性的案子首選14 |
| Noto Sans JP | 另行導入 | 以開放原始碼提供,容易隨伺服器或 Linux 環境一起附帶,也容易在 Web 上交付 |
不只看字型名稱,也要確認使用的環境
選定時重要的不是字體偏好,而是「顯示、列印、PDF 產生所涉及的每一個環境,是否都有那個字型」。
Windows 10/11 的日文補充字型(BIZ UD 等)依組態不同可能沒有安裝;在伺服器端產生 PDF 的架構裡,伺服器上有沒有字型會直接造成影響。
flowchart TB
accTitle: 選字型時該確認的環境
accDescr: 選字型時比起字體偏好,更重要的是顯示與列印與 PDF 產生所涉及的每一個環境是否都有那個字型,補充字型的組態與伺服器上有沒有字型都會直接造成影響
cand["候選字型"] --> exist["每一個環境都有嗎"]
exist --> scr["顯示的環境"]
exist --> prn["列印的環境"]
exist --> srv["產生 PDF 的伺服器"]
scr -.-> hojo["補充字型依組態可能沒有"]
srv -.-> eikyo["伺服器上有沒有字型會直接造成影響"]
圖 12: 選字型與其看字體偏好,不如看它在顯示、列印、PDF 產生的每一個環境是否都有。
7.2. 報表設計的基本 ── 對齊,然後嵌入
讓畫面與報表使用同一字型
在畫面與報表指定同一字型。 字型不同,同一份資料的字形看起來就會不同,於是就有了開頭那種抱怨。「畫面用 Meiryo、報表用 MS Mincho」這類組合,至少應先確認 JIS2004 的那 168 個字有沒有字形差異。
PDF 要在確認授權後嵌入
要把字型嵌進 PDF。 不嵌入的話,檢視端會用手邊的字型替代繪製,不只字形,連版面都可能改變。
能不能嵌入由授權決定。 OpenType 字型以 fsType 欄位宣告嵌入權限(Installable / Restricted / Preview & Print / Editable、禁止子集等),不得嵌入未獲授權嵌入的字型。10 商用字型必須確認契約。
以子集嵌入為基本。 只嵌入用到的字元的字形,就不必扛著整套日文字型(數 MB 到數十 MB)。
長期保存要考慮 PDF/A
有長期保存需求就用 PDF/A。 PDF/A(ISO 19005)是把顯示所需資源全部收進檔案內的規格,必須嵌入字型。11 這也是防止「十年後打開時字形變了」最可靠的方法。
flowchart TB
accTitle: 字型嵌入的判斷流程
accDescr: 把字型嵌進 PDF 之前先確認 fsType 的嵌入授權,獲授權時以子集嵌入為基本,有長期保存需求時則考慮必須嵌入字型的 PDF/A
emb["把字型嵌進 PDF"] --> lic{"fsType 是否授權嵌入?"}
lic -->|已授權| sub["以子集嵌入為基本"]
lic -->|未授權| ng["不得嵌入"]
sub -.-> gly["只嵌入用到的字元的字形"]
sub -->|有長期保存需求| pdfa["考慮 PDF/A"]
pdfa -.-> must["必須嵌入字型"]
圖 13: 嵌入以確認 fsType 授權為前提,子集嵌入與 PDF/A 是基本線。
列印與 PDF 輸出的實作手段怎麼選,〈Windows 業務應用程式的列印與 PDF 輸出〉有詳細說明。
8. 字型連結與後備 ──「混進不同字型」的現象
指定的字型沒有字形的字元,不會什麼都不顯示,而是用另一個字型替代繪製——這是現代繪製堆疊的預設行為。
在 GDI 由登錄檔(FontLink\SystemLink)定義的「字型連結」負責,在 DirectWrite、WPF 與瀏覽器則由「字型後備」負責。15
flowchart TB
accTitle: 字型連結與後備的流程
accDescr: 指定的字型有字形就直接顯示,沒有就用字型連結或後備對象的字型替代繪製,哪裡都沒有字形時會變成 □ 但資料多半還活著
disp["顯示一個字元"] --> has{"指定的字型有字形嗎?"}
has -->|有| draw["以指定的字型顯示"]
has -->|沒有| fb{"連結或後備對象裡有嗎?"}
fb -->|有| alt["用另一個字型替代繪製"]
alt -.-> mixed["字體感覺混在一起的原因"]
fb -->|沒有| tofu["顯示 □(豆腐)"]
tofu -.-> alive["資料多半還活著"]
圖 14: □ 是後備失敗的痕跡,替代繪製成不成功,就是「混在一起」與「豆腐」的分歧點。
從症狀讀出替代繪製的結果
知道這個機制,就能解釋下面這些常見現象。
- 英數字與日文的字體感覺不同:因為先指定了西文字型,只有日文部分由連結或後備的日文字型繪製
- 日文句子裡只有漢字變成中文風格的字形:後備對象被解析成中文字型。常見於沒有正確傳遞語言資訊(lang 屬性或地區設定)的網頁或應用程式
- 出現豆腐(□):指定字型與後備對象都沒有那個字形。也就是說 □ 是後備「失敗的痕跡」,資料多半還活著
後備不能取代設計
後備是救濟機制,不能取代一開始就選對字型。15
在業務應用程式,健康的定位是「主要的顯示與列印路徑只靠設計好的字型就能完成,後備只是非預期字元的保險」。多語言 UI 的字型選擇思路,也請參考〈WinForms/WPF 應用程式的多語言化〉。
9. 業務應用程式的實作檢查清單
最後把從輸入到互通各層該確認的重點整理成表。不要只確認畫面顯示得出來就結束,儲存、列印、互通也要一併確認。
| 層 | 典型的問題 | 設計與實作要點 |
|---|---|---|
| 輸入 | 環境依存字元、帶 IVS 的字元、私人使用區的字元從 IME 進來 | 決定受理的字集並驗證。範圍外不要直接報錯,改成引導(提示替代寫法),櫃檯業務才走得下去 |
| 正規化 | NFKC 把「㈱」變成「(株)」、統一全形半形、① 變成 1 這類非預期的轉換。就算是 NFC,CJK 相容漢字(例如 U+FA19 的「神」)也會被換成統合漢字 U+795E | 不要對姓名與地址套用 NFKC。正規化要限定用途(產生搜尋鍵等),原始資料照輸入的樣子保存12 |
| 儲存 | 代理對與 IVS 造成欄長不足、依碼元截斷 | 以 UTF-8/UTF-16 保存,欄長以碼元計並留餘裕。切片以字素為單位進行 |
| 顯示 | 字型沒有字形而變成 □、因後備而字形改變 | 明確指定能顯示目標字集的字型,並確認目標 OS 的標準收錄狀況 |
| 列印與 PDF | 畫面與報表的字形差異、檢視端的替代繪製 | 讓畫面與報表使用同一字型,PDF 則在確認授權後做子集嵌入10 |
| 與其他系統互通 | JIS X 0213 的新增漢字、IVS、外字在 Shift_JIS(CP932)轉換時變成 ? 或 〓 |
在互通規格中寫明字元編碼與字集。若還留著 CP932 互通,就實作無法轉換字元的偵測與替代規則 |
區分原始資料的保存與供搜尋用的加工
正規化尤其是本文主題本身的陷阱:出於「為你好」而套上的處理,反而壓掉了異體字與全形半形的區別。原則是原始資料保持原樣,加工只做在複本上。
CSV 互通的字元編碼問題,〈CSV 不是「純文字」而已〉有詳細說明。
flowchart TB
accTitle: 原始資料保持原樣,加工只做在複本上
accDescr: 輸入進來的字串以原始資料的形式照輸入的樣子保存,只在產生搜尋鍵等限定用途上對複本套用正規化,對原始資料套用 NFKC 會讓異體字與全形半形的區別消失
input["輸入進來的字串"] --> orig["原始資料:照輸入的樣子保存"]
input --> copy["複本:限定用途做正規化"]
copy -.-> use["產生搜尋鍵等"]
orig -.-> ng["對原始資料套用 NFKC 會壓掉區別"]
圖 15: 正規化要限定用途並套在複本上,原始資料則照輸入的樣子保存。
10. 總結
調查:區分資料與外觀
- 字元的問題先區分成「資料層(字元編碼)」與「外觀層(字型)」。� 是資料層問題的訊號,□ 是外觀層問題的訊號。
- JIS X 0213:2004 改了 168 個字的例示字形,Windows 從 Vista 起以 JIS2004 字形為預設。葛、辻、飴的形狀因環境而異,是字型的歷史,不是資料損壞。
設計:決定字形的指定與受理範圍
- 用資料固定字形的標準手段是 IVS,但支援的字型與應用程式沒到齊,就會落回預設字形。也別忘了一個字最多佔四個 UTF-16 碼元對實作的影響。
- 外字(EUDC)是那台 PC 特有的資產,沒辦法跟著資料一起旅行。務實作法是遷移時盤點、用對應表替換成正規字元或 IVS,並停止新做外字。
- 處理姓名的系統要決定並寫明受理的字集。政府正以戶籍統一文字與文字資訊基盤為基礎,往行政事務標準文字標準化推進,與之互通的系統必須跟上這個動向。
實作與輸出:守住原始資料,統一顯示路徑
- 報表與 PDF 的基本是「與畫面使用同一字型,確認授權後嵌入」。長期保存請考慮 PDF/A。
- NFKC 正規化、依碼元切片、CP932 轉換,是默默弄壞異體字與外字的三大關卡。請以保存原始資料與字素單位處理為原則。
下次有人說「字不一樣」,請先這樣反問:碼位是相同,還是不同?相同就是字型的問題,不同就是資料的問題。光是這一步,就不會走錯調查的入口。
flowchart TB
accTitle: 決定調查入口的第一個問題
accDescr: 有人說字不一樣時先比對碼位是相同還是不同,相同就當成字型的問題,不同就當成資料的問題開始調查
said["有人說字不一樣"] --> cmp{"碼位相同嗎?"}
cmp -->|相同| fontp["字型的問題"]
cmp -->|不同| datap["資料的問題"]
圖 16: 碼位相同就當成字型的問題,不同就當成資料的問題開始調查。
相關文章
- 釐清 Windows 的文字編碼 - 亂碼為什麼會發生,尤其是與 Linux 搭配時什麼地方會偏掉
- 整理 Windows 的字元編碼與換行符 - Shift_JIS / UTF-8 / UTF-16、亂碼、CRLF / LF,為何混亂
- Windows 業務應用程式的列印與 PDF 輸出 ── System.Drawing.Printing / WPF / 報表函式庫的取捨
- WinForms/WPF 應用程式的多語言化 ── resx、附屬組件與文化特性切換的實務
- CSV 不是「純文字」而已 ── C# 業務應用程式的 CSV 實務(字元編碼、Excel 相容性、注入攻擊防範)
- Windows 應用程式無障礙入門 ── 為 UI Automation 與合理調整的義務化做準備
相關諮詢領域
小村軟體有限公司承接業務系統中與字元相關的設計與調查。從釐清「畫面與報表的字不同」「遷移後姓名變成 □」這類症狀的原因,到從舊系統遷移時的外字調查與替代字元表製作、處理姓名的系統的受理字集設計,以及報表與 PDF 字型嵌入架構的審查,我們從碼層與字型層兩邊一起處理。
參考連結
-
Morisawa Inc., JIS X 0213:2004(JIS2004)|字型用語集. 關於 JIS X 0213:2004 依表外漢字字體表把 168 個漢字的例示字形改成印刷標準字體(所謂康熙字典體),以及 Windows Vista 標準內含支援 JIS2004 的字型。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, MS Gothic font family. 關於 MS Gothic 家族的預設字形以 JIS2004 為基礎,以及可透過 OpenType 的 ‘jp90’ 功能存取 JIS90 的舊字形。 ↩ ↩2 ↩3
-
Microsoft Learn, The Unicode standard. 關於變異序列由基底字元加上異體字選擇器(VS1–VS256,U+FE00–U+FE0F 與 U+E0100–U+E01EF)組成,關於 U+845B 葛與 U+845B+U+E0100(VS17)的分用例子(西葛西站與葛城市),以及顯示需要支援的字型。 ↩ ↩2 ↩3
-
Microsoft Learn, cmap — Character to Glyph Index Mapping Table (OpenType spec). 關於 OpenType 字型以 cmap 子表 format 14 實作 Unicode Variation Sequence,關於 default 與 non-default UVS 的區分,以及在支援 JIS2004 的字型上的使用例子。 ↩ ↩2
-
Microsoft Learn, End-User-Defined and Private Use Area Characters. 關於外字(EUDC)與私人使用區(PUA)字元由使用者或團體各自定義,以及同一碼位在不同電腦上指派可能不同而互相衝突。 ↩ ↩2
-
Microsoft Learn, Character Sets and Fonts. 關於 Unicode 的 EUDC 用途使用 PUA(U+E000–U+F8FF 等),關於用私人字元編輯器製作字形,以及 EUDC 字型以 .tte 檔隱藏安裝並在 HKEY_CURRENT_USER\EUDC 登錄檔中與字型建立關聯。 ↩ ↩2
-
Ministry of Justice, 戶籍統一文字資訊 檢索條件輸入. 法務省提供的戶籍統一文字官方檢索網站。關於可檢索戶籍所用文字的字形、讀音與相關資訊。 ↩ ↩2
-
Character Information Technology Promotion Council, 文字資訊基盤整備事業. 關於由 IPA 在經濟產業省等支援下整備、涵蓋行政事務所用約 6 萬漢字的文字資訊基盤(MJ 文字圖形、MJ 文字資訊一覽表、IPAmj 明朝字型),現已移交該協議會並公開。 ↩ ↩2
-
Digital Agency, 地方公共團體資訊系統文字要件維運相關檢討會報告書(令和 6 年 7 月). 關於自治體使用的外字據說約有兩百萬字,關於以文字資訊基盤擴充而成的「行政事務標準文字」(通稱 MJ+)作為符合標準系統姓名等的字集、字元編碼採用 JIS X 0221:2020,關於姓名等資訊的互通使用行政事務標準文字、與智慧型手機等的互通使用 JIS X 0213:2012,以及把既有外字唯一識別到行政事務標準文字後停止使用的方針。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, OS/2 — OS/2 and Windows Metrics (OpenType spec). 關於字型的 fsType 欄位定義嵌入授權(Installable / Restricted License / Preview & Print / Editable、禁止子集位元等),以及應用程式不得嵌入未獲授權嵌入的字型。 ↩ ↩2 ↩3
-
PDF Association, PDF/A Basics. 關於長期保存用的 PDF/A(ISO 19005)必須把顯示文件所需要素收進檔案內,其代表例就是必須嵌入字型。 ↩ ↩2
-
Microsoft Learn, Using Unicode Normalization to Represent Strings. 關於 Unicode 正規化的 NFC/NFD/NFKC/NFKD 四種形式,以及 KC/KD 形式會統合全形半形等相容字元而遺失資訊,因此一般不適合作為字串的正規保存形式。 ↩ ↩2
-
Unicode Consortium, Ideographic Variation Database. 以 UTS #37 為基礎的 IVS 登錄簿。關於已登錄 Adobe-Japan1(2007 年)、Hanyo-Denshi(2010 年)、Moji_Joho(2014 年)等收藏,以及 2026 年 8 月版也對 Moji_Joho 收藏做了追加登錄。 ↩
-
Microsoft Learn, BIZ UDGothic font family. 關於森澤製的通用設計字體 BIZ UD Gothic 從 Windows 10 版本 1809 起作為日文補充字型收錄。 ↩
-
Microsoft Learn, Fonts (Globalization documentation). 關於字型後備的機制,關於 GDI 的字型連結(FontLink\SystemLink 登錄檔),關於預設字形(豆腐)的意義,以及字型連結不能取代選對字型。 ↩ ↩2
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
整理 Windows 的字元編碼與換行符 - Shift_JIS / UTF-8 / UTF-16、亂碼、CRLF / LF,為何混亂
本文整理 Windows 上字元編碼與換行符容易混亂的核心:bytes、UTF-8 與 CP932、UTF-16LE、BOM、CRLF 與 LF 是不同軸的概念,亂碼源於以錯誤前提 decode,且誤儲存後無法還原。讀完即可在規格中寫出明確的 encoding 與換行約定,...
Windows 列印驅動程式停止提供 ── 業務應用程式的報表與標籤列印如何因應
Microsoft 正分階段推動 v3/v4 列印驅動程式的停止提供,從 2026 年 7 月起會優先選用 IPP 類別驅動程式。本文整理 Windows protected print mode 之下會消失哪些東西,並以判斷表梳理業務應用程式的報表、標籤列印中相依處的盤點...
從睡眠恢復就壞掉的應用程式 ── 電源事件的機制,以及耐得住恢復的業務應用程式寫法
打開筆電,業務應用程式的連線卻斷了──原因是設計從未把睡眠算進去。本文依一次資訊整理 WM_POWERBROADCAST 的通知流程、Modern Standby 的行為、斷線/重連設計、睡眠抑制,以及調查指令。
Windows 應用程式無障礙入門 ── 以 UI Automation 因應合理調整的義務化
以 2024 年 4 月施行的日本消除對身心障礙者歧視法修正為背景,本文以螢幕閱讀器讀取 Windows 應用程式的機制 UI Automation 為主軸,從實務角度整理 WinForms/WPF 的命名、鍵盤操作、對比與驗證工具。
多執行緒實務最佳實踐 C 語言篇 ── 以 Win32 API 的方式安全撰寫
C 語言 × Win32 的多執行緒有其定石:以 _beginthreadex 建立執行緒、SRW 鎖與條件變數、Interlocked、以停止事件 + WaitForMultipleObjects 設計停止流程。本文一併整理 TerminateThread 的危險性與 D...
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
常見問題
整理諮詢這個主題時常見的問題。
- 明明是同一個葛字,為什麼在不同 PC 或不同報表上看起來形狀不一樣?
- 這很可能不是亂碼,而是字型字形的差異。JIS X 0213:2004(JIS2004)把 168 個漢字的例示字形改成印刷標準字體,Windows 也從 Vista 起讓 MS Gothic/MS Mincho 等字型以 JIS2004 字形為預設。葛、辻、飴等就是代表例子:Unicode 碼位(資料)完全沒變,只有字型持有的字形(外觀)變了。因此比對資料會完全相符,XP 時代的報表影像與新 PC 的畫面顯示形狀不一致,是符合規格的行為。若連字形也要一致,就讓畫面與報表使用同一字型,或用異體字選擇器指定字形。
- 只要用異體字選擇器(IVS),姓名的字形問題就全部解決了嗎?
- 不會全部解決。IVS 是在基底字元正後方加上 U+E0100 以後的選擇器、把字形當成資料來指定的機制,必須支援的字型(例如 IPAmj 明朝)與支援的應用程式都到齊,才會依指定顯示。在不支援的環境,忽略選擇器、以基底字元的預設字形顯示才是正確行為;有些環境甚至會把選擇器顯示成 □。此外,帶 IVS 的一個字在 UTF-16 最多佔四個碼元,會影響字數計算、切片與資料庫欄長的設計。要導入時,請先確認顯示、列印、下游系統的支援範圍再使用。
- 用外字(EUDC)登錄的字,在別台 PC 或 PDF 上顯示得出來嗎?
- 原則上顯示不出來。外字是使用者把字形登錄到那台 PC 的 eudc.tte 檔、碼位落在 Unicode 私人使用區(U+E000 起)的機制,同一個碼位在別台 PC 上可能未定義,或是別的字形。因此一旦交到郵件、PDF 或其他系統,變成 □ 或看起來像別的字,是必然的結果。若已經接手含外字的資料,務實的做法是在遷移時盤點私人使用區的使用位置,做出對正規 Unicode 字元或異體字選擇器的對應表再替換。新系統則應避免再製作新的外字。
- 業務系統的姓名欄位該受理到多廣的字?
- 第一要務是「決定受理的字集,並在規格中寫明」。戶籍有約 5 萬 6 千字的戶籍統一文字,政府的符合標準系統則採用以文字資訊基盤擴充而成的行政事務標準文字;但一般業務系統沒有義務無上限地受理到同樣水準。務實的設計是先決定範圍,例如「到 JIS X 0213 的範圍為止」「不接受異體字選擇器與私人使用區」,在輸入時驗證,範圍外的字則以警示或替代寫法來處理。只有與政府系統或地方自治體互通的系統,才需要持續追蹤行政事務標準文字與以 JIS X 0221 為基礎的互通要求。
- 要怎麼讓報表或 PDF 顯示出與畫面相同的字?
- 基本做法是先讓畫面與報表指定同一字型,並把字型嵌進 PDF。字型不同,同一份資料的字形就可能改變;檢視端的 PC 沒有那個字型時,會以替代字型繪製而讓外觀走樣。能不能嵌入由字型授權(OpenType 的 fsType)決定,因此不要全丟給報表函式庫,請自己確認。只嵌入用到的字元的子集嵌入,也能壓低檔案大小。若有長期保存需求,就考慮必須嵌入字型的 PDF/A。