# 48. Kerning Panic·字谈字串（五）规范化有四样形式，你知道么？

内核恐慌 · 2017-07-25

<https://lib.pan.icu/8cd97453-21d1-4007-9690-f3e2a98b95b5>

本期节目深入探讨了Unicode规范化（Normalization）的四种形式：NFC、NFD、NFKC和NFKD，解释了它们在编码、存储和搜索中的不同用途。主讲人Eric（Speaker 1）指出，Unicode中同一字符可能有多种码位组合，规范化确保字符串等价性，但不同系统（如Windows使用NFC，macOS的HFS+使用NFD）会导致文件交换时出现乱码或字符拆分问题。吴涛和Rio补充了APFS文件系统对规范化不敏感的设计变化，以及它对开发者API选择的影响。节目还延伸到国际化域名（IDN）的伪码攻击风险、emoji域名安全漏洞，以及字体的合字（ligature）在搜索中的障碍。最后，听众反馈环节解答了中西文混排的行高对齐问题。整个讨论强调Unicode规范化的技术复杂性及其在实际应用中的坑。

## Questions this episode answers

### 什么是Unicode规范化，为什么需要它？

蒸鱼和吴涛解释，Unicode中同一字符可由不同码位序列表示，如带声调字母可组合或预组。规范化提供标准方式判断字符串等价，有四种形式：NFC、NFD、NFKC、NFKD，分别基于标准或兼容方式的分合。这解决了历史遗留问题，便于比较、搜索和存储。

[53:12](https://lib.pan.icu/8cd97453-21d1-4007-9690-f3e2a98b95b5?t=3192000)

### 苹果的新文件系统APFS如何处理Unicode规范化，与HFS+有何不同？

吴涛、Rio和蒸鱼讨论，HFS+采用NFD（分解优先），会将组合字符拆分存储；APFS改为规范化不敏感，不管用户以何种形式输入，都通过哈希值实现文件唯一标识和查找。这避免了跨系统拷贝时因规范化形式不同导致的文件拆分问题，但可能带来兼容性挑战。

[1:08:36](https://lib.pan.icu/8cd97453-21d1-4007-9690-f3e2a98b95b5?t=4116000)

### Unicode规范化如何被利用来进行域名钓鱼攻击？

Eric和吴涛指出，国际化域名支持Unicode后，不同语言字符外观可完全相同（如希腊大写Alpha与英文字母A），但码位不同。攻击者可注册形似正规域名的网站，如用希腊A的apple.com，用户难以区分，骗取密码。虽然Punycode转换会处理，但浏览器显示仍可能混淆。

[1:57:30](https://lib.pan.icu/8cd97453-21d1-4007-9690-f3e2a98b95b5?t=7050000)

## Key moments

- **[0:00] 开场**
  - [1:00] 四人首次同空间见面是在五月底的TIB十周年活动，此前虽多地见过但从未齐聚
  - [2:05] "我们四个人没有合影，Rio也没有和其他三人合过影" ——吴涛
- **[3:02] 字体课程**
  - [4:35] TypeSchool中文设计课将于8月4日至9日在北京举办，由方正字库裘颖等资深设计师授课
  - [5:31] 优秀学员可与方正签约，由方正帮助完成剩余数千汉字，降低造字门槛
  - [6:05] Glyphs开发者Georg来中国，将为Glyphs增加方块汉字特殊功能以更好支持中文设计
- **[7:22] 打字机**
  - [7:42] 打字机没有独立的回车键，换行通过拨动字车手柄同时实现回车和换行，并伴有铃声提示
  - [9:52] 蒸鱼和吴涛讨论中文打字机：字盘可替换，常用字词如‘中华人民共和国’可集中排列以提高打字速度
  - [13:12] 中文打字机力度控制需精确，用力过重可能戳穿纸张，尤其是笔画复杂的繁体字
  - [14:44] "Markdown回归说明所见即所得并非强需求" ——吴涛
  - [15:28] Word过于迁就用户导致样式混乱，而Pages更强调结构，易保持一致性
  - [17:54] "用Word做好排版需要高度自律，忍住不直接改格式的冲动" ——吴涛
- **[23:31] 文本高度**
  - [25:39] 文字显示高度由字体内部metrics决定，中西文混排时均按基线对齐，排版引擎可指定对齐方式但实现可能不符预期
- **[35:40] 排序规则**
  - [35:45] Q: 多语言字符串在iPhone通讯录中如何排序？如何得到汉字读音？
  - [37:37] iPhone通讯录利用phonetic name字段存储发音用于排序，可借助脚本批量注音
  - [41:34] Rio在日文系统下给中文联系人加注音，使其按拼音排序到字母部分，避免堆在井号区
  - [42:54] 名字中的多音字（如“茜”可念xi或qian）无规则可循，自动注音很难处理
  - [44:45] 即使是拼音文字也存在读音歧义，如Warmbier在德语和英语中念法不同，影响排序
  - [49:07] 多语言排序需考虑操作系统、应用层和政治策略等多层面因素，非常复杂
- **[52:12] 规范化入门**
  - [52:12] Unicode规范化解决的是判断两个Unicode字符串是否等价的问题
  - [53:45] 一个视觉字符如á可由单个码位或a加声调符号组合表示，这是等价性的根源
  - [54:10] Unicode等价性问题根源于向后兼容ASCII及各国编码的历史遗留
  - [57:38] 采用组合方式生成带变音符号的字符是为了节省码位空间，如越南语多重标音
  - [1:00:01] 不同语言对字符认知不同，德语ü视为独立字母，法国ç同样，影响编码设计
  - [1:02:34] 日语假名浊音点问题：が既可是独立码位也可是か加浊点，半角片假名亦是历史遗留
- **[1:06:13] 形式与系统**
  - [1:06:13] Unicode定义了四种规范化形式：NFC、NFD、NFKC、NFKD，分为标准等价和兼容等价
  - [1:07:24] 标准等价与兼容等价的区别：兼容等价会将合字ﬁ、圈数字等拆解以支持模糊搜索
  - [1:08:36] 苹果新文件系统APFS对规范化不敏感，解决了HFS+因NFD导致日文字符被拆开的问题
  - [1:11:29] HFS+采用NFD，导致Windows上的假名拷贝到Mac后被分解，可单独删除浊点造成困扰
  - [1:12:06] 文件系统层是否应关心规范化？APFS认为不应参合应用层逻辑，HFS+却做了处理
  - [1:14:18] HFS+在文件系统层做规范化，APFS不再处理，可能导致依赖此行为的应用出问题
- **[1:24:29] 兼容分解**
  - [1:24:33] 兼容分解将合字ﬁ拆分为f和i，使得搜索fi也能匹配ﬁ，实现模糊匹配
  - [1:28:21] 兼容分解还涵盖半角全角假名、竖排标点等视觉变体的等价，以便搜索
  - [1:31:32] 火星文无法纳入规范化，因为汉字偏旁部首组合不唯一，不满足幂等性要求
  - [1:35:03] Unicode为维持规范化幂等性，严格规定了组合字符的固定顺序，如上下加点的次序
  - [1:37:28] APFS通过额外生成文件名哈希值来实现规范化不敏感性，但哈希与大小写保留存在矛盾
  - [1:41:47] 苹果在APFS预览版中先推出case sensitive，后加入case insensitive，说明解决大小写与哈希冲突很复杂
- **[1:55:43] 域名安全**
  - [1:55:58] Punycode攻击可利用不同语言中形状相同的字符（如拉丁A和希腊Alpha）伪造域名进行钓鱼
  - [1:57:30] Eric反对域名使用Unicode，认为引入后视觉相同字符导致钓鱼攻击，过度复杂化
  - [2:00:56] 有人用锁emoji作域名开头，配合希腊字母A伪造apple.com，展示域名安全风险
- **[2:05:50] 结尾**
  - [2:06:02] 上期抽奖中听众“灰”未联系到，请发邮件至podcast@type.com以领取奖品

## Speakers

- **Rio** (host)
- **吴涛** (host)
- **Eric** (guest)
- **蒸鱼** (guest)

## Topics

字符编码, 安全

## Mentioned

Apple (company), IBM (company), Meta Design (company), 微软 (company), 方正字库 (company), APFS (product), Courier (product), Glyphs (product), HFS+ (product), IBM Selectric (product), Swift (product), TypeSchool (product), Windows (product), iOS (product), macOS (product)

## Transcript

### 开场

**Eric** [0:20]
大家好 ， 今天是 7 月 25 号 ， 现在您听的是 《 字谈字串 》 的第 52 期 。

**吴涛** [0:26]
同时也是 《 内核恐慌 》 的第 48 期 。

**Eric** [0:29]
这也是我们 《 字谈字畅 》 和 《 内核恐慌串台 》 的 《 字谈字串 》 节目的第 5 期 。 我们 《 字谈字畅 》 是全球首家用华语制作的字体排印主题播客节目 ， 我是主播文川西半东营区 Eric。

**Rio** [0:42]
我是主播黄浦江边新真人鱼 ， 钱真人鱼 。

**吴涛** [0:46]
《 内核恐慌 》 是 IPN Podcast 网络旗下的 IT 技术主题娱乐节目 ， 我们号称 "Hardcore"，但是也没有干货 。 想听的人听 ，不想听的人就别听 。

我是主播吴涛 。

**Rio** [0:58]
我是 Rio。

**Eric** [1:00]
你说啊 ， 我们这个节目串台都已经串了第 5 期了 ， 等到上次 5 月底才第一次四个人一起在同一个空间见面是吧 ？

**Rio** [1:08]
历史性的会晤啊 。

**Eric** [1:09]
对 ， 我们四个人没有合照 。 那年活动来了好多播客主播吧 ？

**Rio** [1:14]
啊 ， 数来应该有差不多小 10 个 。

**Eric** [1:18]
你们后来就背着我们就直接去喝酒了 。

**吴涛** [1:21]
你们不是也去喝酒了吗 ？

**Rio** [1:23]
你们不是还要去打扫场地吗 ？ 那没有办法呀 。

**Eric** [1:27]
对啊 ， 虽然说是 TIB 十周年活动节目 ， 搞得好像是变成国内 IPN 和各台电台主播的一个小聚会了 。

**Rio** [1:37]
小众播客网络 。

**吴涛** [1:40]
而且其实现在我跟 Eric 在东京见过 ， 然后我跟 Rio 见过很久了 。Eric 跟蒸鱼之前也在上海见过很多次 。

**Rio** [1:51]
对 。

**蒸鱼** [1:52]
我跟 Rio 也见过一次 。

**Eric** [1:53]
然后我跟 Rio 在深圳也见过一两次 。

**Rio** [1:57]
两次 ， 对 。

**吴涛** [1:59]
但真正所有人在一起见 ， 这是第一次 ， 还挺难得的 。

**Rio** [2:05]
我们可以在 show notes 发一下上次活动的剧本 ， 就是四个人都在的照片应该有吧 ？

**蒸鱼** [2:11]
没有 。

**吴涛** [2:13]
好像咱们四个没有合影 ， 对 。

**Eric** [2:16]
Oh my god。

**Rio** [2:17]
啊 ？ 这么惨 ？

**蒸鱼** [2:18]
把吴涛 P 上去 。

**吴涛** [2:21]
不是 ， 那个 Rio 也没有跟其他三个人合过影 。Rio 也没有跟你们两个合过影 。

**蒸鱼** [2:28]
好像有 。

**Rio** [2:28]
走的时候好像有 。

**Eric** [2:29]
肯定有照片 ， 同时有我和 Eric 和 Rio 的 。 我记得有一张 ，有一张有各种主播在一起 。

**吴涛** [2:36]
有一张是你们两个在内间 。

**蒸鱼** [2:41]
那个是一个节目 。

**吴涛** [2:43]
然后 Rio 站在外面的照片 ， 对 。

**Rio** [2:45]
啊 ， 对 ， 这个也有 。 然后活动结束的时候 ， 我跟 Eric 和蒸鱼都有合影 ，但是那个时候吴涛不知道去哪去了 。

**吴涛** [2:52]
我去喝酒 。

**Eric** [2:53]
对啊 ， 去泡妹子了 。

**Rio** [2:54]
吴涛喝花酒去了 。

**吴涛** [2:55]
泡 kiss。

### 字体课程

**Eric** [3:02]
好 ， 首先跟大家讲一讲 ，其实这也不算广告了 ， 我们自己 TypeSchool 七月份的课程已经结束了 。 七月份这个西文的字体设计课程 ， 大家应该虽然很累 ，但很辛苦 ，但是估计大家收获也蛮大的 。

**蒸鱼** [3:18]
一共有几天啊 ？

**Eric** [3:20]
两个礼拜啊 。

**Rio** [3:21]
哦 。

**Eric** [3:22]
我也过去

跟着和大家凑了一会儿热闹 ， 看我们的格奥尔格老师给大家讲 Glyphs， 挺有意思的 。

**蒸鱼** [3:33]
哎对了 ， 我一直很好奇 ，Gale 他是一个字体设计师吗 ？

**Eric** [3:37]
对 ，他自己设计师 ，他自己设计字体 ，但是他有一些计算机开发的基础 ， 然后他做出 Glyphs， 几乎现在就全球都在做 Glyphs 这个软件了 。

**蒸鱼** [3:50]
所以他应该是一个计算机科学出身的人吧 ？ 就是他是一个 。

**Eric** [3:55]
他是设计师出身 。

**蒸鱼** [3:57]
那他竟然能写这么复杂的 。 我觉得 Glyphs 已经是一个非常复杂的软件了 。

**Eric** [4:01]
对 ， 对 。

**蒸鱼** [4:04]
非常令人惊讶 。

**Eric** [4:05]
对 。

**蒸鱼** [4:06]
好吧 。

**Eric** [4:07]
设计界需要这样的人才 。 所以我也希望有更多的设计师来听我们的 《 字谈字串 》。

**蒸鱼** [4:13]
好吧 。

**Eric** [4:15]
然后就有很多朋友问 ， 就是因为这次是讲西文嘛 ， 那有没有学中文的字体设计课程 。 然后其实呢 ， 就是可能大家在微信上面有看到消息了 ， 我们在 8 月 4 号到 9 号呢会有这样一个课程 ， 叫 TypeSchool 的中文字体设计课 ，而且这次呢不是在上海 ，是在北京 。

然后我们请到了老师呢 ， 就有方正字库的思维设计师 ， 包括像裘颖 ， 裘颖先生这样经验非常丰富的字体设计过很多中文字体的设计师 ， 可能大家都知道他最著名的字体就是那个 U 黑嘛 。

**蒸鱼** [4:51]
对 。

**Eric** [4:51]
然后 TypeSchool 呢就会教大家如何实现字库 。 然后因为是做中文 ， 所以呢可能工程比较浩大 ， 说从 12 个字扩展到 50 个字到 500、5000、5 万 ， 对吧 ？

平时大家设计中文的话是没有头绪嘛 ，不知道怎么用什么方法做 ， 然后要做多少字 。 然后一旦多了话呢 ， 对吧 ， 这个怎么提高效率 ， 然后呢尽早

发现问题 ， 对吧 ， 比如说大小不一样啊 ， 怎么处理啊 ， 这些我们都会具体的在 TypeSchool 请老师呢给大家介绍 。

**蒸鱼** [5:31]
对 ，不过 5 天时间其实做 12 个字也就差不多 。

**Eric** [5:35]
我们这次呢有一个很好的机会是优秀的学员啊 ， 可以和方正签约 。 只要你先做好几百个字 ， 剩下的成千上万字啊 ， 方正会帮你做 。

**蒸鱼** [5:48]
啊 ， 对 ， 这个其实就跟之前的这个字体竞赛很相似啊 ， 就是你提交一份样字的作品 ， 然后如果字体公司觉得非常合适 ，有商业化的价值的话 ，他会与你签约 ， 然后帮你把它做成一个真正意义上的字库 。

**Eric** [6:05]
当然在这样的课程里面呢 ， 大家也会可以接触到 Glyphs 这样一个什么字体神器啊 。其实而且这次呢我们 Glyphs 开发者格奥尔格来中国 ， 给他切身感到了啊 ， 做方块汉字的一些特殊的要求呢 ， 我们有很多新的功能也会加到这个 Glyphs 里面 ， 给大家可以试用一下 。

这次呢我们还邀请到了德国的 Meta Design， 那 Meta Design 的德国的他们那边的这个公司的他们的设计师也会参与到活动里面进来 ， 那对 Meta Design 感兴趣的朋友呢也有机会啊 。

所以这也是蛮难得的一个机会 。

**蒸鱼** [6:49]
嗯 。

**Eric** [6:50]
8 月份的北京比较热哈 ，但是呢我觉得 7 月份的上海也够热的 。

**蒸鱼** [6:57]
上海更热吧 ？ 我觉得这两天北京比上海凉快多了 。

**Eric** [7:01]
没有 ， 北京还好是干热嘛 ， 上海主要是湿度比较大 ， 比较难受 。

**蒸鱼** [7:06]
对 ， 上海这周是爆热 ， 已经超过 40 度了 。

**Eric** [7:10]
对啊 ，有这种夏令营的感觉哈 ， 那大家呢也欢迎大家来多多的进行报名 ，其实有这样的机会是非常难得的 。

**蒸鱼** [7:20]
对 。

### 打字机

**Eric** [7:22]
好了 ， 难得我们这次第五次的串台嘛 ，但是还要先讲一下反馈 。 那上次呢就是我们的 《 字谈字串 》 的第四期 《 峰回路转换 》， 后来呢有一位朋友说吴涛重新发明打字机 ， 吴涛重新发明打字机 ， 带回车键的打字机 ， 感叹号 。

**Rio** [7:42]
所以打字机是没有回车键的 ， 对吧 ？

**吴涛** [7:45]
对 ， 打字机没有一个键是你按下去之后它会跳到下一行 。 哎 ，wait a second， 好像是有的 ，但这个键并不是回车键 ， 就也不是在每一个打字机上都有 。

然后换行的时候是你拨动那个左边的拨杆 ， 把字车往右拨的过程中， 它会自动朝下滚一格 。 所以换行这个功能实际上是在字车上实现的 。

**Eric** [8:11]
正义还是把那位听众的反馈念一下吧 。

**蒸鱼** [8:15]
好吧 ， 刚 Eric 念的是第一行 ， 然后接下来念 ， 说打字机没有回车键 ， 打字机滚筒左端的手柄兼具回车与换行功能 ， 手柄从左向右平推可以将滚轮向右推送 ， 就是回车 ， 手柄从左向右扳动 ， 同时带点轻微的顺时针扭转可以滚动滚动 ， 就是换行 ， 扳得轻一点可以换半行或四分之一行 ， 打字时当滚动行进行到进

到接近行末位置时会有叮的一声铃音提示 ， 平推手柄将滚轮推到最右实现回车 ， 顺势继续用手 ， 哎 ， 顺势继续用力手柄会自然向右摆动转动滚轮 ， 这好拗口 。

**吴涛** [9:09]
你怎么了 ？ 你用这个不正来了吗 ？ 钱真人鱼 。

**蒸鱼** [9:11]
这好拗口 。 实现换行 。OK， 大家听懂了吗 ？

**吴涛** [9:17]
没有 ， 我是没听懂 。 我知道它是什么意思 ， 就是你在敲一行 ， 比如说这一行有 80 个字符 ， 然后你敲到大概 75 个的时候 ， 打字机会叮一声告诉你说没地了 ， 你赶紧换行 。

然后这个时候你压左侧的那个换行杆 ， 稍微压一下， 然后那个字车就会往上滚一格 ， 然后你继续往下压 ， 它就会把整个字车拉到纸的最左边 ， 然后就这么一件事 。

**蒸鱼** [9:50]
嗯 。

**Eric** [9:51]
对 。

**吴涛** [9:52]
我还是很好奇为什么你们小时候都没有用过打字机呢 ？

**蒸鱼** [9:56]
对 ， 就没有用过西文 。

**吴涛** [9:59]
哦 ， 没有用过 。 所以你用过中文的打字机 ， 那更屌了 。 中文打字机是一个一米乘一米的大台子呀 。

**蒸鱼** [10:07]
对 ， 这个我用过 ， 就玩过一下 。

**Eric** [10:10]
那个真的存在吗 ？ 就是那个那么多个字是那么大怎么移动呢 ？

**吴涛** [10:16]
是一个笛卡尔平面 ， 你要 XY， 真的 。

**Eric** [10:24]
天 。

**Rio** [10:26]
那能有多少个字啊 ？ 上面字母啊 。

**吴涛** [10:28]
相信一万个吧 ， 可能有 。

**蒸鱼** [10:30]
很多很多 。

**Eric** [10:30]
没有吧 ？ 没有没有 ，不到一万多吧 。 那一两千肯定是有的 ，因为中文 。

**吴涛** [10:37]
我印象里面 ， 我印象里面我玩过的那台是有 6000 个字 。

**Eric** [10:42]
因为中文常用字也就 3500 吧 。

**Rio** [10:45]
就它把常用字放上面 ， 然后不够的是用空格 ， 然后就再手写 。

**Eric** [10:49]
它底下那个可以换的 ， 可以替换 。

**吴涛** [10:52]
我印象里面是个 100 乘 100 的格子 ， 你知道吧 。

**Eric** [10:55]
嗯 ， 我印象好像有那么多吗 ？ 没那么大吧 。

**吴涛** [10:59]
没有 100 乘 100 吗 ？

**Eric** [11:01]
嗯 ， 记不大清楚了 。

**蒸鱼** [11:03]
挺大的 ， 对 ， 挺大的 。

**吴涛** [11:05]
对 ， 反正是个相当大的东西 。

**蒸鱼** [11:07]
我刚给大家发了一个链接 ， 那个也是一种汉字的打字机 ， 这个是日本人做的 ， 然后它是一个滚筒式的选字机构 。

**吴涛** [11:19]
哦 ，OK， 这个比较牛逼 。

**蒸鱼** [11:22]
对 ， 这个是在京都的汉字博物馆里面展示的一件展品 。

**Rio** [11:27]
哎 ，其实如果这么多 ， 这怎么记啊 ？

**蒸鱼** [11:32]
可能熟能生巧吧 。 另外它肯定排字是有规则的 ， 你看它有标了不同的颜色 。

**Rio** [11:37]
排一位哦 ？ 它会给 Color 这样排吗 ？

**蒸鱼** [11:40]
不 ， 汉字应该不是这样排的 。 应该是按音式排的吧 ？ 它而且有颜色划分嘛 ， 应该是按那个所谓的行合列 ， 就是 50 音的行合列的发音来标音之后再分开 。

**Eric** [11:55]
我天 ， 怎么记得住啊 ？ 哪个字在哪个位置 ？

**蒸鱼** [11:57]
还是要找的 。

**Rio** [11:59]
不 ， 你想就说假设只有 3000 个常用字的那个滚筒的话 ， 那这打字速度应该很慢吧 。

**蒸鱼** [12:07]
嗯 ， 就得转 ， 转然后找 ， 找完以后才打出一个字来 ， 就是这样 。

**吴涛** [12:12]
它这个毕竟还是按拼音排列的 ， 我觉得可能还是要比中文打字机那个按部首排列的要快一点 ， 我觉得 。

**蒸鱼** [12:19]
对 ，不过因为日语一个字有很多发音嘛 ， 所以你可能得记住这个字它用的是哪个标音 。

**Eric** [12:27]
像我以前看的 ， 就是我爸单位他们那个打字员用的那种打字机的话 ， 它底下那个

钢冲的那个钢字的盘是可以换的 ， 所以它经常会把这比如常用的字的组合 ，因为它可以随任意调配嘛 ， 然后把常用的放在一起 ， 比如中华人民共和国 ， 它就全部放一起 ， 咔咔咔咔咔 ， 它就顺下来可以直接打出来就可以 。

**蒸鱼** [12:52]
啊 ，而且我记得就我见到那个中文打字机 ， 好像它那个字盘不只是一层 ， 它好像有两层的 ， 可以抽的 。

**Eric** [13:00]
啊 ， 对 ， 没错 ， 对 ， 没错 。

**蒸鱼** [13:01]
上面有一层可能是常用的 ， 下面还有一层次常用的 。

**Eric** [13:05]
哦 ， 对对对 ， 没错 ，是这样的 。 所以我印象中的中文打字机没那么大 。

**吴涛** [13:12]
嗯 ，有道理 ， 对 ，100 乘 100 好像移动起来挺麻烦的 。

**Eric** [13:18]
打太极拳都可以 。

**Rio** [13:21]
因为我小时候其实根本没有见过这些就纯机械的打字机 ，因为我记得我小时候第一次看人打字的时候已经是有那个叫 ， 那个叫什么来着 ， 就是字符 ， 那个 DOS 环境里面有一个中文的系统 。

**Eric** [13:35]
WPS。

**吴涛** [13:38]
是 CCED 吧 ， 应该是 。

**Rio** [13:39]
对 ，CCED 是更早的 ， 后来 WPS 后出的嘛 ， 然后后出的时候那个时候已经有那种就是在那个 WPS 的那个就是字符界面那个版本里面去排印 ， 然后用那种真实打印机再把那个字打出来嘛 ， 所以这个时候其实已经没有见过真的那种传统意义的打字机了 。

**Eric** [13:58]
我高中办校报的时候就是用那个先进 UCDOS， 然后再进那个 WPS， 然后呢它那不是一个 ， 它是字符编辑界面嘛 ， 它不是那个所见即所得的嘛 ， 所以你得要一些装饰的东西 ， 都用那个符号写进去 ， 好像不停不停的预览 ， 然后经常 386 的机器还会死机 。

**吴涛** [14:19]
对 ， 那个时候对于所见即所得没什么概念嘛 ， 就是你要不停的预览 。 但是后来基本上熟练一点的人会对于文章大概会看起来是什么样子有个概念 ， 就跟现在手写的 HTML 一样 ， 然后预览 。

**Rio** [14:36]
本质上也是一种 Markup 语言嘛 ， 那个 。

**Eric** [14:38]
是 ， 那完全就是 Markup， 所以你脑子中要想好你所要的是什么东西嘛 。

**Rio** [14:43]
嗯 ， 对 。

**Eric** [14:44]
所以其实现在我们又回 Markdown 又回去了是吧 ？

**Rio** [14:46]
又回来了 ， 对 。

**吴涛** [14:49]
实际上我觉得这个所见即所得并不是一个强需求 ， 说实话 。

**Eric** [14:56]
就要看它那个门槛放低了以后是可以让更多人进来嘛 ，但是对于专业用户的话可能需求不一样嘛 。

**Rio** [15:04]
对 ， 就我觉得所见即所得本身是没有问题的 ， 主要问题在于现在就主要是像 Word 那个实现 ， 它的那个实现过程有问题 ， 就是它把所有的那个效果都直接锁键了 ， 你没有办法用一个类似于像模板或者是一种格式的方式 ， 虽然有格式刷 ，但是那个格式刷就是极其不稳定嘛 。

**吴涛** [15:28]
我觉得这个问题太迁就用户了 ， 就是用户说我这个小标题要

15 磅重加粗 ， 下一个小标题他就弄了一个 16 磅重 ， 然后倾斜 ， 然后 Word 就傻逼了 ，Word 说哎呦 ， 我应该怎么办呢 ， 我应该问用户说不对 ， 你上一个小标题用的是这个 ， 然后这个小标题你也得用那个 ，但是这样一来用户可能不爽 ， 那我还是迁就用户再多分出来一个小标题吧 ， 然后等到整篇文章写完之后发现小标题的 style 可能有 20 种 。

**蒸鱼** [16:03]
35 种 。

**吴涛** [16:04]
对 ， 如果一上来你们从来没有学会过用 Word 格式刷这个习惯的话呢 ， 那基本上就最后只能手动改 。

**Rio** [16:13]
不 ， 关键是那个格式 ， 它那个格式刷它也是一个就是事后加的东西 ， 我觉得 ， 就是它的本质上它的主理结构是以那个实际看的为准的 ， 这点跟那个苹果那个 Pages 就是跟 Word 差不多的一个软件的逻辑是完全不一样的 。Pages 里面其实你是可以先定义那个文章的结构 ， 比如说这个刚才讲说这个是标题 ， 就是一级标题 ， 二级标题 ， 然后是正文 ， 这

个是这个表格的内容 ， 然后定好之后你是可以直接通过改那个类型的文本 ， 比如说我要改标题都改成一种同样的东西 ， 它可以直接更新 ， 然后让所有的标题文本都是长那个样子的 ，但是在 Word 里面这一点实现起来是非常不稳定的 。

**蒸鱼** [16:53]
哎 ，Word 也有这功能 。

**Eric** [16:55]
Word 也有 ， 对 。

**蒸鱼** [16:56]
只是实现非常的少 。

**Rio** [16:58]
不是不是 ， 它的实现确实是有问题的 ， 就是它不是那么强调那个结构和统一的这么一个概念 ， 就刚才讲吴涛说的嘛 ， 就是用户觉得这里要改一点 ， 那一点改 ， 它就不去 enforce 这个一致性的问题 。

**Eric** [17:13]
这个其实是专业用户的一个需求不一样的 ， 像我当年也曾经用 Word 做 40 页的小册子的时候 ， 我都是用那个样 ， 那个叫什么 style 样式吧 ， 它专门有个样式小窗口来做的 。

**Rio** [17:27]
对对对 。

**Eric** [17:27]
你做长文档的时候就必须要用那样来做 ， 要不然的话非常复杂 。

**Rio** [17:32]
对 ， 就是那个实际使用的情况下 Word 就会出现刚才我才讲的那个问题 ， 就是你的那个格式刷它不是有一个列表有多少种格式嘛 ， 你可能一边稍微长 10 页的文档可能会出现四五十种那个不同的格式 。

**吴涛** [17:43]
对 ， 就是 Word 对于就是你想把 Word 用好的话 ， 你要有一个你要有一个非常好的 ， 怎么说 ，discipline， 就是你必须是一个非常自律的 。

**Eric** [17:53]
高度自律的人是吧 ？

**吴涛** [17:54]
对 。

**Eric** [17:55]
对 。

**吴涛** [17:55]
你一定要忍住那个选中这一行字 ， 然后直接往上改变它的格式的这个 ， 改变它的样式的这个冲动 ， 然后忍辱负重的去用格式刷来刷这行字 。

**Eric** [18:09]
嗯 ， 对 。

**吴涛** [18:10]
对 ， 否则你就乱了 。

**Rio** [18:11]
它很容易在那些小细节地方就变掉 ， 就是你用格式刷也刷不回来 ， 就有些我不知道你们遇到过 ，有些比如说两个字之间出现一个东西 ， 你不论用格式刷你点多少次它都不会变的 ， 就是它的内部应该是有一些实现的 bug 的 。

**Eric** [18:25]
这个东西就是那你要自律的话看有没有洁癖了 ， 对吧 ？ 就千万不能用硬回车来撑行距 ， 对吧 ？

用空格来撑字距 ， 对吧 ？ 像这种东西的话 ， 本来就是排版的首先的做法是不一样的呀 。

**吴涛** [18:44]
OK， 补充一句刚才说的那个中文打字机 ， 我记得那个中文打字机它有一个最大的问题就是它不像英文打字机 ， 英文打字机也有这个问题 ，但是没那么严重 ， 就是你在用英文打字机的时候你可能按一个键 ， 你的力度轻了 ， 那个打在纸上的字就会不清楚 ，而中文打字机是如果你力度轻了那个字不清楚也就罢了 ， 如果你用力比较重的话 ， 那个

字那个笔画又比较复杂 ， 比如

繁体的什么国家的国字啊这种字 ， 你一打上去那个纸会不会穿烂的 ， 你想想 。

**Eric** [19:23]
嗯 。

**吴涛** [19:24]
对 ， 所以那个时候不仅打字是一个要寻纸 ， 你还要控制自己打字的力量 ， 真的是很累很累的 。

**Eric** [19:34]
哎 ， 为什么会这样呢 ？

**Rio** [19:35]
所以它那个按键是不是均匀力度下卷 ，是靠你的那个手的力量来决定的 。

**吴涛** [19:41]
对 ，其实它是把一张纸卷在一个大滚筒上， 那个滚筒是在这个笛卡尔平面上就移动的嘛 ， 然后移动的时候你找到一个字 ， 你要把那个手给压下去 ， 然后我理解是它把那个签字吸上来 ， 然后在纸上戳一下， 然后这个如果戳的比较狠的话 ， 那个纸就会破 。

**Eric** [20:06]
对 。

**蒸鱼** [20:08]
哎 ，但我觉得像用键盘的这种打字机 ， 它完全是可以用机械设计解决这个问题 。

**吴涛** [20:14]
对 ， 像 IBM 的那种又是用球形的那个打字头的打字机 ， 它就是它把输入跟那个打字的部分分开了 ， 就是实际上你是驱动一个发条 ， 然后那个发条每次会以均匀的力度把那个字打在纸上 。

**Eric** [20:29]
对对对 。

**吴涛** [20:29]
但这个都比较高端了 ， 对 ， 这个都比较高端了 ， 就家用的那种就是变 ， 尤其是便携的袖珍的打字机 ， 都是还是你按你的手按的力度多大 ， 那个字就有多深 。

**Rio** [20:41]
怪不得看有些那种以前那种打字机打的文档 ， 它有些那个字符的粗细是不一样的 ， 就是因为这个原因是吧 ？

**吴涛** [20:49]
对 ， 就是用力太 。

**Eric** [20:51]
力度的问题 。

**吴涛** [20:52]
对 。

**Eric** [20:53]
OK。 这也是 ， 这个真的是个手艺活 。

**吴涛** [20:56]
对 ， 你像那个

IBM 出的打字机里面 ，Courier 这个字体就是这么来的嘛 ， 就是专门为了它那一个滚筒式打字机的那个设计的一套字体 ， 就 Courier。

**Eric** [21:11]
有什么讲究吗 ？

**吴涛** [21:12]
就是等宽嘛 ， 那个时候的等宽 ， 然后是就有点 slab 的感觉嘛 ， 就是带一点点衬线那样 。

**Eric** [21:19]
OK。 最近有个新闻可以和大家分享一下 ，因为我们前一段时间说过那个 Emoji 嘛 ， 就是表情符号嘛 ， 刚好 7 月 17 号就是 Emoji 日 。7 月 17 号是 Emoji 日这个事情你们知道吗 ？

**蒸鱼** [21:32]
我们提过 。

**Eric** [21:33]
真的不知道 。

**蒸鱼** [21:34]
我们提过 。

**吴涛** [21:34]
Emoji 还有自己的节日呢 ， 已经 。

**Eric** [21:37]
对啊 。

**蒸鱼** [21:37]
我们讲 Emoji 那期提过这个事情 。

**Rio** [21:39]
哎 ， 为什么是那天我忘了 。

**蒸鱼** [21:41]
就是因为那个 Emoji 的那个日历的图标上写的是 7 月 17。

**Rio** [21:45]
哦 ， 对对对 。

**蒸鱼** [21:46]
哦 ， 对 ， 我想想 。

**Rio** [21:47]
苹果那个日历 。

**Eric** [21:49]
沿用苹果的那个 ， 当时还叫 iCal 的日子 ， 对 ， 然后这次苹果居然在他们官方网站上面搞一个什么新闻出来了是吧 ， 预先把今年稍晚推出的那个表情符号跟大家展示了一下 。

**蒸鱼** [22:05]
嗯哼 ， 就是 iOS 11 里面会搭载那一套新的 。

**Eric** [22:10]
对 ，也就是 6 月份 Unicode 第十版里面已经通过的这些 ， 它已经准备好 ， 已经画好了嘛 ， 就马上就要拿出来跟大家用了 ， 比如说有什么僵尸 ， 水 ，有什么戴头巾的女人， 长胡须的人。

**吴涛** [22:29]
僵尸和穆斯林是同一个批次的是吧 ？

**Eric** [22:34]
或者说应该还有什么饺子和筷子嘛 ，不是 ？ 我上次在节目 ，在我们节目里面说过 ， 到它到底是画成包子还是画成馄饨的 ， 那就不知道了 。

**蒸鱼** [22:44]
到时候看实现吧 。

**Rio** [22:47]
哎 ， 所以现在在那个 iOS 11 的预览 ， 那个就是什么 beta 版你们应该已经可以看得到了吧 ？

**Eric** [22:53]
你们装了吗 ？

**Rio** [22:55]
我在 iPad 上装了 ，但还没注意到看那个表情 ， 那个 Emoji 的变化 。

**蒸鱼** [23:02]
好像还没吧 。

**吴涛** [23:03]
我没装 。

**Eric** [23:04]
我没装 。

**蒸鱼** [23:06]
我也没装 ，但好像还没上吧 。

**Rio** [23:08]
它上了一个叫做 public beta， 上了两次了 。

**蒸鱼** [23:12]
对 ， 我知道 ，但 Emoji 好像还没上 。

**吴涛** [23:13]
巨不稳定 ， 我看好多人都说巨不稳定 。

**Rio** [23:16]
哎 ， 我在那个 iPad 上装的 ， 反正还行 ，因为这次 iPad 改动比较大嘛 ， 待会我们去看一下， 看那个 iPad 上有没有 。

**蒸鱼** [23:22]
嗯 。

**Eric** [23:26]
那现在就可以念另外一封听众反馈了是吧 ？

### 文本高度

**吴涛** [23:31]
可以啊 。

**Eric** [23:32]
好 ， 我来念一下吧 。 一位没有署名的听众 ， 就后来我问了他 ， 我还专门写信去问了他应该怎么称呼 ， 然后他说可以称呼他叫 Tiger， 老虎 ， 然后这位自称叫老虎的听众来了一封邮件 ， 说赞美主播并纠结两个问题 。

两位主播好 ，他是写给字谈字畅的 。 两位主播好 ， 我是一个通信工程毕业的码农 ， 具体来说是做 iOS 开发的 ， 大概一年前吧 ， 偶然机会发现了你们的播客 ， 一直听到现在 ， 很佩服你们的毅力能够持续更新 ， 超越了内核恐慌 。

我是码农 ， 所以最开始听的是内核恐慌 ， 听你们播客过程中 。

**Rio** [24:14]
感觉我们还没超越 。

**Eric** [24:16]
我受益匪浅 ， 知道任何东西都不是简简单单的 ， 一个设计作品或者具体到一个 UI 界面 ， 看起来很舒服 ， 一定是有其背后的道理 。

我也看了你们推荐的一些书籍 ， 做了一些笔记 ， 这里就不说了 ， 一直以来就想着就这样被你们润物细无声也挺好的 ，但是我最近遇到了一些问题 ， 想得到你们的指教 ，因为有个问题是偏计算机方面 ， 和字体没啥关系 ，不知道提出来是不是很合适 ，不过我觉得真鱼主播一定可以的 ，其实真鱼主播不可以 。

**蒸鱼** [24:46]
你咋不行 ？

**Eric** [24:48]
问题关于中西文混排时的高度 ，在一个 label 上展示文字时， 最终展示的高度如何确定 ？ 如果文字只有英文 ， 字号选择是 14 号字 ，在两倍视网膜屏幕上， 那么最后文字的高度不会超过 28pixel， 虽然它写的是 point， 我估计是个笔误 ， 这个高度应该等于深部线到降部线的高度 ， 如果文字只有中文 ， 那么类似 ， 最后文字的高度也不会超过 28pixel， 虽然中文不

一定有深部线和降部线 ，但是原理是类似的 ， 如果是中英混排 ， 最后文字的高度会是怎样呢 ？

我问了我们的设计师 ， 说是会比 28pixel 多出一到两个像素 ， 这是什么原因呢 ？ 是因为中文和英文的基线没有对齐吗 ？

希望可以得到主播的解答 。 问题二 ， 关于多语言字符串的 。

**Rio** [25:37]
先回答一个再讲吧 。

**Eric** [25:39]
这个我给他写了一个邮件去说明了一下其中一些问题 ，但是我觉得他对他们的设计师对整个渲染机制可能没有理解到 ， 所以说的完全不着调 。

我还是简单来说一下吧 ， 就是首先就是说 iOS 它维护了一套所谓的这个逻辑尺寸嘛 ， 就是逻辑布局的空间 ， 所以它的这个 point 换算成一个 pixel 的值 ，并不是一定 1:1、1:2、1:3 或者是 1: 几点几的 ，因为还有像 iPhone Plus 这样子奇葩的屏幕分辨率 ， 另外就是用户也可以调这个屏幕分辨率 ， 就一定是 。

**Rio** [26:19]
像那个什么 dynamic type 是吧 ？ 那个 。

**Eric** [26:21]
就是它可以调这个缩放吧 ， 就比如说你视力不好 。

**吴涛** [26:25]
缩放 。

**Eric** [26:25]
对对对 ， 所以你可以调这个 ， 所以这个具体几倍几倍其实是由操作系统来维护的 ， 那么你只能使用一个逻辑的这个 point 的这个值 ， 这个值是 iOS 给开发者使用的 ， 所以一个字符当它被那个设定成比如说 14point 的时候 ，其实简单来说我们用一个 typography unit 的概念来说 ， 我们就是将一个 em 的尺寸设成了 14 个 point， 那么究竟一个 em 的 glyph 它的显示的这个尺寸是多少个 point

或者是具体到多少个 pixel，其实完全是由字体来决定的 ， 你可以将一个 em 的 glyph 设计的只占一个像素那么大 ， 你也可以设计的超过一个 em 的方格的空间 ， 这都是没有问题的 ， 所以具体渲染成多少个像素或者多少个 point 完全是由这个字体来决定的 ， 就跟其他的没有任何关系 。

**吴涛** [27:20]
就好像你选 zapfinal，zapfinal 你选一个 14 号的 zapfinal， 最终渲染出来的一个单词可能会占 100 乘 200 这么大 ， 这都是有可能的 。

**Eric** [27:33]
对 ， 比如说它的 f 就会非常的高 ，有一个非常长的降步这样 。

**Rio** [27:38]
对 ， 然后他问那个问题其实我理解是不是之前也遇到过 ， 就是以前你们记不记得那个 macOS 的那个 text edit 那个程序 。

**吴涛** [27:47]
它会 。

**Rio** [27:49]
它的那个 。

**Eric** [27:49]
对 ， 它的那个中英文混排的时候那个行高是有问题的 ， 它不一致 ， 就不稳定 ， 应该是这个问题 。

**蒸鱼** [27:57]
这个问题当时好像 。

**Rio** [27:59]
我们也讲过好像 。

**蒸鱼** [28:00]
对对对 ， 它有个问题就是说当时的 text edit 好像是以整个文档的第一个字符的那个 font 来决定这个文档的行高是多少的 ，但是你在这个输入的这个 flag 的过程中， 就是这个 input flag 的过程中， 它好像又会动态的去调用当前这个 glyph 的 font 来计算当前这个光标所在位置的行高 ， 所以如果说你是一个多语言的 ， 对对对 ， 就会有跳动 ，但现在好像这个问题被

改善了吧 ， 它会预设一个比较大的 。

**吴涛** [28:31]
是没有进行修复吧 ， 我最近好像没有注意到这个问题了 ， 就再没出现过了 。

**Rio** [28:36]
对 ， 已经修复了 。

**Eric** [28:38]
那他问那个就中文和英文这个基线没有对齐这个事情是可能发生的吗 ？ 还是说没有这个事儿 ？

**吴涛** [28:45]
对 ， 这是盘面引擎来决定的 ， 就中文你可以说是要它的基线来跟 ，不对 ，是用中文字框的底线和英文的基线对齐 ， 还是用中文线框的底线和英文线框的底线对齐 ， 还是用中文线框的上顶端和那个英文的就是上升部的顶端对齐 ， 这有很多种 。

**Rio** [29:12]
所以这几种有什么 ， 就是我听出这个区别了 ， 就是说我们日常采取的一般是哪种方式呢 ？

**吴涛** [29:18]
一般是基线对底线吧 ， 我理解 。

**Eric** [29:20]
不是 。

**蒸鱼** [29:21]
一般是基线对基线 。

**Eric** [29:23]
对 ， 就是说在正常的哪怕是中文或者汉字的字体设计里面 ， 现在呢就是真正的 font 们也会画一个基线 ， 虽然说基线也是给西文设计的 ，但是呢就是说中文设计首先是有个字框嘛 ，但是现代的字体都会在字框上面再补一个基线 ，因为不管怎么样 ， 操作系统的话都是以基线来对齐的 ， 现在无论是 font，是很多排版引擎 ， 还有很多 web 都是这样 ， 它

只去调用这个一个 font 里面的基线 ， 所以呢它即使是中文字体它也会设成一个基线 ， 然后在很多的中文日文字体 ， 比如说大家会默认哈 ， 中文的方框是那个字框是 1000×1000 嘛 ， 的一个正方形的话 ， 一般来讲会把这个基线放在 120 左右 ， 就是底下 120， 上面 880， 就是放在这样的一个位置 ， 然后呢排版引擎的话不管你是中文还是西文 ， 它都会去调用你这个 font

里面 metrics 里面的这个基线的位置 ， 它是按基线对齐的 ， 无论你这个是阿拉伯文还是印度的天成文还是中文的汉字 ， 它们都有一个基线的值 。

**吴涛** [30:36]
哎 ， 所以那个印度天成 ， 就是天成文的那个基线在哪儿 ？ 是在靠下的位置还是 ？

**Eric** [30:43]
天成文它本身的基线它是汉音 ， 它是挂在上面的 。

**吴涛** [30:47]
对 。

**Eric** [30:47]
但是呢它 ， 嗯 ，但是它为了混排的话 ， 它也有 ， 它也在事先 ， 字体设计师要设一个基线 ， 虽然它不用 。

**吴涛** [30:56]
这名字叫什么呢 ？ 是叫 baseline 还是叫 。

**Eric** [30:58]
就是叫 baseline， 就是叫 baseline。

**吴涛** [30:59]
然后呢它本身的那条 hongline 叫什么 ？ 叫 hongline 吗 ？ 还是 。

**Eric** [31:04]
那个有天成文它们自己的名字 ， 对 。

**吴涛** [31:06]
OK。

**蒸鱼** [31:06]
对 ， 就是 。

**Rio** [31:07]
这个得问两个 。

**蒸鱼** [31:08]
OpenType 里面有一个 table 就叫 base 嘛 ， 就是 base 这个 table 就是描述的你这条 baseline 的位置在这个原始坐标 00 跟它相对的这个位置在哪里 ，其实它默认就在 00 这个位置上了 ， 那么那个你在设一个中文字体的时候呢 ， 你可以将你的这个起点比如说设在 0 负多少多少 ， 比如说 -120， 这个是 Adobe 常用的一个数值 ， 那么 monotype 可能会有什么 -110 之类的 ， 就每个字体厂商他们都会有它自己

的 convention 来做这个事情 。

**Eric** [31:39]
所以呢其实这个就是一个普通的字体文件里面它 metrics， 我们叫度量或者量度 ， 它的一个设置 ， 就字体设计师必须要设置的 ， 然后再由排版引擎去调用 。

**吴涛** [31:52]
OK。

**Rio** [31:53]
所以就其实不会出现这个中英文 ，他问的这个中文和英文基线没对齐的情况 ， 对吧 ？

**吴涛** [31:59]
这个好像还是可以改的吧 ， 就是比如说像我说的 ， 你可以强行说在这个排版的时候 ， 或者说在这个 label 里面让所有字符底端对齐 ， 这个还是可以做到的 。

**Rio** [32:12]
可以的 。

**吴涛** [32:13]
就如果你强行要这么设的话 ， 还是可能的 。

**Rio** [32:16]
因为像那个 CSS 里面就是有这个一个基线对齐的概念嘛 ，但是它应该没有区分这个多语言文本 ， 它是整个和那个图片的对齐 ， 那想来如果一个比较高级的排版引擎应该也是可以允许做这种比较非标准的操作吧 。

**Eric** [32:33]
如果是印刷方面的话 ， 比如说 InDesign 的话 ， 这个特别尤其是中西文混排的时候 ， 比如在做复合字体的时候 ， 就可以做基线偏移 ，而且呢在更广的范围来讲呢 ， 比如说把一个数字做成上标或者下标 ， 这其实也是一种基线偏移 ， 就是在不同的环境下不同的排版引擎都是有这样的功能的 。

那具体在 CSS 的话是另外的事情吧 ， 对吧 ？

**蒸鱼** [33:02]
对 ，CSS 它是这样的 ， 就是它的机制比较麻烦 ， 它有一个所谓的 linebox 和这个 inlinebox 的概念 ， 所以就是当它 。

**Rio** [33:12]
要换到格子里吗 ？

**蒸鱼** [33:13]
对 ， 它会把一个行内的一小段字符串计算它一个很小的一个矩形 ， 然后矩形的这个高度会有一个高度 ， 然后基线会在这个矩形内部的一个相对位置里面 ， 然后这个时候 CSS 的那个 vertical align 这个属性 ， 这个 property 里面设了几种值 ， 就会来决定这个基线之间相互对齐的关系 ，但这个 vertical align 的这个属性非常的不直观 ， 就这是我觉得这是 CSS 设计的一个缺陷吧 ， 就是对

于入门者来说你很难去直观的感受到你做了哪些对齐 ，因为你有的时候选 middle 对齐的时候 ， 你发现它其实并不是你预期的那种 middle 的方式 ， 它是以它定义的那种 middle 的方式 ， 然后 baseline 是默认的一种对齐方式 。

**吴涛** [33:59]
对 。

**Eric** [33:59]
这个还和字体有关系吧 ？

**蒸鱼** [34:02]
CSS 它会比较简单 ， 它会对一段文字使用同一种字体的这个参数来计算这个 linebox 的高度的这样一个属性 ， 对 ，但是这个 linebox 的高度它算起来就不是很准 ， 它也不是在所有地方都很准的 。

**Eric** [34:22]
而且它首先它会调用 ， 就是因为如果你是调用一个中文字体的话 ， 中文字体内部也有西文嘛 ， 就首先它会调用一个字体设计师他本身设定好的就是中西文的那个基线 ， 就这个 ，因为这个你调用的字体 font 本身是有这个信息的 ， 然后它要拿到这个信息以后再这个信息再继续调整嘛 。

**蒸鱼** [34:45]
对 ，但 CSS 有个问题就是说它在计算一个 linebox 的这个高度的时候 ， 它默认是按 CSS 设定的那个 line height 的那个数值来计算的 ， 对 ，但这个 line height 的值未必跟字体设计师定义的那个默认的 line height 是一样的 ， 所以这个时候基线应该放在什么位置其实是有一点问题的 ，有的时候是会出 bug 的 。

**Eric** [35:09]
Line height 的话就是我们说中文就是行高嘛 ， 那大家也知道 CSS 里面行高的话它是要把行间距除以 2， 一半放上面一半放下面 。

**蒸鱼** [35:21]
对对对 。

**Eric** [35:22]
那个盒子的 ， 对 ， 所以这个盒子是怎么算的是比较麻烦的一件事情 。

**蒸鱼** [35:28]
对 ， 特别是你多种字体混合组合的时候会有些问题 。

**Eric** [35:33]
不同字体而且是不同字号的时候会非常麻烦 。

**蒸鱼** [35:37]
啊 ， 对 。

**Rio** [35:40]
OK，他还问了第二个问题哈 ，是关于这个多语言字符串 。

### 排序规则

**蒸鱼** [35:45]
关于多语言字符串的排序和索引 。

**Eric** [35:47]
这个要讲吗 ？

**蒸鱼** [35:49]
这个问题跟今天我们要说的有点关系 。

**Eric** [35:52]
有点关系或者说 。

**吴涛** [35:53]
有关系吧 。

**Eric** [35:55]
要不我们等到后面专门一起来讲的排序 ，因为 。

**蒸鱼** [35:58]
对 ， 要不我们就先念一下他这个邮件吧 ， 就答不答再说了 。 如今是多语言国际化的时代 ， 多语言字符串排序和索引的规则是什么呢 ？iPhone 通讯录中姓名的排序规则是什么呢 ？

对于整个问题我自己也做了一些研究 ， 大致是 Unicode 给出了一套规则 ， 根据这个规则来实现就好了 ，但是 Unicode 的文档卷纸好烦吗 ？

卷纸 ， 我实在无能为力 。

**吴涛** [36:26]
卷纸好烦吗是吗 ？

**蒸鱼** [36:27]
卷意 。

**Rio** [36:28]
这是卷纸吗 ？

**蒸鱼** [36:30]
就纸吧 。

**吴涛** [36:32]
纸 。

**蒸鱼** [36:32]
对 ， 卷纸 ， 卷纸好烦 。

**吴涛** [36:34]
卷纸好烦 。

**Rio** [36:36]
收尾题目暴露了自己的文化修养 。

**蒸鱼** [36:38]
对 ， 深调念错了 ， 我实在无能为力 ， 完全搞不懂 ， 我自己总结了一点东西 ， 写了三篇文章放在博客上， 希望可以得到两位主播的指点 ， 同时我自己也有一点问题没有搞明白 。

第一 ， 索引时指定的排序规则是什么呢 ？ 似乎是按照拼音 ，但是中文和英文交织并不一定中文 ，并不是中文一定在英文前面或者后面 ， 怎样得到每一个汉字的读音呢 ？

在指定汉字顺序的

zh dot xml 这是一个文件 ， 汉字的读音在井号之后似乎是被注释掉了 ， 那么怎么知道汉字的读音呢 ？

具体来说 ， 左边的读音是左边 ， 它写的是一个拼音的左边 ，是怎么被确定的呢 ？ 这个问题和字体排印没啥关系 ， 和你们做的 Unicode 串台节目有那么一点点关系 ， 所以希望可以得到解答 ， 这个问题已经困扰我好久好久了 。

它应该是拿了一个什么 database 来做这个排序吧 。

**Rio** [37:37]
不 ， 这个事儿比较复杂 ， 那个 iPhone 的那个通讯录 ， 就 iOS 通讯录上面它有一个这个机制 ， 就可能很多 ，iPhone 上我不知道有没有办法添加 ，在 Mac 上是可以给那个联系人的名字加一个叫做 phonetic 那个 。

**蒸鱼** [37:51]
对 ， 就音 。

**吴涛** [37:51]
这也是我想说的 。

**蒸鱼** [37:52]
对 。

**吴涛** [37:53]
它有一个 phonetic， 还有一个另外一个注音 ， 就除了 phonetic 之外还有另外一个注音 ， 我忘了叫什么了 ， 暂时 。 然后这两个可以拿来做排序的依据 ，但是排序的时候的那个 ， 比如说你用中文 ， 就是你把系统设成中文的时候 ， 排序规则跟设成英文的时候排序规则是不一样的 。

**Eric** [38:19]
哪怕你设成中文也可以用不同的排序 ， 比如如果大家用 Mac 的话 ， 打开那个系统偏好设置的语言地区那边 ， 就专门有一个列表排列顺序的一个设置 ， 然后中文默认是拼音顺序 ，但是中文你也可以用 ， 比如说你用笔画顺序也可以 ， 用 GB 的那个内码的顺序也可以 。

**吴涛** [38:42]
对 ，但是在手机上面有这个设置吗 ？

**Rio** [38:46]
跟你的语言环境有点关系 。

**吴涛** [38:49]
就我的理解是在用那个 ， 就比如说你在 Mac 上面可以说我的系统语言是英语 ，但是我的第三 preferred language 是中文 ， 与此同时那个我可以把那个 list salt order 设成中文的 ， 比如说笔画排序或者是注音排序 ，但是在 iPhone 上是没有这个设定的 ， 就是你不能说系统语言是中文 ， 系统语言是英文的同时你还可以指定中文的排序方式 ， 就是我以前在推上跟 ， 好像是跟金雷还是谁去

研究过这个问题 ， 就是他想说手机的系统是英文的同时还可以让通讯录按照中文的笔画顺序排列 ， 好像是 ，但后来发现这个其实是做不到的 ， 就是当时我产生的一个状态是我先把手机设成中文 ， 然后发现通讯录被用中文 iOS 的默认通讯录排序是什么来着 ，是注音还是 。

**蒸鱼** [39:52]
拼音吧 。

**Eric** [39:53]
应该是拼音 。

**蒸鱼** [39:54]
OK。

**Eric** [39:54]
拼音 ，是的 。

**蒸鱼** [39:55]
然后当我切换回英文系统的时候 ， 这个排序是得以保留的 ，但是只要我往里面新加一个通讯录的 ， 只要我往里面新加一个联络人， 整个排序就又变成了英文排序 ， 然后所有的中文会被集中堆在后面 ， 除非你设定了那个 phonetic spelling， 就 pronunciation， 它才会在英文的部分出现 。

**Rio** [40:22]
我的情况哈 ， 我的 iPhone 是设置成日文状态的 ， 然后呢 ， 所以我打开我的那个通讯录的时候呢 ，因为日文状态它会默认用那首先日文排序嘛 ， 首先右边那个 index， 右边不是一个快速的可以转播那个 index 吗 ？

如果是这样的话 ，在日文状态的话 ， 首先它会有日文的 akasatana 的顺序 ， 然后后面还有 26 个字母的顺序 ， 所以呢 ，在这样的状态 ， 日文和那个英文首先是分开的 ， 然后呢 ，因为我系统默认是日文 ， 所以首先呢 ， 汉字呢是按照那个日文顺序排的 ， 然后如果我当然我这里面有中国朋友 ， 我中国朋友如果我不加注音的话 ，他的中文汉字的是所有是堆

在底下的 ，但是呢我如果 。

**Eric** [41:08]
井号的那个 。

**Rio** [41:08]
对 ， 井号的 ， 对 ，但是呢如果我 ，因为这个注音这个词在日文是非常常见的 ，因为日本人的汉字如果你不加读音根本都不知道它怎么念 ， 所以一般来 ， 对 ， 它如果是开成日文以后， 它会默认首先把那个注音的那个 field 打开 ， 它会让你写 ， 中文的话可能有时候它默认不打开 ， 很多人都不知道有这样一个 field，在日文的话那个 field 默认是打开的 ， 你可以往

里面填那个你这个词怎么念 ， 然后呢 ， 我个人的做法是把这个中文的名字把它拼音写上去 ， 这样的话呢 ，在我的手机范围里面 ， 日本人就在假名那一堆 ， 然后中国人就按照拼音放在这个 alphabet 的这一堆 ， 我个人是这样区分的 。

**蒸鱼** [41:51]
哦 ， 还是这样好 。

**Rio** [41:52]
非常好啊 。

**Eric** [41:53]
但是很麻烦啊 ， 你要每一个字 。

**吴涛** [41:56]
这是一个非常蛋疼的事情 ， 对 。

**Rio** [41:58]
对 ， 所以在那个 Mac 上面 ， 就是我们的朋友 ， 就是江江 ，他之前写过一个小软件 ， 就是自动给那个通讯录里面的中文名字的人标注他的那个 phonetic names， 就是 phonetic 的姓和名 ， 就这样的话他就可以在英文环境下还可以按照那个读音来排序 。

**蒸鱼** [42:21]
对 ， 这件事比较适合脚本来做 。

**Rio** [42:23]
对对 ，但 iPhone 上好像就这个我不知道有人有没有 ， 应该也是可以的 ， 就是写 。

**Eric** [42:28]
你把数据导一下嘛 。

**Rio** [42:29]
对对 ，因为那个就是通讯录是可以访问的嘛 ， 通过 API 然后你把它改一下 ，但这里就会牵涉到他问的那个第二个问题 ， 就怎样得到一个汉字的读音 ，因为这个比较简单的逻辑是有一个那个对照表的 ， 就是汉字和它的那个拼音的对照表的 ， 这个是很多系统里面都自带的 ，但这个比较 tricky 的就是说有些字是那个多音字 ， 这个时候特别是在那个名字里面

， 它有些很多是非标 ， 没有就不太具备这个参考意义的 ， 比如说有些字的多音字你是可以通过这个上下文的语义来看出它是念哪个的嘛 ，但是在名字里面其实是一个非常 arbitrary 的一个事情 ， 比如说有一个朋友叫那个就是草字头一个下面东南西北的西字那个字 ，他可以念西也可以念倩对吧 ？

**蒸鱼** [43:15]
对 。

**Rio** [43:17]
在名字里面很多人都是把它念倩的对吧 ，但其实在他在选择的时候就把它念成念西 ， 这个时候你说你怎么办 ， 你没有办法 。

**蒸鱼** [43:27]
对 ， 这点还好 ， 另外有一个问题就是有些人的这个姓的同一个字的写法 ， 它甚至都有不一样的念法 。

**Rio** [43:37]
姓的话 ， 一般做姓的那个音会比较特殊的 。

**蒸鱼** [43:42]
就有一些会有白读嘛 ， 然后这个白读又会被这个当成一种传统 ， 比如说那个最我印象最深的就是有一个姓叫盖嘛 ， 你们知道吗 ， 就是盖子的盖 ， 盖叫天有一个 。

经济原因 。 对 ，但是这个姓其实它在念姓的时候 ， 一个比较规范的念法应该念葛 。

**Rio** [44:04]
对 ，但是很多人都觉得 。

**吴涛** [44:06]
普数吧 ， 普数这个普 。

**Eric** [44:08]
朴数 。

**蒸鱼** [44:09]
朴 。

**吴涛** [44:10]
它变成朴了 。

**Rio** [44:10]
对 ，不过它就是韩国人那个 。

**蒸鱼** [44:12]
应该是小众吧 ， 它应该是一个艺名之类的小众 ，但那个盖和葛的问题就是很多人他都希望自己被念成叫盖 ， 就是不要改成葛这个音 ，但是有一些人他可能祖上传下来一直都念葛 ， 所以他又希望这个字念葛 ， 所以这个字念什么音其实也是不一样的 。

**Rio** [44:31]
就是所以就是说刚才讲的那个问题 ， 就姓名里面这个读音是没有一个规则可以参考 ，因为很多是靠他自己自定的一个选择来怎么念的 ， 这个时候你就很非常尴尬 ，有些人就成心来添乱 。

**吴涛** [44:45]
对 ，而且这个问题其实并不仅仅是中文或者是在表意文字才有的 ， 就在英文或者说在拉丁语 ， 拉丁字符世界甚至是拼音字符世界也是有的 ， 比如说前阵子被韩国被

朝鲜弄死的那个美国人 ，他的名字叫做 Warmbier， 就是你如果你是一个美国人的话 ， 你念他的名字 ， 你会念成 Warmbier， 然后有一天 ，但是 Warm 和 Bier 这两个词其实就是地道的德语词 ， 包括这个人的整个的名字 ，他的名字叫什么来着 ，Otto Warmbier， 这一听就是一个德国后裔你知道吧 ， 就是那种感觉 ， 就好像这种感觉很奇怪 ， 就好像你是一个华人， 然后现在中国人已经是什么 ，

刨去我们这一代就是很多人都是双字名的 ， 现在的中国小孩都起什么艺轩啊 ， 紫萱啊 ， 什么这种非常又浓 ， 说不出来奇怪在哪 ，但是有点奇怪的名字 ， 然后忽然有一天你发现一个在美国出生的土生土长的华裔 ， 名字叫曾国藩或者左宗棠这种感觉 。

**Eric** [46:02]
非常古典是吧 。

**吴涛** [46:03]
对 ， 就是 Otto，他的中名是什么来着 ，Frederick， 对 ，Otto。

**Eric** [46:09]
奥托什么什么 。

**吴涛** [46:10]
奥托弗雷德里克 Warmbier， 对 ， 这样一个名字 ， 这个名字如果他是一个德国人的话 ， 那么他的名字会变成 Warmbier，但如果他是一个美国人的话 ， 包括德国人念他在广播里面念这个人的名字的时候都会念成 Warmbier， 就是按美语的发音来念 ， 所以这就是为什么刚才说到的那个在 iPhone 的联系人里面你可以给它添加两个

额外的项目 ， 一个叫做 pronunciation

spelling，pronunciation name， 另外一个叫做 phonetic name， 就是我记得这两个之中一个会被 Siri 拿来当做发音的依据 。

**Eric** [47:02]
对 。

**吴涛** [47:03]
对 ， 就比如说你 ， 比如说吴涛这两个字 ， 你可以在

phonetic name 里面写 W-U-T-A-O，但是在 pronunciation 里面你可以写 W-O-O dash T-A-U， 比如说 ， 然后 Siri 会试着用 Wu Tao 这个方法来念这个名字 。

**Rio** [47:31]
Pronunciation 就纯粹是给那个语音生成那个合成器用的是吧 ？

**吴涛** [47:35]
对 ， 我是这么理解的 ，但当然我从来没有用过 ，但我相信用过的人应该可以知道 ， 比如说你可以

用这个功能来告诉 Siri 说打电话给谁谁谁 ， 实现这样一个功能 。

**Eric** [47:49]
还有一个更直接的办法就是 Siri 的话你可以直接语音告诉它把这个字念成什么 。

**吴涛** [47:55]
你可以教它念成什么 ， 对 。

**Eric** [47:56]
对 。

**蒸鱼** [47:58]
啊 ， 可以这样啊 。

**Eric** [48:00]
对 ， 所以呢 ， 就专门有这样的一个 field 是给语音合成器来教它念读音的这样一个 field， 对 。

**Rio** [48:07]
这个 field 好像只有这个 iOS 上才有 ，Mac 上是没有这个 field， 我刚刚检查了一遍 ， 对 ，因为 Mac 上之前没有 Siri 嘛 ， 所以估计没做 ，但现在 Mac 上也有 Siri 了 。

**Eric** [48:17]
现在有了 。

**Rio** [48:18]
怎么办 ？ 但是那个在那个 contact 就是通讯录的那个添加那个 ， 那个叫什么来着 ， 那个 field 那个里面是没有那个字段的 ， 没有 pronunciation。

**吴涛** [48:31]
只有 phonetic， 对 ， 应该只有 phonetic。

**Rio** [48:33]
但是还没更新到那里来 。

**Eric** [48:36]
Anyway， 这个邮件里面其实还提了一个非常重要的事 ， 就是说其实我理解啊 ， 就是说在这种多语言的时候怎么排序 ， 比如刚才我们提到的这个日文环境和这个德语环境的时候 ， 它都是有这个区别的 ， 你没有想过这个问题 ， 如果一个人他精通多国语言 ， 比如说他会这个日语 ， 然后韩语 ， 然后会这个什么阿拉伯语 ， 对吧 ， 然后他还都有讲

这种语种的 ， 或者是这个名字的这个朋友 ，他的通讯录怎么办 ？

**蒸鱼** [49:07]
不过我们觉得应该把这件事情啊要分好多层次来说 ， 别讲得乱七八糟 ， 首先是有一个代码层面的问题 ， 对不对 ？

然后呢 。

**Rio** [49:19]
因为你可以分成一个顺序的嘛 。

**蒸鱼** [49:21]
对 ， 然后呢 ， 首先有操作系统层面的问题 ， 然后还有 App 层面的问题 ， 对 ， 这几个层面都会影响到你最后看起来的最后的排序是怎么样的 。

**Rio** [49:34]
对 ，因为后来想了一下 ，其实这种在多种语种 ， 特别是多语种混合环境下， 就是还不是说一个系列 ， 比如拉丁语系还相对来说可以兼容嘛 ， 像刚才讲的那种情况下 ，其实还跟你的这个叫做什么来着 ， 政治策略有关系 。

**蒸鱼** [49:50]
政治正确 ， 对 。

**Rio** [49:51]
对对 ， 你说要把这个某种语言的这个 ， 虽然说 Unicode 里面有一个顺序 ，但是如果你在某一种环境下你把一种语言的名字排在前面 ， 另一种排在后面 ，其实多多少少会有一些这个的考量在里面 ， 所以其实挺复杂的一个问题的 。

**Eric** [50:10]
那不管怎么样 ， 我们刚才从这个层面来讲的话 ，在操作系统层面 ， 比如说 iOS 和 MacOS 就不一样 ， 对吧 ， 针对一个语言的话 ，因为 iOS 它是移动的系统 ， 所以呢 ， 它的一个语言它只有一个默认的排序 ，但是 MacOS 上面呢 ， 你一个语言你可以选好多个排序 ， 你是可以选的 ， 然后呢 ，在操作系统层面 ， 像刚才我们说的很最典型的有很多需要这个通讯录 ， 它是可以再另外加

一个 field 的 ， 还有一个很典型的是 iTunes，iTunes 它各种歌曲的名字 ，因为那个曲名也有各国的曲名。 对 ， 然后呢 ， 它在 MP3 的或者你在一个音乐的那一个就是 metadata 里面 ， 你可以再继续把这个名字 ， 像刚才人的名字一样 ， 把个歌曲的名字也是给它注音注进去也是可以的 。

**Rio** [51:10]
这个比较鸡贼啊 ， 它其实做的不是注音 ， 它直接给了一个选项叫做 sort order 嘛 ， 就是排序的这个顺序 。

**Eric** [51:16]
排序 。

**Rio** [51:17]
对 ， 它完全不管 。

**Eric** [51:19]
对 ，但是它至少就是它有一个 metadata 可以写嘛 ， 你往那里面写的话 ， 然后 iTunes 就会去读那个 field 嘛 ， 对吧 ，是 iTunes 它给提供了这样一个可能嘛 ， 就专门为了排序它提供了它做了这样一个功能嘛 ， 所以像这样的功能是 application 层面给它设计出来然后给它做的嘛 ， 对吧 ？

**蒸鱼** [51:39]
对 。

**Eric** [51:41]
如果你不在那边做的话 ， 它会默认先去调用系统的顺序嘛 ， 对吧 ， 它有个 fallback 的顺序 ， 对吧 ？ 所以然后如果系统也没事的话 ， 那它直接就去读内码的顺序了 ， 对吧 ，有 Unicode 它默认的 ， 它那个真正的那个内码是什么顺序 。

**Rio** [52:03]
所以你看这个现代软件里面多少复杂性 ， 就是有这些原因导致的 。

**Eric** [52:12]
好吧 ， 那我们今天终于可以讲正题了吗 ？

### 规范化入门

**吴涛** [52:15]
今天还有正题啊 。

**蒸鱼** [52:18]
今天还有正题啊 。

**Eric** [52:19]
今天我们要讲一个非常 hardcore 的正题 。 就是很多人都没有意识到这个问题的存在 ， 今天我们要讲的是 Unicode 的规范化形式叫 normalization。

很多人都讲 normalization 是什么东西 ？

**吴涛** [52:35]
你来自问自答一下好了 。

**Eric** [52:37]
它有中文的标准译法吗 ？ 或者我们有没有什么推荐译法 ？

**蒸鱼** [52:43]
因为 Unicode 它就是国际标准 ISO 嘛 ， 那 ISO 它又是各国的都会写到各国的

国家标准里面 ， 那么中国的国标就是 ISO， 那就是中国国标是 13000， 然后它对这个 normalization 的翻译是叫规范化 ， 那我们在今天节目里面就叫规范化吧 ， 要不然挺乱的 。

**Eric** [53:10]
OK。

**蒸鱼** [53:12]
然后很多朋友就不知道还有一个规范化的东西 ，其实很简单 ， 就是你看到的比如说带声调的字符 ， 比如说拼音啊啊啊啊那个 ， 比如说那个 R， 对吧 ，是字母 A 上面加个所谓的第二声 ， 对吧 ， 你看到的是这样一个字形 ， 可是它的背后可能是一个编码 ， 或者它也可能是两个字符 ， 两个编码 ，也就是说一个字母 A 的编码加上一个带声调的这个编码组合

而成的一个东西 。

**吴涛** [53:47]
对 。

**蒸鱼** [53:47]
其实就是本质上 Unicode 有一个现象 ， 就是说当我们看到一串 Unicode 的码位的组合的时候 ， 它们可能在码位上是不同的 ，但它们实际上表示的这个字符或者是字符串是相等的 ， 就 Unicode 有这样一个所谓的等 ， 对 ，有一个等价性的这样一个东西 。

**吴涛** [54:10]
主要是这主要还是一个

本质上还是个历史的遗留问题 ， 它如果当初不是一定要兼容那个 ASCII 的低位的话 ， 就不会有这个问题 ， 我是这么理解的 。

**Eric** [54:24]
但是而且现在是由于 Unicode 是多语言的嘛 ， 那各个语言也都会有这样一个问题 ， 所以这个规范化就越搞越烦 ， 然后这个东西的话 ，有时候呢 ， 你要给它看成是一个字 ，因为比如要看成两个字 ，因为这有时候必须区别嘛 ， 就是带声调的和不带声调的肯定是两个字嘛 ，不一样 ， 你不能给它混在一起 ，但是呢 ，有时候呢 ， 你又要给它混在一起 ， 比

如说在搜索的时候 ， 你在搜索的时候你可能希望就是说你只打一个字母 A，但是你能顺带你能把这些带声调的东西能一起搜索到 ， 就是能在你那个候选下能出来 ， 所以这个时候呢 ， 你又希望模糊的把这些全部带 ， 所以呢 ， 这个是有这样的需求的 ， 就是有时候你需要区别 ，有时候呢 ， 你又不想不区别 。

**Rio** [55:13]
就是这里有个问题就是为什么要同一个码位要对应两个 ， 就最开始它产生的原因是什么 ， 刚才那个吴涛提了一个解释 ，但是 。

**吴涛** [55:23]
不是 ，是反过来 ，是反过来 ，是同一个字符会有多个码位 ，而不是同一个码位会对应两个字符 。

**Rio** [55:31]
那就是为什么会出现这种情况 ， 就是它的历史背景是什么 ？

**吴涛** [55:35]
最简单的一个 ， 比如说当时欧洲各自都

使用很多带有那个扩展符号的拉丁字符嘛 ， 所以当时 ASCII 的那个高位就被拿来做扩展 ， 然后最常见的就是 Windows 上那个叫什么 CP1252 还是哪一个 ？

**Eric** [55:59]
代码页 。

**吴涛** [56:00]
对 ，Windows 直到今天都是在使用代码页这套机制 ， 这套非常坑爹的机制 ， 所以这是一个就是不能忽视的历史问题 ， 所以 Unicode 一开始在做的时候 ， 它的我记得是低位的完全兼容 ASCII， 然后此时就出现了一个问题 ， 就是比如说 u 上面加两点这个字符 ， 那它就有可能出现 ， 它就等于在 Unicode 里面出现了两种组合的可能 ， 一种是因为 Unicode 兼容它固有的那个表达方式 ，

就是

u 这个字符是在哪个码位上， 然后它会它直接把那个码位就做进了 Unicode 里面 ， 说在这个码位上面 ，Unicode 这个码位上面 ， 这里就是 u 上面加两点 ，但与此同时它又给出了单独的一个 u 和单独一个两点 ， 于是此时你就又可以用说我要一个 u 然后上面加两点来做出这个字符来 。

**Rio** [57:02]
这个就是问题嘛 ， 就是为什么会有这种组合的需求存在 ， 如果说我提个比较极端的情况 ， 就如果说我们把所有的组合都是就组合后的字都变成一个独立的码位 ， 就不存在这个问题了嘛 。

**吴涛** [57:18]
因为首先一方面这是它比较节省空间 ， 另外一个就是你如果你要组合的话 ， 你是组合不穷尽的 ， 尤其是比如说有些组合一方面有些组合可能完全没有意义 ， 另外一方面比如说像越南语 ， 就是一个字符上面可能有四五个 ， 四五个可能太夸张了 ， 三个应该是有可能 。

**Eric** [57:40]
三个也可以 。

**吴涛** [57:41]
对 ， 三个标音符号 ， 然后你要把所有的 combination 都弄出来的话 ， 这对于空间其实是很大的浪费 。

**Eric** [57:49]
给大家一个比较更直观的一个例子哈 ， 比如说

汉语拼音那个 u 上有两点是 ü 嘛 ， 对吧 ， 然后 ü 也可以带声调嘛 ，ü、ü、ü、ü 嘛 ， 所以呢 ， 比如说鱼 ， 对吧 ， 那你因为单纯你就可以看着 u 上面加两点再加那个第二声 ， 这其实是这到底是一个字还是三个字 ？

**吴涛** [58:13]
这个例子举的不对啊 ， 鱼应该那个 yu 的时候 。

**Eric** [58:19]
我不说那个单音节 ， 我不说单音节的情况 ， 我不说那个汉语拼音那个音节情况 ， 我单纯说这个字符 。

**吴涛** [58:27]
对 ，OK。 比如说绿色的绿 ， 对 ， 你加了一个声调 ， 然后这此时这个双点和下降调都是存在的 。

**Rio** [58:38]
就是为了这个 ， 就是我们组合成部件 ， 然后通过一个固定的方法来组合 ， 避免去存多种变种嘛 。

**吴涛** [58:48]
对 ， 一个是这个 ， 另外一方面就是比如说像韩语 ， 韩语那个字母的把几个字母拼在一起的这一套合成机制跟那个在字母上面加点的合成机制实际上是同一套 ， 那么你如果你要把这一套 ， 比如说我要完全摒弃这一套 ， 然后把所有的 combination 全都做出来的话 ， 那韩语的 combination 那就是横河沙数啊 ， 一个 player 不要再多了 。

**蒸鱼** [59:16]
那它曾经就做过嘛 ， 对吧 ？

**Rio** [59:17]
曾经就可以导致什么 UTF-16 就不够用了是吧 ？

**吴涛** [59:21]
对 。

**蒸鱼** [59:22]
我记得微软好像为了这事情就 hack 过这个事情嘛 ， 还把 Unicode 标准给 hack 了 ， 所以 Unicode 标准在韩语有坑嘛 。

**Eric** [59:32]
还特别乱 ， 对 ， 特别乱 。 没有 ， 首先是这样子的 ， 就是说如果大家觉得要省编码的话 ， 就是说像就不用组合 ， 对吧 ， 就给它当你就给它当成是一个东西的话 ， 这会在不同语言里面会有不同的这个认知 ， 比如说在德语里面 u 上加两点它就是一个字母 ， 它对于普通的德文的母语者来讲它是一个字母 ， 它没有这种组合的感觉 ， 就是像比如说

在法语里面它底下有个 c 底下可以加个软音符 ， 就是然后像这样的对于说法语的人来讲这是一个字母 ，而不会说是什么 c 加一个符号 ， 所以在历史上 ，而且在历史上呢 ， 就各国因为它自行的对 ASCII 进行扩充 ， 所以在它也有个向后兼容的一个需要 ， 所以它必须有这样就当成一个字母的这样的一个需求 ， 然后又有想分开的需求 ， 就是因为你有时候会加的不

穷尽嘛 ， 还是说有这种单独就这个第二声的这样的一个东西 ， 或者两点这样的东西 ， 这样的你可以自由的往其他的字母上面加 ， 这样明显是更灵活的嘛 ， 虽然很灵活 ，但是你就浪费了码位 ， 就变成原来一个字符就可以搞定的东西现在就变成两个字符了 ， 然后现在的历史结果就变成有的时候要一个字符 ，有的时候要两个字符 ， 然后又有向后兼容性

， 那没办法 ， 那就大家统一起来 Unicode 就搞得这样出一个这样一个 normalization， 就是所谓的规范化的一个形式 。

**蒸鱼** [1:01:12]
对 ，而且其实我们刚刚一直在讲这个组合的问题 ， 然后事实上 Unicode 的这个等价性问题或者说 normalization 问题 ， 它不仅仅要解决组合的问题 ， 它要解决的是两个字符之间它们虽然码位是不同的 ， 它们各自也只有一个码位的时候 ， 它们也有可能是等价的 ， 比如举一个例子就是 omega 和这个单位欧姆之间 ， 它们其实各有一个码位 ，但它们其实本质上是完全

是同一个字符 ， 那么它们有的时候也需要一种等价的处理方式 。

**Rio** [1:01:45]
对 ， 这就是那个认知的问题嘛 ， 就是我们人类在说我看见这个符号的时候我想的是哪一个东西 。

**蒸鱼** [1:01:54]
对对对 ， 另外还有像日语的一些遗留问题 ， 比如说日语有半角和全角的问题啊这样子 。

**Eric** [1:02:01]
对 ， 日语就坑多了 ，因为大家也知道比如说像日文普通的五十音图里面 kakigakeiko 加上两点就会变成浊音 ， 就变成 kakigakeiko 嘛 ， 所以呢 ， 首先它就会有这种就所谓的加点这种组合的问题 ， 比如说 ka 如果是 ga 的话 ， 它可能是一个字 ga，也可能是 ka 加上两点变成的 ga， 首先就是有刚才说的这个组合问题 ， 然后呢 ，也有刚才那个字形不同的问题 ， 就因为要有那

个等价关系 ， 一个 ka 的话它可能可以是半角的 ，也可以是全角的 ， 半角的片假名也是因为历史上有这个 ASCII 日本人自己扩展的问题 ， 所以它必须有个向后兼容性 ， 它要保持这个半角片假名 ， 就以前发电报时候用的 ， 所以这也是一个向后兼容留下来的一个坑 。

**吴涛** [1:03:00]
对 ， 基本上就是当年跑步进入新兴时代的这些国家各自为战 ， 然后

才导致了今天才导致了今天有什么 ISO8859 啊或者是 JS 的 standard 啊 ， 然后 Unicode 不得不捏着鼻子把这些历史遗留的问题全都收进来 ， 所以才会有这样的问题 ， 就如果我们今天能够把人类社会推倒重来 ， 然后把信息技术从头再来的话 ， 那很多东西都会不一样 ，ASCII 也是 ， 就是编码也是里面的一个 。

**Rio** [1:03:34]
所以这个规范化解决的问题其实就是说看就是它是一个可以理解为它是一个查找的一个表 ， 然后通过这个表可以找到说哪些 Unicode 的这种一个 Unicode 字符串它两个的意义其实是等价的 ， 它解决这么一个问题 。

**Eric** [1:03:55]
所以大家去看 Unicode 的话呢 ， 就专门它有个标准附录 ， 那 Normalization 呢是在标准附录的第 15 号里面呢会有就是具体的这个组合是等于什么什么的 ， 它有这个机制的介绍和各个语言的所有 Unicode 里面带的 Normalization 的它一个表格 chart 都有 ， 然后呢如果大家去看呢会发现各个语言都有很奇怪的各种等价 。

**吴涛** [1:04:20]
对 ，其实我记得以前前一阵子 Swift 的语言 ， 当然这个比较这个部分可能比较内核恐慌 ， 就是 Swift 的语言在好像在上一版里面又改变了字符串的那个表达方法 ， 字符串现在又是一个 collection 了 ， 然后并且它就是支持你直接 compare 两个字符串是否相等 ， 然后这个相等的依据就是它们的那个在做 Unicode Normalization 之后是不是相等 ， 比如说你这两个字符串可能在

byte 层面上是不一样的 ， 一个是一个的那个一个字符串里面的 u 上面加点可能是 ASCII 的那个码位 220， 另外一个可能是一个 u 加上两个点 ，但是如果你问在 Swift 里面问这两个字符串是不是相等的话 ，Swift 会说这两个字符串是相等的 。

**Rio** [1:05:17]
所以这就是我不太喜欢那个 Swift 的地方 ， 它老是把一些本来该交给这个 library 来做的事情放到这个 language 这层面来搞 ， 就搞得很乱 。

**蒸鱼** [1:05:29]
对 ， 它没有某一种选项机制吗 ， 就是什么情况下我要认为它们是相等的 ， 什么情况下认为它们是不相等的 。其实现在是有的 ， 就是现在

的思路就是如果你把它当做一个

string 来处理的话 ， 那么它默认是个 Unicode string， 然后我刚才说的这个就是它们在 Normalization 之后相等就算相等 ，而如果你要一定要比较它们在 byte 层面上的大小的话 ， 你需要取出它们的我想想是 charset 吧 ， 还是就是你可以把它们转换为另外一种形式来比较 ， 然后这样的话再比较就不相等。

### 形式与系统

**Eric** [1:06:13]
好吧 ， 那看来这个 Normalization 是很必要的 ， 那我们再就给大家介绍各种不同的 Normalization 规范化 ， 这是另外一个坑 ， 就大家都来做规范化就好了嘛 ， 同样规范化就大家都按同样的规范化来做这个事情也没什么 。

**吴涛** [1:06:29]
方法还不一样 。

**Eric** [1:06:31]
对 ， 这个坑 ， 哎呀真是的 。

**Rio** [1:06:33]
我们需要一个 Meta Normalization。

**蒸鱼** [1:06:37]
其实这里有我觉得有两个层面吧 ， 就是首先就是我们刚才说了这个规范化它要解决的是两个 Unicode 的串它是不是等价这样一个问题 ， 那么这个等价其实是有多种意义的 ， 或者说有多种用途的 ，有的时候我们希望这个等价是一个相对来说比较严格的等价 ， 它们只是我们对一种字符的分解方式或者组合方式的认知不同 ， 那么有的时候我们可能

对这个等价要求是比较宽松的 ， 它们可能是一种更宽松的语义层面的等价 ，因为我们有这个搜索的需求对吧 。

**Eric** [1:07:13]
所以呢 ， 等价就是所谓的规范化呢 ， 它有两大类 ， 然后每个大类里面又有两小类 ， 所以一共有四种 ，

两大类就是标准等价和这个兼容性的等价 ， 刚才说兼容就是为了大家能比如说为了搜索能找到嘛 ， 所以它有个向后兼容的需求 ， 那兼容的话它有两种 ， 那标准的规范化呢有两种 ， 那一种呢就是叫什么 D 型 ，有 C 型 D 型 ，C 型那个叫什么 ， 先分解后合成是吧 。

**吴涛** [1:07:51]
对 ， 先 decomposite 然后再 composite。

**Eric** [1:07:57]
然后 D 型的话就是分解掉 ， 这个按着分解掉 ， 然后兼容分解两小类也是 ， 就是兼容的默认是分解的 ， 或者是兼容性的先分解后组合 ， 然后很坑的一点就是操作系统它又分别又采用了不同的方法 ， 所以呢这又跟操纵系统有关系 ， 那最近呢这个 Normalization 提上话题的话就有一个很有意思的一个时机 ， 就是因为刚好苹果要改文件系统了 。

**吴涛** [1:08:32]
OK， 上次 WWDC 出来的消息吧 。

**Eric** [1:08:36]
对 。

**吴涛** [1:08:37]
我们好像之前还提过了 。

**Rio** [1:08:40]
对 。

**蒸鱼** [1:08:40]
现在我们跑的 iOS 十点几来着 ？

**Eric** [1:08:45]
现在的十点三已经是新的系统了 。

**蒸鱼** [1:08:48]
对 ， 已经是 APFS 了 。

**Eric** [1:08:50]
对 ， 就 Apple File System 嘛 ， 你们知道为什么明明是 Apple File System， 那为什么要缩写成 APFS 嘛 ，而不是 AFS 嘛 。

**蒸鱼** [1:09:01]
AFS 被占了呀 。

**Eric** [1:09:04]
对 ， 原来因为有一个那个苹果文件服务嘛 ，Apple File Service。

**蒸鱼** [1:09:11]
刚说哪个版本的 Sierra 已经是 APFS 了 。

**Eric** [1:09:15]
下一个就是 。

**蒸鱼** [1:09:17]
High Sierra 才会是 。

**Eric** [1:09:18]
High Sierra 才是 ， 对 ，iOS 的话更快 ，iOS 在十点三就已经把这个文件改为了 APFS 了 ，而在之前也就是说现在的我们的 Mac 呢都是 HFS+， 这是一个超好老啊 ， 这个已经十几年， 多少 ？

**蒸鱼** [1:09:40]
八几年的 ， 八几年的文件系统 ， 快十年了 。

**Eric** [1:09:43]
对啊 ， 终于要苹果一咬牙一狠心要换 ， 把它给它换掉 ， 那换掉了以后呢就出现了一个问题 ， 就是在这个新的 APFS 里面呢 ， 它把这个原来的 Normalization 系统默认的 Normalization 呢给换掉了 ，因为新的 APFS 呢它是叫 Normalization 的 Insensitive， 它是不敏感的 ， 对这个规范化不敏感的 ， 所以就是说无论它可以到时候你就是它都能找到这个文件 ，因为刚才说了嘛 ， 它如果你如果对它不敏

感的话 ， 就更容易搜索到嘛 ， 就是无论你是用什么样的规范化来做的话 ， 它都能指向这个文件 ，以前呢会有坑的问题 ，而对于用日语的朋友来讲 ， 这个是最坑的问题 ， 我们在我刚才说了就因为日文经常要用会涉及到就踩到这个规范化的坑 ，是因为日文像刚才说的浊音点是经常用的嘛 ， 然后经常会出现在日文的 Windows 的文件名拷到

Mac 的时候 ， 刚才说凡是带有那个浊音点的字放到 Mac 里面就被拆成了两个字 ， 然后因为是两个字你还可以一个字删除 ， 所以你可以把那个浊音点分别删除

， 就是因为在老的 HFS+ 的时候呢 ， 这也就是 Mac 现在用的这个系统里面呢 ， 它对这个 Normalization 的处理是不一样的 ，因为它采用的是就分解优先 ， 所以它会把这个字拆成认成是两个字 。

**蒸鱼** [1:11:29]
这里可能要解释一下这个背景 ， 就是为什么从改了一个文件系统会导致这个 Normalization 的问题 ，因为 HFS+ 就是那个旧的那个文件系统是对这个有一个默认的一个处理的 ， 就是那个文件系统它其实是知道你写进去一个文件名 ， 它会帮你去自动做一遍这个 Normalization 是这样 ， 如果我没记错的话 ， 然后这个 APFS 其实就之前那个设计其实有点问题的 ，因为照理说一个文件系统不

应该去参乎这种应用层的事情 ， 对吧 ？ 因为这个因为 Normalization 的规范 。

**Eric** [1:12:06]
这显然是应用层的问题啊 ，因为文件系统应该就是啊这可能有一点 。

**蒸鱼** [1:12:12]
其实这里有个哲学问题 ， 就是这也是我一个疑问 ， 就是 Normalization 究竟是应该在这个存储的层面或者说在 。

**吴涛** [1:12:20]
层级上发明的对吧 ？

**蒸鱼** [1:12:22]
对 ， 还是在这个应用调用某一个数据的过程中对它进行实时的处理 。

**Eric** [1:12:27]
因为本质上你说对一个文件系统来说 ， 它并不关心里面存的内容是什么 ， 就是你给我一堆 byte 对吧 ， 然后我把这个 byte 按照某一种规则啊存进去 ， 然后到时候你再问我要这堆 byte 的时候 ， 我就把这堆 byte 又还给你 ，但是我需要一个 key 找到这个这堆 byte 嘛 ， 这个 key 就是这个所谓的这个文件名和路径嘛 ， 那么 APFS 最开始的它的那个逻辑我记得当时他

说过 ，他说对这个东西他是就是完全不过问这东西 ， 你给我什么 ， 你给我那个文件叫什么 ， 就我就写什么嘛 ，但是在 HFS 里面它其实是已经它会去解析那个文件名的那个格式和内容的 。

规范化这个事情是一个逻辑的概念 ， 它并不是它是我们在做这个叫做 API 的层面解决的问题 ，但是最终你写到那个磁盘上的那个东西的时候 ， 它肯定是一堆一堆 byte 嘛 ， 所以就是 APFS 它的这个设计理念就是我作为一个文件系统 ， 一个非常底层的东西 ， 我不应该去参乎上层逻辑 API 应该去解决的问题 。

**吴涛** [1:13:33]
不是 ，Rio 我明白你意思 ，Rio 我明白你意思 ，但是我有一个问题 ， 比如说你说文件系统是一个非常底层的系统 ， 那么请问获得一个文件的路径这件事情很底层对不对 ， 那么获得一个文件的路径跟这个文件的名字是以什么样的标准化形式写出来的有没有关联 ？

**蒸鱼** [1:13:59]
这个对我 。

**Eric** [1:14:00]
肯定有关联啊 。

**蒸鱼** [1:14:01]
不但这个不是文件系统 ， 就对这个文件系统没有关系 ，因为文件系统拿到最终都是一堆 byte 嘛 ， 它不需要去 concern 这件事情 。

**吴涛** [1:14:10]
其实它做了一次 。

**蒸鱼** [1:14:11]
先 。

**吴涛** [1:14:11]
Rio 的意思是说先规范化再存储这件事情不是在文件系统的层面上发生的 。

**Eric** [1:14:18]
对 ， 它是在一个他们叫什么 foundation 那个 。

**吴涛** [1:14:22]
对 ，在操作系统的层面上发生的 ， 或者在操作系统和文件系统就管理文件系统那一部分的 API 里面产生的 ，而不是文件系统本身需要操心的事情 。

**Eric** [1:14:33]
对 ，但这里就会导致一个问题 ， 就是它就向后不兼容了 ，因为在 HFS 里面它是就是文件系统确实管了这么一件事情的 ， 所以操作系统和包括很多应用程序它是不需要过度的去考虑这个问题 ， 你用什么 API 去访问那个文件 ， 反正你只要给了它 ， 它都会通过统一的方法规范化 ， 然后形成统一的一个那个 byte， 然后再去通过那个 byte 在文件系统里面去找嘛 ， 最后就

变成向后兼容的问题了 ，但这个问题之所以在这个 iOS 里面没有暴露出来 ，是因为 iOS 并没有起码对用户而言啊没有暴露出一个文件系统嘛 ， 起码到目前为止是没有的对吧 ， 那么也就不存在就并不会大量存在说有很多这个历史文件的名它的规范化形式不太对 ， 导致可能找不回来的一个问题 ，但是在 Mac 里面就会存在这个问题 ，因为 Mac 里面我们现在大量还在使用用户直接

访问文件系统嘛 ， 大家还是用 Finder 嘛对吧 ， 所以就导致这么一个很尴尬的情况 ， 所以现在都出的都是一些打补丁的方案嘛 。

**蒸鱼** [1:15:40]
这其实你一直用同样一个系统的话 ， 相对来讲会好一些 ， 那就只要是像跟和 Windows 像 Windows 因为它默认的那它规范化的方式不一样嘛 ， 所以从那边不同规范化的方式里拷过来的东西就会有问题 ， 你 Mac 一直都用这样的规范化形式的话 ， 它其实还相对来讲它的那个向后兼容性还是挺好的呀 。

**Eric** [1:16:06]
但是有一个问题是这样的哈 ， 就是说因为 APFS 如果按照最开始的那个设计理念是不涉及规范化和你怎么就你不它不涉及你的文件怎么编码 ， 你甚至可以不用 UTF-8 编码 ， 理论上是可以的对吧 。

**蒸鱼** [1:16:20]
APFS 只接受有效的 UTF-8 的编码的文件名。

**Eric** [1:16:24]
我就说就是说如果它就是刚才讲如果它只管是 byte 的话 。

**吴涛** [1:16:28]
就它只在字节层面上说你给我什么我就存什么 。

**Eric** [1:16:32]
对对对 ， 存什么啊 。

**蒸鱼** [1:16:33]
就会有 。

**Eric** [1:16:34]
文件系统嘛 。

**蒸鱼** [1:16:35]
对 ， 就是刚才那个问题就是说假设我们用那个我们就是遵守这个 Apple 的一个规范 ， 用这些 foundation 的这些 library 去命名文件 ， 去访问文件 ， 比如说 openfile 之类的 API 的话 ， 那你可能得到的是一个路径对吧 ， 然后你在那个就是叫什么来着 ， 命令行的界面下你用那个 Unix 那套 API 去访问 ， 又会得到另外一个文件的路径 ， 它两个可能是不一样的 ， 这个时候就会发

现你用那个文件你用那个 Mac 的那套 API 去存了一个文件 ， 然后你在 Unix 上面你也找不回那个文件了 ， 就很尴尬嘛 。

**Eric** [1:17:11]
这个事情当年也存在的 ， 像当年就是老 Mac 转成 macOS X 的时候 。

**蒸鱼** [1:17:20]
就是 MacOS 9 对吧 。

**Eric** [1:17:23]
9 改成真正 OS X 的时候 ，OS X 是真正的 Unix 嘛 ，但是原来老的 Mac 不是嘛 ， 所以它那个路径的那个标志分割符都不一样嘛 ， 就是正斜杠反斜杠那个事情 ， 这个那这是操作系统的事情 ， 这和它那个文件系统也不搭边啊 。

**蒸鱼** [1:17:45]
那我们其实知道那个 Windows 一直以来都是用 NFC 这种形式的对吧 ， 这点应该没错吧 ， 那么 Apple 的话对 Apple 的话 HFS+ 它是用哪一种形式的呢 ，是

用 NFC 还是用 NFD 呢 ？

**Eric** [1:18:03]
这个还真的不知道 。

**吴涛** [1:18:05]
不知道 。

**蒸鱼** [1:18:05]
对 ， 我觉得这可能是第一个问题 ， 然后第二个问题可能就是 Rio 刚才说的就是在 HFS+ 的年代里面 ，Apple 是就是说 macOS 会做一件事情 ， 它做这件事情就是当你输入一个文件名的时候 ， 它会帮你转成已经标准化后的形式再存储到你的存储介质上对吧

， 我理解的没错吧 。

**Eric** [1:18:31]
应该就是说就是刚才 Rio 也说的也是 ， 就是说在这个文件系统里面它我们只说它的 normalization 它是 sensitive 还是 insensitive， 对这个规范是否敏感 ， 它没有在做 ， 的确它只是在存储代码而已 ， 存储这个 byte 而已 ，但是呢它是不是对这个 normalization 敏感 。

**吴涛** [1:18:53]
对 ，HFS 是的确是对 normalization 敏感 ，但是 AFS，APFS 好像是 。

**Eric** [1:19:00]
它就新的就不敏感了 ， 它就不敏感了 ， 对 ， 这个和那个大小写也是一样的 ， 就是 sensitive 这个这叫什么 case sensitive 和 case insensitive 嘛 。

**蒸鱼** [1:19:14]
这里还有个比较坑的一个事情 ， 就是所谓这个叫做 case preserving 和这个 normalization preserving 的问题 。

**Eric** [1:19:22]
对 ， 它可以保持按照道理保存下来 ，但是它对它不敏感就还是当成一样的

，是可保存但是它不敏感 ， 就是有这样的 ， 现在的话就是新的 APFS 就是这样 ， 它可以保存下来 ， 然后 NFC 它也认得 ，NFD 它也认得 ，但是呢它不敏感 ， 所以两边都可以 。

**蒸鱼** [1:19:45]
那么其实按我的理解 ，Apple 并没有改它的这个标准化形式 ， 它改的只是它对这个标准化形式是不是敏感这样一个问题 。

**Eric** [1:19:56]
就是在这个处理 ， 所以它对这个文件名处理它的行为发生变化了嘛 。

**蒸鱼** [1:20:02]
刚刚我查了一下那个 HFS+ 用的是 NFD 的这种标准化形式 ， 那么这个第一个问题就是跟 Windows 肯定是不一样的 。

**Eric** [1:20:13]
分解优先 ， 对 。

**蒸鱼** [1:20:16]
可能我们刚才把那个带过了哈 ， 就是刚才讲的 NFC 和 NFD 它到底是个什么意思 ， 可能还要解释一下 。

**吴涛** [1:20:23]
OK，NFC 就是先就等于是这么说吧 ， 规范化有两个思路 ， 一个是说什么叫规范化的最终形式 ， 那第一种思路就是规范化的最终形式是所有能够被拆分的东西都已经被拆分了 ， 然后我存储这个形式 ， 第二种思路是说存储的最终形式应该是所有能够被合成的东西已经被合成了 ，而且是按照某一种特定的方式合成 ， 这是第二种思路 ， 所以就是比如说

第一型规范化就是 NFD 的话 ， 那就是说以标准方式的分解 ， 分解到不能再分解了 ， 那我的规范化的完成过程就结束了 。

**Eric** [1:21:13]
比如说刚才那个鱼的话的话它就分成三就分成三个了 ， 两点然后省掉它能分就尽量分 ， 所以它我们看到是一个字 ，但是它背面它分成了三个码 。

**吴涛** [1:21:25]
对 ， 一个是 u， 一个是合成 ， 一个是两点 ，

然后如果你要如果你说我要把它合成的状态作为最终状态的话 ， 那刚才这个 u 就是就把它合成成一个字符这样来形容 ， 然后但是由于分解和结分解和合成又分别有所谓标准方式和兼容方式 ， 所以你可以说标准方式分解结束 ， 还是兼容方式分解结束 ， 还是标准方式分解之后再以标准方式合成结束 ， 还是以标准方式分解之后再以兼容方式合成结束

， 或者是反过来 ， 对 ， 基本上是一个 combination 来着 ， 对 。

**蒸鱼** [1:22:13]
我想问一下为什么要做这么多种 ， 我们的这个 normalization 的目的不就是为了解决这个标准化的问题吗 ， 为什么还要再搞四种不一样的方式呢 ， 就它们之间各有什么或者说应用场景是什么 。

**吴涛** [1:22:28]
就比如说以标准方式分解 ， 分解到不能再分解了 ， 这个实际上是非常适合编程的嘛 ， 对吧 ， 就是你 。

**蒸鱼** [1:22:36]
最小单元嘛 。

**吴涛** [1:22:38]
就比如说你刚才我刚才说那个 SWIFT 语言判定两个字符串相等的时候 ， 那你就把它们全都拆成不能再拆的状况 ， 然后看两个是不是一样的 。

**蒸鱼** [1:22:48]
然后一个 。

**吴涛** [1:22:49]
如果是一样的话 ， 那就不管它们原来是怎么样 ， 对 ， 这样就结束了 ，但是如果说你要 。

**Eric** [1:22:58]
太死板了 ， 太死板了话就是对啊 ， 就是你要拆的要先拆拆的这么碎了以后， 要每一个部件都一样 ， 它才认判定为是一样的对吧 。

**吴涛** [1:23:10]
对 ，但是这种方式的时候就是就这种规范化的方式是只适合存储或者是比较的 ， 那如果你要把它就是以节省空间的方式显示出来的话 ， 那你还是很有可能希望说我要把它最终还是要合成起来 。

**蒸鱼** [1:23:31]
就刚才那个拆的方式说可能会导致比如说那个特殊的字符就是鱼再加一个声调的话 ， 它会从理论上它可以从一个点位变成三个点位嘛 ， 就是这个它的空间存储空间的要求变成三倍了嘛 ， 然后那我们如果就全部合到一起有什么不好呢 。

**吴涛** [1:23:55]
的确没有什么 。

**蒸鱼** [1:23:55]
只是为了比较 ， 比较化 ， 就是说比如 NFD 的应用场景和 NFC 的应用场景它们各有什么不同 ， 就是不能互相替代的地方 。

**吴涛** [1:24:04]
因为 NFD 你要少做一步计算 ， 就 NFC 你最终要把它合成起来的 。

**蒸鱼** [1:24:10]
但是 NFD 的你要付出更多的存储空间呀 。

**Eric** [1:24:14]
对呀 ， 所以这个就是一长一短嘛 。

**吴涛** [1:24:17]
这就是时间 ， 这是时间换空间还是空间换时间的间隔嘛 。

**Eric** [1:24:21]
对 ， 所以这个就是逻辑问题 ， 然后只是偏好问题而已 ， 这个并没有什么对错或者怎么样 。

**蒸鱼** [1:24:29]
所以刚才提了一个叫做兼容分解和标准分解有什么不一样 。

### 兼容分解

**Eric** [1:24:33]
那个我简单来说一下兼容分解 ， 就是我不把它说得非常细 ， 就兼容分解要解决一个问题就是说有一些串它在这个字符的 byte 的表达层面是不一样的 ， 然后它拆分组合之后呢也是不一样的 ，但是我们希望认为它们是一样的 ， 比如一个场景就是合字的问题 ， 比如 fi 合字 ， 那么 fi 合字我们可以理解成它是一个 f 和一个 i 的两个字母的合成 ，但它同

时又是一个单独的码位 ， 就是 Unicode 里面有一个码位就是 fi 这个合字了 ， 那么我们在搜索的时候呢用户可能输入 fi 合字是非常复杂的 ， 所以我们可能希望用户输入一个 fi 一个 f 和一个 i， 我们可以把所有 fi 合字相关内容也给它匹配起来 ， 所以这个时候就是这个兼容性分解和合成所需要起到作用的这样一个场景 。

**蒸鱼** [1:25:25]
等一下， 这里我提一个问题 ， 好像没有区别啊 ， 只用分解一次就好了嘛 ， 或者合成一次就好了嘛 ， 就是你这个时候你这个问题是这样子啊 ， 就是说有一堆文档里面包含这个 fi 的合字和 fi 分解的两种情况对吧 ， 我们没有做对它做任何处理 ， 这个时候你用户来了说用户说输入 fi 我们希望把前面的 fi 合字和 fi 分开的都搜出来对吧 ， 这

个时候有两种做法 ， 第一个是说我们把这个我们之前存的那些文档全部做分解 ， 就是把 fi 的合字一个 codepoint 分成两个 ， 然后这个时候我们就可以直接跟那个用户输入的 fi 直接对比了嘛 ， 另一个方法就是说我们把用户输入的 fi 弄成一个合字 ， 同时把所有我们已有的文档里面的 fi 分开的也弄成一个合字 ， 这个时候再搜索也可以了嘛 ， 对吧 ， 就这

两种操作方式嘛 。

**吴涛** [1:26:14]
对对对 。

**蒸鱼** [1:26:15]
OK。

**Eric** [1:26:16]
但是因为你这就是为了兼容嘛 ， 用户并不知道这里面到底用的是合字还是分开的 。

**蒸鱼** [1:26:23]
但这里问题就是说这个标准分解和这个兼容分解好像没有区别在这里面 。

**Eric** [1:26:30]
这个区别就在于哪些东西是可以分的 ， 就是说哪些东西是可以等价的 ，其实它们的区别就在于 ， 比如说那个 fi 合字它本质上不能完全等同于一个 f 和一个 i， 它们本质上是两种不同的字符 ， 那么有的时候我们希望它们是等价的 。

**吴涛** [1:26:47]
对 ， 这个其实不仅仅是说这不纯粹是一个字符层面的问题 ， 还是一个语言层面的问题 ， 比如说在有些语言里面 。

**Eric** [1:26:57]
它是一个语义的问题 。

**吴涛** [1:26:58]
对 ，在有些语言里面 ch 或者是

sh 是被视成一个视作一个单独的字母 ， 或者是在比如说像荷兰语里面 ij 经常是一个单独的字母 ， 另外就是对 ， 另外就是有些语言里面一个字母可能有两种形式 ， 比如说阿拉伯语字首字中字末一个字母是表达形式不一样的 ， 比如希腊语那个是 sigma，sigma 在词尾的时候写法和在词中不一样 ， 又比如说那个英语里面的长 s 就是微积分那个符号那个 s，

它跟普通的 s 也不一样 ，在德语里面在旧式的德语正字法里面 ， 如果它如果一个 s 出现在词中的话 ， 你必须写成长 s，但是长 s 你用标准分解的话 ， 你只能最终只能分解出一个长 s，但如果你用兼容分解的话 。

**Eric** [1:27:54]
因为它本来就是一个字符 ， 它不管单独还是合 ， 它就是一个字符 。

**吴涛** [1:27:58]
对 ，而如果你用兼容分解的话 ， 它会说哦这个 s 实际上是这个长 s 实际上是 s 的一个变种 ， 所以在匹配的时候我必须把它匹配成一个短 s。

**蒸鱼** [1:28:08]
就是说有一些 。

**Eric** [1:28:09]
以便于搜索到 ， 就有一些组合在标准分解它是不能分解 ，但是为了让大家方便 。

**吴涛** [1:28:17]
会让它 。

**Eric** [1:28:17]
这样就把它拆成就强行拆开 。

**蒸鱼** [1:28:21]
对 ，是的 。

**Eric** [1:28:23]
哇天啊 ， 这个 。

**蒸鱼** [1:28:24]
对 ， 它有几种常见的形式 ， 一种就是一个字母它可能有一些字体设计这个历史原因带来的不一样 ， 比如说一个拉丁字母它可以设计成好几种形式了 ， 比如说什么有什么双层形啊之类的 ， 就这个双层是指这个视觉样式上了 ， 比如它有一个双勾线的这种形式 ， 然后另一种形式呢比如说有一些空白字符 ， 它们可能都是一个空格 ，但是它们可能有我们知

道 Unicode 有非常多种空格 ，但是我们希望它们在搜索的时候或者在语义识别的时候认为它们都是空格这一种 。

**Eric** [1:28:57]
都是 white space。

**蒸鱼** [1:28:58]
对 ， 然后另外一种就是刚才吴涛说的有一些语言里面有一些字母它在不同的位置上它其实会有不一样的写法 ， 然后它也有不一样的 Unicode 码位 。

**吴涛** [1:29:08]
对 。

**蒸鱼** [1:29:08]
OK， 对 ， 然后接下来有一种比如说数字有的是带圈的 ，有的是不带圈的 ，但它们可能都是同一个数字 1 或者数字 2， 那么它们应该是一样的 ， 就我们希望它们识别成一样的 ， 然后日语里面假名有半角和全角的区别 ， 然后汉语里面标点符号有竖排和横排的区别 ， 然后还有像数学里面有上标和下标和这个非上标下标的这个普通数字的这个

区别 ，但它们都是同一个数字 ， 另外日语里面还有一些就是几个字母几个字或者几个假名它会组合成一起 ， 比如说这个年号像什么平成 ， 它可能会组合成一个字符 ，但它也可以写成平成这两个字 ， 对 。

**Eric** [1:29:47]
株式会社 。

**蒸鱼** [1:29:48]
啊对对对 ， 株式会社 ， 叠在一起的 ， 对对对 ， 填字格的方式 。

**Eric** [1:29:53]
对 ， 另外就是像有分数 ， 比如说 1/2 它可能有一个单独的码位就是 1/2，但我们也可以写成 1/2 这样的一种形式 。

**吴涛** [1:30:02]
这个例子很好 ， 就是我第一次我刚到德国的时候最惊艳的一件事情就是德语键盘上有 1/2、1/3 这两个键 。

**蒸鱼** [1:30:14]
所以我问一下， 刚才我们讲的很多都是这个外文的问题 ， 中文有这个问题吗 ？

**Eric** [1:30:18]
中文我刚刚说了一个嘛 ， 就是标点的横竖形 ， 就是横排和竖排标点 。

**蒸鱼** [1:30:23]
但这个不涉及拆解的问题吧 ， 它就是说把哪些它本来不在一个码位的标点 ，但是因为我们认为它的在某一些情况下认为它是等价的嘛 。

**Eric** [1:30:33]
对 ， 所以 normalization 不只是一个拆分的问题 ， 它有的时候也是单个字符之间相互的等价问题 。

**蒸鱼** [1:30:39]
对 ， 中文是没有拆分和组合这个问题吗 ？

**Eric** [1:30:43]
中文基本上没有 ，但韩语可能就会有 。

**蒸鱼** [1:30:46]
那中文那个带圈文字是有这个问题没 ？

**吴涛** [1:30:49]
中文是什么 ？

**Eric** [1:30:50]
那有带圈文字的话就会有刚才那个兼容的问题嘛 ， 就是因为你它即使加了一个圈 ，但是比如说那个 。

**吴涛** [1:30:58]
哦 ， 圈里面加一个圈是吧 。

**Eric** [1:31:02]
对啊对啊 ， 就是圆圈嘛 。 有人说要为它申请个特殊的码位 ， 这是另外的 ， 还有比如说像什么括弧 1 对吧 ， 括弧 123456789， 汉字的对吧 ， 像这些都是有那个兼容的 ， 这样的兼容的话给它拆成三个嘛 ， 前括弧汉字 1 后括弧就是它也要这样认嘛 ，以便于可以搜索到嘛 。

**蒸鱼** [1:31:24]
就中文其实也有这个问题对吧 。

**Eric** [1:31:26]
对 ， 这些其实都是日本过来的 ， 我觉得最早应该都是日本人去申请这些码位的 。

**蒸鱼** [1:31:32]
那我再问一下， 那是不是说现在不是流行那个火星文嘛 ？ 火星文不是只有半截式那个正常的字母 。

**吴涛** [1:31:40]
Oh my god。

**蒸鱼** [1:31:41]
部首都是没有用的是吧 ， 所以其实 。

**吴涛** [1:31:43]
Oh my god。

**Eric** [1:31:45]
火星文能不能等价是不是 ？

**蒸鱼** [1:31:47]
对啊对啊 ， 你必然就是我们在实际使用的情况下， 火星文必然是等价为某一些这个就是非火星文的文本的嘛 ， 就其实它也是一个 。

**吴涛** [1:31:57]
这个我觉得这个还是留给人工智能解决吧 ， 我靠 ， 这个你强要一个 normalization 的过程 ， 考虑这种情况实在是太强一组了 ，因为 。

**蒸鱼** [1:32:08]
不不 ， 我就说因为这个可能不需要在这个就不能写到规范里面去嘛 ，但是如果说比如说这个我们现在在做一个这个审查系统对吧 ， 我们做这个内容过滤 ， 可能要过滤到某一些不合时宜的字的时候 ， 你肯定还是要做这个火星文的拆解 ， 然后做一个等价替换嘛 。

**Eric** [1:32:28]
就是你说能不能沿用 Unicode 这套 normalize。

**蒸鱼** [1:32:32]
就是它的逻辑肯定是沿用 。

**Eric** [1:32:34]
逻辑 ， 对 ， 它就是所谓的兼容分解嘛 ， 所谓的 。 这个不一定 ， 我觉得不一定 ， 就要看你能不能设计出这样一套机制 ，因为其实 normalization 有一个数学上的特性 ， 它叫幂等性嘛 ， 就是你无论对一个串做多少次这个 normalization 之后 。

**蒸鱼** [1:32:50]
结果最终是一样的 。

**Eric** [1:32:51]
对对对 ， 就是你要看你的设计的这套拆解和组合机制能不能符合这个幂等性 。

**蒸鱼** [1:32:58]
而且幂等要倒回来 。

**Eric** [1:32:59]
对 ， 当然要能倒回来 ， 倒不回来的话就不是都错了嘛 。

**蒸鱼** [1:33:05]
对 ， 所以我觉得火星文可能有问题 ， 火星文有问题 。

**Eric** [1:33:09]
那肯定是倒不回来的呀 ， 比如说它原始的一个我们刚才举那个鱼和上面有个有一个鱼撇这个一个情况嘛 ， 那其实我们想来它应该有好几种组合形式对吧 ， 它可以说是 u 组合一个就最拆解三个类点然后拼一起的方式嘛 ， 它可以说是就是 u 上面有鱼然后再加一个无音调 ， 就是两个点对吧 ， 它也可以是 u 有声调再加两个点嘛 ， 那其实你拆解之后你

是回不去的 ， 它这个是一个单向的过程 ， 就好像那个繁体中文转简体中文一样 ， 你是不能就是过去又回来的嘛 。

**吴涛** [1:33:49]
OK。

**Eric** [1:33:50]
就是它应该不是一个可逆的操作 。

**蒸鱼** [1:33:54]
为什么 ？

**Eric** [1:33:54]
因为你丢失了你最开始你进去的 。

**吴涛** [1:33:57]
你丢失了一开始的信息 ， 这是没错的 ， 就是你 normalize 过后你一开始什么样你就不知道 。

**Eric** [1:34:04]
对啊 ， 所以它就不能做到幂等 ， 就是可以不断重复的做一个 normalization， 它得到结果是稳定的 ，但是它不能它不能做不能反不能再逆回去 ，不可逆的 。

**蒸鱼** [1:34:15]
你的意思是你不知道它最初这个 source 究竟是哪一种表达形式 。

**Eric** [1:34:20]
对对对 ， 你不知道 。

**蒸鱼** [1:34:20]
是 ， 你漏掉这个就破坏掉那个信息了嘛 。

**Eric** [1:34:24]
OK，但是它们永远是相等的 ，但是如果你拆这个汉字的话就不一定了 ，因为你本质上拆汉字就是把汉字拆成各种偏旁部首 ， 然后把它们组合起来 ，但我们知道汉字这个偏旁部首可能前一个字的一个偏旁可以成为后一个字的另一个偏旁 ， 所以它们的组合方式有很多嘛 ， 这个时候它们就可能不幂等了 。

**蒸鱼** [1:34:47]
就是那个火星文的左右两边可能选出来的那个字是就是一个选了左边那个部首 ， 一个是选的是右边那个部首对吧 。

**Eric** [1:34:54]
对对对 ， 就有可能会有这种情况 ， 对 ， 这有可能会破坏这个幂等性 。

**蒸鱼** [1:35:01]
这还是挺坑的一个事情 。

**Eric** [1:35:03]
对 ，因为 Unicode 为了维持这个幂等性 ， 它其实是做了很多工作的 ， 包括它定义了这个拆解出来的部件的顺序 ， 如果你破坏了这个顺序的话 ， 就有可能破坏了这个幂等性 ， 所以它拆解的这个顺序是有确定的顺序的 ， 比如有一些字母它可能上面可以加一个点 ， 下面也可以加一个点 ， 那么哪个点是下面这个点在前还是上面这个点在前 ， 它其实是有固定

顺序的 。

**蒸鱼** [1:35:25]
嗯哼 。

本期节目的那个 show notes 里面还得标注一下幂等性的一个链接到底 。

**吴涛** [1:35:33]
幂等性 ， 天啊我靠 。

棚架这最后肯定我相信肯定有读者是连着幂等性一路点到什么棚架来什么 。

**Eric** [1:35:46]
这就是个数学问题 。

**吴涛** [1:35:47]
对 ， 哥德尔不完备定理 。

**蒸鱼** [1:35:52]
哇了好大一个 。

**Eric** [1:35:53]
就是 Wikipedia 各种链接点点点 ， 你最后都会点到那几个页面 。

**吴涛** [1:35:57]
对 ， 最终肯定会回到哲学 ， 我跟你讲 ， 哲学和数学

。

**蒸鱼** [1:36:08]
刚才我们讲了这个就是那个 normalization 的各种方法和它的背后的一些这个机制哈 ， 然后我们回来讲那个 APFS 它在 macOS 和 iOS 里面到底不一样的地方 ， 我觉得这个还其实挺有意思的 ，因为照我的理解 APFS 在 macOS 里面对于 normalization 的处理是最近才决定的 ， 就是其实我们在之前上那个 iOS 的 APFS 它是没有考虑这个问题的嘛 。

**Eric** [1:36:36]
嗯 。

**蒸鱼** [1:36:37]
对 ， 所以它现在搞了一个什么样的一个哈希的方式我还没太明白 ， 你们谁看了 ？

**Eric** [1:36:44]
我也不知道 。

**蒸鱼** [1:36:44]
就是说因为它改成 APFS， 就是不管 Mac 是用 HFS+ 还是用 APFS， 它都是这个 normalization insensitive 的 ， 它就它不敏感 ， 它对你这个规范化形式不敏感 ，但是呢 HFS 它是它就直接它就直接存在那个磁盘上了 ， 那 APFS 呢它会它是先规范化 ， 然后这个文件名它会它会另外生成一个哈希值来指来给这个提供那个 normalization 的这个就不敏感性 ， 要不然的话就找不到了嘛 ， 就是所以它必须

再给它附一个那个自动附一个哈希值 。

**Eric** [1:37:32]
OK， 这里面其实还挺麻烦的 ，因为有几个问题啊 ， 就是刚才讲的有几个事情揉在了一起 ， 就是一个说它要不要保留那个就是你开始的这个先说一下还有个事情没说 ， 刚才因为这跟你有关系 ， 就是 iOS 的那个文件系统是大小写敏感的 ， 就是大小写是就同样一个文件名大小写不一样 ， 它认为是不一样的那个文件哈 ，在 macOS 里面 。

**蒸鱼** [1:38:01]
也是 。

**Eric** [1:38:01]
不管是它不管是过去的 HFS 还是现在 APFS， 它默认的都是大小写不敏感 ， 就是它认为 。

**蒸鱼** [1:38:08]
但是它是大小写可保存但是不敏感 。

**Eric** [1:38:13]
对 ， 它会把那个你开始原始的那个大小写保留下来 ，但是就说它不会它不会说它会去区分这个事情 ，但是当然也可以就说你在那个 macOS 里面你在格式化一个磁盘的时候 ， 你可以选择让那个文件系统是做成大小写敏感的 ，但这个应该用的人不多 ，而且再用了就会导致很多兼容性的问题 ， 就是不太鼓励大家这么做的 ， 所以这里面如果它是用哈希

值的话就会牵涉到这个问题了 ， 就是说如果它是大小写 preserving 就是 case preserving 的话 ， 它哈希的那个串到底是什么啊 ，因为大小写不同的两个同样的字符串的哈希值是不一样的 。

**蒸鱼** [1:38:55]
对 。

**Eric** [1:38:57]
这样的话它的这个它的 case preserving 和它的这个哈希的方式其实是有冲突的 ， 所以我一直没太搞明白这里是怎么一回事 。

**蒸鱼** [1:39:06]
对 ， 我觉得先要给字谈字畅的这个听众简单解释一下哈希是个什么样的过程 。

**Eric** [1:39:13]
哈希你可以理解成为就是我们把一个字符串吧 ， 然后通过某种数学的方式把它变成一个固定长度的一个数字 ， 这可能都是比如说是 120 啊不对 ， 哈希一般 16 个字节是多少 ，16 个字节是乘以 8 对吧 ，256 个呃别错了 。

**蒸鱼** [1:39:39]
256 个字节 。

**Eric** [1:39:41]
就等于给它一个生成了一个特定的一个码编号 。

**蒸鱼** [1:39:46]
对 ， 就是 。

**Eric** [1:39:47]
正常的会返回一个比如说 256 个 bit 的一个数或者是 512 个 bit 的一个数 ， 然后因为这个数其实足够大嘛 ， 你想一下 2 的 2 的 256 次方这个数其实非常大的 ， 那么这个哈希有个什么特性呢 ， 就是说只要我们这个哈希算法或者这个哈希函数选的少 ， 我们可以做到在一个几乎可以忽略的概率上得到那个数和就两个就不太可能得你不太可能拿两个有意义的文

本得到两个完全一样的哈希的值 。

**蒸鱼** [1:40:19]
嗯嗯 。

**Eric** [1:40:20]
这个可能有很多人比较容易费解这个东西 ， 就因为你想一下这个在数学上是不可能的嘛 ，因为你的那个字符串的就是你的那个函数的哈希函数的那个输入的那个 space input space 是远远大于这个 output space 嘛 ， 要不它是一个它是一个固定 。

**蒸鱼** [1:40:36]
它是一个有限值 。

**Eric** [1:40:38]
它是对 ， 它是个有限集嘛 ，但你输入的其实是一个无限集嘛 ，但是因为那个无限有输出那个有限集的空间足够足够大 ， 然后只要我们这个哈希函数选的足够好的话 ， 我们是可以在大概率上认为是不会出现那种两个不同的输入得到同一个哈希值的嘛 ， 然后这个哈希值就我们可以拿来做很多事情 ， 比如说我们可以拿来把一个东西缩短成一个我们认为

这个它的是一个类似于指纹的一个概念对吧 ， 我们觉得它这个这一串哈希值可以对应那串原文 ，因为我们找不到另外一串原文跟这个跟这个可以得到同样的哈希值 ， 然后 APFS 里面就它就是说我是用这个哈希值来保存文件的对吧 。

**蒸鱼** [1:41:20]
嗯 ， 保存文件名。

**Eric** [1:41:22]
对 ，但我就不太理解就是说这里面如果它怎么去解决刚才讲的那个 case preserving 的问题 ， 就其实我看起来还觉得还挺难的 。

**蒸鱼** [1:41:30]
所以啊就是这有一个历史就是在这个 macOS Sierra 的去年 6 月份 ， 它已经它有做一个 APFS 的第一版的开发者的预览版 ， 当时这个预览版里面只有 case sensitive 的版本 。

**Eric** [1:41:47]
嗯哼 。

**蒸鱼** [1:41:48]
就是说明那时候苹果还没想好就怎么做你知道吧 ， 所以当时它做的第一版的开发者预览版只能做 case sensitive 对大小写 。

**Eric** [1:41:58]
这个就是最简单嘛 。

**蒸鱼** [1:41:59]
对对对 ， 然后等到后面 macOS 的 10.12.4 了以后给这个开发者的预览版后面它才补加了做出来这个 case insensitive 的版本 。

**Eric** [1:42:11]
因为它这个是就是就也是因为就是为了去填那个历史的坑嘛 ，因为过去 HFS 它是默认是 insensitive 的 ， 你就很尴尬 。

**蒸鱼** [1:42:20]
对 ， 所以其实就是它在后面具体它在怎么搞其实我也不大清楚 ，但是就是因为有这个坑所以对 ，因为有这个坑所以它也是花了很长时间在搞的 。

**Eric** [1:42:32]
因为现在那个 APFS 就那个 High Sierra 还没有就是正式发布嘛 ， 现在只是 beta 版哈 ， 就说他们还有的有的机会改 ，但是如果说到了今年的这个 9 月份也就两个月的时间嘛 ， 对 ， 就会放出来 ， 放出来之后如果没有这个问题没解决好的话 ， 就会导致很多人的软件可能用不了或者说是文件出问题的情况 ， 所以他们必须在必须在这段时间把这个问题给彻底

解决了 。

**蒸鱼** [1:42:57]
嗯嗯 。

**Eric** [1:42:59]
用各种方式吧 ， 就现在我们看到的其实也不是一个我觉得应该也不是一个最终的版本 。

**蒸鱼** [1:43:04]
嗯 ，不过反正 High Sierra 是可以定了 ， 就是肯定要用新的这个 APFS 了 。

**Eric** [1:43:12]
嗯哼 。

**蒸鱼** [1:43:12]
在安装过程中它会默认的 ， 它会先把你格式化一遍 。

**Eric** [1:43:16]
你默认 。

**蒸鱼** [1:43:17]
格式化 ， 没有没有 ， 就是 。

**Eric** [1:43:19]
还没知道呢 。

**蒸鱼** [1:43:19]
但是生其实在生那个 iOS 10.3 的时候就是这样的呀 。

**Eric** [1:43:25]
iOS 都说了嘛 ， 它不存在这个它不担心这个问题 ，因为 iOS 并没有 。

**蒸鱼** [1:43:28]
啊对啊没错 。

**Eric** [1:43:30]
而且而且而且 iOS 还有个特性就是它没有一个它只有一套 API 去访问那个文件就是 。

**蒸鱼** [1:43:37]
对 。

**Eric** [1:43:37]
都是用那个 foundation 那些库嘛 ， 它不像那个 Mac 里面我们用这个 terminal 的时候其实是直接用 POSIX 就 Unix 那套逻辑去访问嘛 ， 所以它 。

**蒸鱼** [1:43:45]
POSIX。

**Eric** [1:43:46]
对 ， 它考虑的那个那个那个难度就是要小很多 。

**蒸鱼** [1:43:50]
对 。

**Eric** [1:43:50]
所以我觉得 Mac 其实挺大的一个坑的 。

**蒸鱼** [1:43:52]
嗯 ，而且说实话这个东西对于用户来讲是完全看不见的嘛 ， 像我刚才说的它这个格式化的过程它其实安就放到了那个安装进程里面去 ， 你开始对于尤其是对于 iOS 啊你在装在更新的时候就用户不能做任何事情嘛 ， 反正你就等着它不要重新启动两遍哦 ， 反正就是新的了就这样 。

**Eric** [1:44:16]
而且而且就是用户就算即便知道了这个区别它也改不了做不了任何事情 ，因为你用的这个程序如果没有没有更新去支持这个事情的话 ， 你也是只能抓瞎嘛 。

**蒸鱼** [1:44:27]
对 ， 那对于 Mac 的话呢 ， 可能就是因为如果万一搞不清楚的话就会造成找不到文件了对吧 ，因为那个那 normalization 不一样 ， 文件名不一样嘛 ， 然后就和你磁盘上存的东西不一样就找不到了就有时候 。

**Eric** [1:44:43]
对 。

**蒸鱼** [1:44:43]
这是最坑的最最差的结果嘛 。

**Eric** [1:44:47]
所以所以这个 normalization 这个事情会对我们交换在不同程序里面交换文件产生影响吗 ， 就是因为现在有很多问题 ， 比如说我不知道你们有没有收到 Windows 用户发给你们的这种 zip 这种打包的这种压缩包 。

**蒸鱼** [1:45:01]
啊 ， 经常会乱码的事情 。

**Eric** [1:45:02]
就经常会解解出来里面的那个文件就是那个名字是乱的嘛 。

**蒸鱼** [1:45:08]
嗯嗯 ，但是那个乱码的机制很复杂的 ， 就是为什么会乱 。

**Eric** [1:45:14]
呃 ， 就是简单来说那个 zip 打包的时候它会把那些文件名的信息也装进去嘛 ， 这个时候它用的那个 encoding 的方式啊 。

**蒸鱼** [1:45:25]
嗯 。

**Eric** [1:45:25]
就就 zip 这个格式其实是比较灵活的 ， 它不会要求说你一定要有什么 encoding 的方式 ， 这个时候都是由那个打包程序决定的嘛 ，但是解码的程序又如果用的跟那个打包程序它用的那个理解是不一样的话 ， 就会导致这个问题 。

经常我们收到一个 Windows 用户发过来打包的 。

**蒸鱼** [1:45:45]
但是这是编码层次的问题啊 ， 就是比如说它没有用 UTF-8 之类的 ， 这是编码和解码的事情啊 。

**Eric** [1:45:53]
对对对对对 ，但是我就说如果是呃哪怕他们都用了 UTF-8 去编码 ， 那个 normalization 不同的话解出来也会导致不同的 。

**蒸鱼** [1:46:01]
也会不一样 。

**Eric** [1:46:02]
对 ， 没错 ，是的 。 所以这是一个非常非常深的一个坑 。

**蒸鱼** [1:46:08]
对对对 ， 所以呢就刚才说一般遇到乱码问题的话是编码层面的问题 ，而像我刚才说的呃在日文的 Windows 拷贝到 Mac 上面就会发现这个字被拆开来了 ， 就会有这样的问题 。

**Eric** [1:46:25]
就会变成一个字它变成两个字了是吧 。

**蒸鱼** [1:46:27]
两个字了 ， 对对对 。

**Eric** [1:46:28]
就是你看着已经是两个字了 。

**蒸鱼** [1:46:30]
你看着就已经是两个字 ， 就是嗯就会就完全会被拆开来 ， 就是因为它已经它从就透到那个操作系统层面上来了变成 。

**Eric** [1:46:42]
OK， 就用户已经感受到 。

**蒸鱼** [1:46:43]
因为系统不一样 。

**Eric** [1:46:44]
那这个时候你们怎么办呢 ？

**蒸鱼** [1:46:46]
没办法呀 。

**Eric** [1:46:48]
就自己再重新编辑一下文件名。

**蒸鱼** [1:46:51]
对啊 。

**吴涛** [1:46:51]
但其实这个这件事情并不是发生在 normalization 的这个过程中我觉得 。

**蒸鱼** [1:47:00]
嗯 ， 对 ， 没错 ， 这不是这个过程当中 。 嗯 ，但是毕竟是因为它 normalization 它的采取的原则方式不一样 ， 然后最后呢它而且原来刚才也说了嘛 ， 就 normalization 这个事情它其实是不会被用户所知道的嘛 。

**吴涛** [1:47:15]
嗯 ， 就其实它是这样的嘛 ， 就说说明 Windows 的某一个用户他在输入这个文件名的时候 ，他输入的那一串字符其实就是一个被拆解的形式 ， 然后呢它就被 Windows 的这个操作系统记录下来并且保存下来 ， 那么它传到这个 OS 10 上的时候 ， 呃 OS 10 就觉得哎这里其实是两个字符 ， 那么我就把它们分开进行一个操作 ， 比如说删除的时候你能删除其中的一半对

吧 。

**Eric** [1:47:41]
嗯 。

**蒸鱼** [1:47:41]
对 ，但是其实两个操作系统之间这里反而体现了 normalization 的一个好处吧 ， 就虽然它可能输入的这个字符串行为是不一样的 ，但是至少我们在看的时候看起来它们是一样的 ，并且我们搜索的时候也能搜索到它 ， 就是我觉得这个时候反而是 normalization 起到了一个保护的作用 ， 就是它没有让整个文件名变得不兼容 ，而还起到了一定的这个最基本的兼容 。

**Eric** [1:48:10]
嗯哼 ， 对 ， 所以 normalization 是必要的就是 。

**蒸鱼** [1:48:13]
哎 ， 那我问其实你们知道这个中国用户怎么解决这个问题吗 ？

**吴涛** [1:48:20]
中国用户其实遇到的不算太多吧 。

**蒸鱼** [1:48:23]
对啊 ， 就就为了为了啊就就要避免在那个文件里面使用中文嘛 ， 那就用拼音的所有字母代替就好 。

**Eric** [1:48:31]
啊哈哈 。

**蒸鱼** [1:48:32]
很多人很多人这么干的嘛 。

**吴涛** [1:48:34]
好吧 ，但其实这个完全是为了避免编码的问题吧 。

**Eric** [1:48:38]
呃 ， 这也也为了就打字比较简单嘛 ， 总比你找字相对来说方便一些嘛 。

**蒸鱼** [1:48:45]
所以我不知道这个 Eric 你可能比较熟悉一点 ， 就是在日文用户里面会有很多人用日文去命名那个文件名吧 。

**Eric** [1:48:53]
对啊 ， 那肯定啊 。

**蒸鱼** [1:48:54]
嗯 ，OK。

**吴涛** [1:48:56]
我其实经常遇到一个问题 ， 比如说我看一个英文的文档 ， 然后这个文档可能是排版的比较精细的 ， 它里面有一些单词就会出现合字 。

**蒸鱼** [1:49:05]
对 ，fi 合字搜不到 。

**吴涛** [1:49:07]
对 ， 这个时候我用那个系统的自带的那个 ， 比如说啊三指双击可以取词查查字典嘛 ， 这时候它查到那个字它就会识别不了 ，因为它里面带了一个合字 ， 我觉得这方面好像至少我现在用的这个 Sierra 还还处理的不是很好 。

**Eric** [1:49:24]
就 PDF 会有这个问题吗 ， 主要是 。

**吴涛** [1:49:26]
对对对 ， 就 Preview 这个 APP 它在这方面的处理我觉得还不是特别的完善 ， 它其实理论上它应该是帮你做好这个 normalization 再去查字典 。

**蒸鱼** [1:49:34]
这里面跟那个 PDF 生成好像还有什么关系 ， 这就是我 。

**Eric** [1:49:38]
这这跟对这个这个比较复杂 ， 这呃不完全是 Preview 的错 。

**蒸鱼** [1:49:44]
对 ， 跟 PDF 规范有一定关系 。

**Eric** [1:49:46]
对 ， 跟 PDF 有关系 ，而且是呃对没错 ，是的 。

**吴涛** [1:49:49]
但其实如果它它用这个兼容方式的 normalization 它处理的特别好的话 ， 它其实可以绕开这个问题 。

**蒸鱼** [1:49:58]
啊 。

**吴涛** [1:49:59]
它其实没有做这个兼容处理嘛 ， 它只是做了一个标准处理可能 。

**蒸鱼** [1:50:04]
但基本上如果你在网页上的话 ， 它应该还是可以正确识别出来吧 。

**吴涛** [1:50:09]
不一定 ， 我觉得还真不一定 。

**蒸鱼** [1:50:11]
还不一定哈 。

**Eric** [1:50:11]
不一定 ，不一定 。

**吴涛** [1:50:12]
对 ，因为网页上很多时候你看到的这个 ligature 可能它并不是一个真正的 Unicode 的 ligature， 它可能只是一个 font 来显示出来的 ligature， 可能用户输的都是单独的字符 ， 所以你不太会遇到这个问题 。

**蒸鱼** [1:50:27]
对 。

**Eric** [1:50:28]
哎 ， 所以说这是你你看到东西其实有一个很多很多层面的东西 ， 嗯 ， 你看到是一个字 ， 它可能是两个字 ，但是变成一个字的时候可能是系统帮你做的 ， 可能是 application 帮你做 ， 那也可能是 font 帮你做的 ， 就是就中间隔了好多道 。

**蒸鱼** [1:50:45]
对对对 。 所以人类为什么要给自己找这么多麻烦 。

**Eric** [1:50:51]
其实说实话 ， 如果不 Unicode 的话 ， 就各个各各自做各的就就不会有这么多问题 。

**蒸鱼** [1:50:56]
但是就会有各种就好多好多套规则嘛 。

**Eric** [1:51:00]
哈哈哈 ， 比较坑 。

**蒸鱼** [1:51:03]
所以 Unicode 对啊 ， 就是这一个大熔炉嘛 ， 就什么东西都有嘛 ， 然后就就会发生说以前不曾出现过的问题 ， 知道吧 。

**Eric** [1:51:11]
不对啊 ，其实你各搞各的也会出现这个问题 ， 你还是要考虑就是说比如你搜索的时候你要考虑说这兼容的问题嘛 ， 无非就是说有有各个应用程序自己去搞 ， 还是说交给 Unicode 这个组织来统一搞一套 ， 大家都遵守这个标准来搞就好了 ， 虽然很复杂 。

**吴涛** [1:51:27]
可能各搞各的问题更多吧 ， 可能搜都搜不到 。

**Eric** [1:51:31]
哈哈哈 。

**吴涛** [1:51:31]
对 ， 你你一个汉字可能在这个 Big Five 里和在 GB 里面完全是不一样的内码 ， 这个搜都搜不到 。

**蒸鱼** [1:51:37]
嗯嗯 ，但是还好人类在这这一个时机的话又发现必须要做 Unicode， 然后现在大家走上了 Unicode 阳光大道了 ， 才发现还要做很多很多的相互兼容 。

**Eric** [1:51:50]
嗯哼 。 但非常不幸的是 ， 还有很多国内的网站还是用 GB 这个 2312 的 。

**蒸鱼** [1:51:57]
哎 ， 台湾也有很多 ， 就是在用 Big Five， 然后可能打开就会变成乱码 。

**Eric** [1:52:05]
哈哈 ， 对对对 ， 声明又又很不正确的就是对吧 ， 那个 HTM 声明 。

**吴涛** [1:52:11]
对 ， 我记得台湾教育部好像还有一个网站是用 Big Five， 然后它那个网页不知道是出什么问题 ， 用 Safari 打开基本都会是乱码 。

**蒸鱼** [1:52:19]
就默认就是乱的 ， 对 。

**吴涛** [1:52:21]
对 ， 你要手动去调 。

**蒸鱼** [1:52:24]
对对 ， 浏览器的那个那个就启发式判断的方法都已经失效了 。

**Eric** [1:52:30]
嗯 。

**蒸鱼** [1:52:31]
特别坑 。 好吧 ， 今天差不多讲到这里了 。

**Eric** [1:52:35]
我其实想经通过这样一个节目呢 ， 就是告诉我们的听众朋友 ， 就说平时大家说 Unicode 哈 ， 就感觉就是就是就编码嘛 ， 对吧 ， 就就是码位啊什么什么这些东西 ，其实 Unicode 除了就给字符编码的以外， 它还有很多就是在 Unicode 这个叫 Standard Annex， 呃就 Anexis 嘛 ， 就是它一个标准的附录 ， 然后这附录里面其实有很多就是文文字处理方面的一些技术信息 ， 比如说像今天我

们说的这个 normalization，其实这是一个很复杂的一个技术环节的问题 ， 这其实也是 Unicode 标准的其中之一是 ，而且对作为 Unicode 它是必要的 。

然后像比如说我们上上次在节目也提到 ， 就比如这次 10.0 里面增加了一个就是 Unicode 标准附录 ， 就是 Unicode 竖排文本啊 ， 这这这其实也是必要的嘛 ， 就说在横排和竖排之间是有什么样的关系 ， 呃要给给它提升到这样一个标准附录里面去的话 ， 能给这个它首先有个 core specification， 就核心的这个标准的一个规范 ， 然后呢还周边有这么多标准的附录 ， 这样

组合起来才是一个整体的 Unicode 的这样一个应该可以说是一个系统了 ， 对吧 。

**吴涛** [1:53:58]
嗯 。

**Eric** [1:53:59]
那其实我们在字谈字串的这个专题里面 ，其实我们还可以再讲很多很多关于这样的事情 。

**吴涛** [1:54:07]
对 ， 那关于这个 normalization 的应用层面的问题 ， 就是第一个我想问的问题是 ， 作为一个软件开发者来说 ，他多大程度上会遇到说我要去主动解决这个问题 ？Rio 你有没有遇到过要去解决这个问题 ？

**蒸鱼** [1:54:24]
比较少 ，其实因为特别是就特别操作系统和它的那个系统库都提供了这个标准的流程给你去去调用的时候 ， 你肯定不要自己去搞 ，因为这样你自己去搞的话有可能和系统的不兼容嘛 。

**Eric** [1:54:38]
嗯 ，但是但是你就有刚才提到那个难题嘛 ， 就是说比如说在 macOS 这种比较特殊的呃系统上面 ， 它有多套 API 的时候 ， 你就很你就比较尴尬了 ，因为它有这个就是 Unicode Unix 那套比较底层的 API 和相对上 Foundation API 那些比较高层的 API 的时候 ， 那你怎么办 ？

就这个时候你肯定要把这两个的就是哪些是支持什么样的这个 normalization 的呃规范的可能搞清楚 ， 然后具体说怎么实现 ，其实你是不用去太多考虑的 ， 反正那些都是有有标准函数去去调用的嘛 。

**吴涛** [1:55:14]
对对对 ， 这个规范化的转换转换算法其实已经有一些非常标准的方式来实现 。

**Eric** [1:55:21]
唯唯一作为开发者你需要的知道的就是说 ， 你知道在什么时候用什么样的 API 去调用什么样的结果 。

**吴涛** [1:55:29]
嗯 。

**Eric** [1:55:29]
啊 ， 这个是比较重要的 。

**蒸鱼** [1:55:31]
嗯 ， 所以去查文档的话 ，其实肯定也就是说呃为了防防止发生这个 normalization 错误的话 ， 就是去调用很官方的 API 就完了 。

**Eric** [1:55:42]
对对对 。

### 域名安全

**吴涛** [1:55:43]
另外还有个事情跟我们今天讲的有点关系 ，是 Rio 上次提到的那个 IDN 的一个一个伪装攻击的问题是吗 ？

就一个网址的一个漏洞 。

**Eric** [1:55:55]
就 Punycode 那个的问题嘛 。

**吴涛** [1:55:57]
嗯哼 。

**Eric** [1:55:58]
啊 ， 这个是一个就也是 Unicode 的一个坑吧 ， 我们可以这里作为这个节目的就是事后的环节哈 ， 所以顺便顺便吐个小槽 ， 就是我们现在知道很多这个网站 ， 它有一种叫做什么就钓鱼网站嘛 ， 就它骗你 ， 它说它是这个啊这个银行某你的那个银行的网站 ， 然后让你输入你的这个卡号密码 ， 然后让你去转你的钱嘛 ， 对吧 。

那但可能银行这个例子不太好 ， 现在银行都有这个两步认证了 ， 可能也不太那么容易去做 ，但是呃逻辑是这样的 ， 就是那我们传统的在浏览器里面去判定一个网站是不是你访问的那个网站的时候 ， 你是看它的那个域名嘛 ， 对吧 ， 域名其实就是一个字符串构成的东西嘛 。

那坑就坑在于呃因为 Unicode 里面啊 ，也不叫这也不是 Unicode 的坑 ， 就是这个人类的人类的问题吧 ， 就是在某一些不同的语言里面 ， 它的两个完全不同的字符 ， 它看起来是一模一样的 。

**蒸鱼** [1:56:58]
嗯 ， 比如说英文的第一个字母叫 A， 对吧 ，但是希腊文的第一个字母叫 Alpha，但是两个大写字母长得一模一样 。

**Eric** [1:57:07]
对 ，在在过去不存在这个问题 ，因为在过去的话 ， 那个域名系统其实是一个非常简单的系统 ， 它就只有 ASCII， 就是它它只能用啊 ， 就是就是我们讲域名那个部分只能用哪几个呃字符 ，26 个英文字母不区分大小写啊 ，10 个阿拉伯数字 ， 然后再加一个那个横短横线 ， 对吧 。

**吴涛** [1:57:29]
嗯嗯嗯 。

**Eric** [1:57:30]
然后在这这个这个点呢 ， 肯定没得说了吧 ， 就是 A 就是 A 点 B， 这个是可以知道的 。 然后后来呢 ， 为了支持所谓的多语言的这个域名嘛 ， 啊我们中国以前搞过啊 ，CNSA 搞过所谓的中文域名 ， 对不对 ， 就是什么什么汉字域名 ， 对 ， 汉字域名什么什么点中国 ， 很很傻的 ， 之前应该是 90 年代末的时候有流行过一段时间 ， 然后之后就是谢天谢地

终于没有流行起来 ， 对吧 。 啊 ， 然后刚才讲的那个希腊文的那个 A 和英文那个 A 这个问题 ， 比如说你都想访问 apple.com， 就苹果的官网 ， 对吧 ， 那你看的是 apple.com，但其实人家把那个 A 给换成了那个希腊语的那个 A， 然后你看起来也是 apple.com，但是你访问的是一个完全不同的网站 ， 这个时候啊 ， 这个这个假的这个 apple.com 这个网站让你输入你的这个 iCloud 这个账号

密码 ， 你输不输呢 ？

**吴涛** [1:58:24]
哈哈哈 。

**Eric** [1:58:26]
对吧 ， 所以我觉得就是在域名这个呃这个比较关乎安全的这种领域里面 ， 我其实挺反对去加入这种多语言支持的 ， 虽然说听起来政治不正确 ， 凭什么域名一定要是一个英文的一个东西 ， 或者说就是对吧 ， 或者说 so， 呃其实也就拉丁文的东西嘛 ， 为什么韩国人不能用韩语做域名 ， 中国人不能用中文做域名 ， 日本人不能用日语做域名呢 ？

但是你用了之后就会出现这种不可知的结果嘛 ， 这个时候就比较尴尬了 。

**吴涛** [1:58:59]
嗯哼 。

另外我还有个问题 ，其实就是呃如果我们输入两个两个在这个呃标准化之后是相等的 Unicode 字符串 ， 那么浏览器会认为它们是同一个域名吗 ？

但是它们实际上是不一样的 。

**Eric** [1:59:19]
呃这里面好像有那个域名有一个叫 Punicode， 它是有一个规范的 ，但是这里要扯一个很很很坑爹的事情 ，Punicode 的规范是早于 Unicode 的 。

**蒸鱼** [1:59:29]
嗯 ，是的 。

**Eric** [1:59:31]
就会有一个转换的问题 。

**吴涛** [1:59:34]
对 ， 所以比如说我们刚才我们刚才说 ， 比如说有一些字母 ， 比如说像 Omega， 它就是两个完全一模一样的字符 ，在形式上 ，在这个语义的来源上也是一样 ，但它就是分裂成两两个字符了 ， 一个是用来表示这个物理单位的 ， 一个是 Omega 这个字符本身 。

**Eric** [1:59:52]
对 ， 这个我没有去查过 ，但是照我的理解应该是要先做那个 Unicode 规范化 ， 然后再转成那个 Punicode 才能拿到一个最终的一个结果 ， 然后这个时候应该是是一个唯一的一个一个结 ，但我不是 。

**蒸鱼** [2:00:07]
所以它们其实应该是一样的是 。

**Eric** [2:00:09]
我我的理解应该是一样的 ，不然的话就会出现刚才我说的另外一个问题 ， 就是你看见的两个完全一模一样的 ，而且你用 Unicode 看都是一模一样的哦 ， 或者 Unicode 都是等价的两个域名 ，但是它其实访问了两个不同的网站 ， 这个时候你就你就非常坑爹了 ， 对不对 ？

**吴涛** [2:00:23]
嗯嗯嗯 。

**Eric** [2:00:25]
当然呢 ， 这个事情可能可能也会越来越不是一个事了吧 ， 就是你其实我们现在看很多这个移动网站上， 你根本就不知道那个网址是什么了 ， 对不对 ， 比如说你在这个微信的浏览器里面打开一个网站 ， 你都看不见那个域那个 UR URL 了 。

**吴涛** [2:00:41]
对 ， 所以最终你可能还是得靠一些证书之类的东西 ， 就其他的一些工具来验证这个网站是不是你想要访问的 。

**Eric** [2:00:48]
对啊对啊对啊对啊对啊啊 ，但也会你认一个人总是不能看名字呀 。

**蒸鱼** [2:00:56]
这这就会变成另外一个很好很好玩的事情 ， 这个跟 emoji 有关了哈 ， 就是之前我前几天在那个 Twitter 上转发的一个事情 ， 就是现在那个浏览器它不是前面靠那个地址的左边有一个那个小锁的那个图标来表示这是一个加密链接吗 ？

**吴涛** [2:01:12]
嗯嗯嗯 。

**蒸鱼** [2:01:13]
对 ， 然后觉得你看上去觉得很安全嘛 ， 然后你知道那个 emoji 里面是有一个锁的图标的吗 ？

**吴涛** [2:01:19]
啊 ， 嗯嗯 。

**蒸鱼** [2:01:21]
然后然后然后那个有些那个有些那个域名的那个有些顶级域名是支持 emoji 域名的 ， 就刚才我们讲 Unicode 的 Punicode 的域名之外， 它还支持 emoji 的域名 ， 这个时候有人就说他做了一个他的那个域名的第一个就是一个锁啊 ， 你知道 ， 然后后面假设假设它是一个锁 ， 然后然后然后 HTTPS， 然后再两点斜杠斜杠 ， 然后是那个希腊字母的 A 的 APPL.com， 这个时候你你敢不敢访问

这个网站 ？

**Eric** [2:01:53]
哈哈哈 ， 对吧 ， 所以所以我觉得就是就是这怎么这可能有点不太正确哈 ，但是我觉得这个事情是是是有有得有得有所有些事情你是不能做的 ， 就像我说你不能在域名里面去加 emoji， 你不能在域名里面去加这个 Unicode 的东西 ， 这真的会把事情搞得无比复杂 ， 就是本来大家只用考虑大家刚才讲啊 ，26 个字母加 10 个数字再加一个横线 ， 才才多

少 ， 才 37 个 ， 对吧 ， 的一个一个那这个一个这个 space 的一个问题 ， 现在突然你变成一个整个 Unicode 的那个 space 都在那里 ， 那是多少倍的一个复杂度的扩张 ， 对于用户的认知理解来说 ， 你是没有办法去做这个教育的 。

**吴涛** [2:02:37]
嗯嗯 。

**Eric** [2:02:38]
所以你看中中国用户大家还是比较乖的 ， 大家刚才刚才这种数字域名就不会出现这种情况了 ， 对吧 ？

**吴涛** [2:02:44]
嗯嗯嗯 。

**Eric** [2:02:46]
163 点杠数字应该不会有这个长得一样的数字 ，但是不一样的点位吧 ？

**蒸鱼** [2:02:54]
有也有啊 。 数字的 normalization 不是很多吗 ？

**Eric** [2:03:00]
天呐 。 啊对 ，有那个什么半高的这种数字 ， 对不对 ？ 还有那个叫什么来的那个啊 。

**吴涛** [2:03:08]
另外罗马数啊 ， 那是罗马数字吗 ？ 就是罗马数字也是有罗马数字自己的码也可以 。

**蒸鱼** [2:03:14]
对 ，但我们一般都是用拉丁字母来写 ， 它们就用什么 IV 啊之类的字母 。

**Eric** [2:03:19]
对 ， 所以我就觉得嘛 ， 就是有些事情其实是都是一些政治的因素 ， 让我们把这个事情变得非常复杂 ， 本来技术是可以做得非常简单可靠稳定的 。

**吴涛** [2:03:28]
嗯 。

**Eric** [2:03:28]
但是一会过来一个 PM， 那会过来一个 PM 都在提这个需求 ， 这个时候你就爆炸了 。

**蒸鱼** [2:03:35]
对 ，其实说到这个 URL， 我想想就是其实 W3C 也是有一套自己的这个 normalization 的机制的 。

**Eric** [2:03:44]
哈哈哈 。

**蒸鱼** [2:03:46]
对 ， 就是当然它其实是基于 Unicode 的 ， 就是它当然它首先推荐的是 NFC 的这种标准化的形式 ， 规范化的形式 。

那么同时我们知道 ，因为 W3C 在网页上， 它其实有一个特殊的字符串形式叫 character reference， 就是以一个这个 epsilon 的和井号键开头的 ， 然后后面加一个数字的序列 ， 然后加一个加一个分号 ， 这样一个可以用来引用引用到任何一个 Unicode 字符上的这样一个序列 。

那么这个序列如果你在网页上在 HTML 里面输入的话 ， 它其实要被这个 normalize 的成为另外一个真正的实意的字符的 ，而不是直接保留这个东西 。

那么这个就就其实是在 Unicode 的基础上啊扩展了一下， 应该说 。

**Eric** [2:04:34]
那不就是那个 Punicode 吗 ？

**蒸鱼** [2:04:36]
啊 ， 可以这么说吧 ， 可以就机制是类似的 ， 可能是 ，但它们的表达形式不太一样 。

**Eric** [2:04:47]
这是一个挺沉重的事情 ， 我觉得就反正我我在在我的那个理解里面 ， 我是不介意 ， 就是我是反对把把一些就是其实你说一定有那么强的必要要用一个中文或者日文的域名吗 ？

其实也没有 ， 对不对 ， 大家不也过得很好吗 ？ 就为什么要人为把这个事情搞那么复杂 ？

**吴涛** [2:05:05]
哈哈哈

。

**Eric** [2:05:09]
就是太多的 downside 没有很好的这个 upside。

**蒸鱼** [2:05:15]
啊 ，但是对于这个网页来说 ，其实它有这些需求啊 ， 比如你输入一些不可见字符的时候 ， 你在 HTML 里面 ， 你可能输入这个 character reference 就变成可见了嘛 ， 那么对于程序员来说 ， 这个是比较友好的一种形式 。

**Eric** [2:05:29]
不 ， 我就说你不要在网页里面做这个 ，不要在那个那个域名和网址里面做这个事情嘛 。

**蒸鱼** [2:05:34]
对对对 ，在域名里面做的话 。

**Eric** [2:05:36]
就是要得有所节制 ， 你知道吗 ？ 就是现在很多很多这个忍不住啊 。 对 ， 技术技术产品之所以如此复杂 ， 就是因为上面提产提需求的人就是就是对吧 ？

### 结尾

**Eric** [2:05:50]
不考虑后果 。

**蒸鱼** [2:05:53]
好吧 ， 那今天我们就聊到这里 。

**Eric** [2:05:58]
对 。

**蒸鱼** [2:06:02]
嗯啊 ， 对了 ， 我们这次要抽 ， 我们这次就不抽奖了是吧 ？

**吴涛** [2:06:08]
啊 ， 对对对 ，但是我们其实上一次抽奖的结果已经出来了 ，但是有一位听众联系不到 。 哈哈哈 ， 所以其实那个呃 ， 我们可以借这次节目先做一个这个通知吧 。

**蒸鱼** [2:06:19]
啊 ， 那你说吧 。

**吴涛** [2:06:20]
对 ， 就是之前呢 ， 那个我们在第第十就上星期是第 51 期吧 ， 我们公布了一个抽奖的通知 ， 然后呢 ， 接下来的一周之后呢 ， 我们这个抽奖的结果其实已经出来了 。

那么我们这次抽到的两位听众呢 ， 都是来自支付宝捐赠的听众 。 第一位听众他的署名是灰 ， 一个灰黄的灰这个单字 。

第二位听众署名是 Friend， 那第二位听众呢 ， 我已经联系上他了 ， 那么他应该也已经收到了我们的奖品 ，但是第一位听众我没法联系到他 ， 所以如果你听到这期节目呢 ，也可以直接给我们发邮件 ， 发到 podcast@type.com 来跟我们联络 ， 然后我们会跟你进一步沟通 ， 然后把奖品发给你 。

**蒸鱼** [2:07:02]
好 ， 感谢大家的捐赠 ， 那别忘记了和我们的联系的方法呢 ，是 podcast@type.com 啊 ，有捐赠也就有机会参加我们的抽奖 。

我也今天啊 ， 我给大家准备了新的礼物 ， 那等我们下次再说吧 ， 好吧 ？

**吴涛** [2:07:18]
好 ， 那感谢大家收听今天的节目 。 如果大家喜欢我们的节目的话 ， 喜欢自弹自唱的话 ， 就可以给我们捐赠 ， 我们的捐赠渠道呢 ， 跟我们的邮箱地址是一样的 ， 都是 podcast@type.com，P-O-D-C-A-S-T at T-H-E-T-Y-P-E dot C-O-M。

同时呢 ， 大家也可以在社交网站上关注我们 ，在新浪微博 ，在 Twitter，在啊微信上面 ， 我们的 ID 都是 @type.com。 那么在 Facebook 上搜索 "Type is Beautiful" 也可以关注到我们 。

同时呢 ， 我们在知乎专栏上也会同步的发布每一期节目的这个节目简介 。 同时呢 ，也欢迎大家关注 Type is Beautiful 的网站 typebeautiful.com。

**Eric** [2:08:04]
啊 ， 感谢收听 IPN Podcast 网络旗下的 IT 技术主题娱乐节目 《 内核恐慌 》。 我们号称 hardcore，但是也没有干货 ， 想听的人听 ， 想听的人就别听 。

您可以为本节目捐款 ， 地址是 currentpanic.fm/donate。 捐款金额随意 ， 只要是 Bard 正常入贝就可以了 。 捐款不会给你带来什么 ，不捐也不会让你失去什么 。

我们的口号是 "No hard feelings"。 如果你有任何反馈 ， 可以发邮件到 current， 呃 ， 可以发电子邮件到 currentpanic@ipn.li。 同时也欢迎你收听 Rio 主持的 《 疯投圈 》。

哎 ，《 疯投圈 》 现在好像改成收费节目了 。

**蒸鱼** [2:08:39]
呃 ， 对 。

**Eric** [2:08:40]
OK。

**吴涛** [2:08:41]
啊 ， 我还加了会员 。

**Eric** [2:08:42]
旗下的其他几档节目未知道 ， 太一来了 ， 流星通信 、High Story、 硬影像 、 吴思源 、 薄雾志 、 玄美 、 碧霞关 、 一天世界 、 时尚怪物 ， 我们下期节目再会 。

**蒸鱼** [2:08:52]
OK， 拜拜 。

**Eric** [2:08:53]
拜拜 。

**吴涛** [2:08:54]
拜拜 。

**Eric** [2:08:55]
拜拜

。

---

本节目库由 PodHood（https://podhood.com）提供支持——播客网站平台。
