学习这个知识点的背景是,我需要做一个 在canvas 上书写矢量文本的功能, 使用opentype来加载字体文件,并将内容转换为 svg,导入画布。 但是有些字体文件 是不包含 一些其他语言的字符的。就可能出现 “无效字符”。
花了点时间研究字体文件与语言系统,以及字符编码 之间的关系和逻辑。
你的问题非常关键,也是多语言文本渲染中经常遇到的核心难点。我们来逐步拆解 “Unicode 范围”、“字符”、“字体分类” 这几个概念,帮你建立一个完整清晰的理解框架。
Unicode 是一个全球字符集标准,目的是为所有语言中的所有字符分配一个统一的编码。它把 字符按照功能、语言或书写系统划分为“区段”,每个区段就是一个 Unicode 范围。
比如:
Unicode 范围 | 字符示例 | 用途 |
---|---|---|
U+0041 - U+007A | A-Z, a-z | 拉丁基本字母 |
U+0400 - U+04FF | А-Я, а-я | 西里尔字母(俄语、乌克兰语等) |
U+4E00 - U+9FFF | 中、国、文 | 常用汉字 |
U+0370 - U+03FF | Α, β, γ | 希腊字母 |
U+00C0 - U+00FF | À, ç, ñ | 拉丁扩展-A(法语、西语等变音) |
U+1F600 - U+1F64F | 😀, 😢 | Emoji |
所以 你不需要按“语言”去处理字体,而是按“字符属于哪个 Unicode 范围”来选对应字体。
一个字体(.ttf
或 .otf
)并不会支持所有 Unicode 字符,而是只包含 一部分字符的字形(glyph)。
我们可以这样理解:
字体的支持范围可以通过工具查看,如:
opentype.js
中的 font.tables.cmap
也能拿到它支持的字符编码范围你可以在处理每一个字符时:
char.codePointAt(0)
)比如伪代码如下:
function pickFontForChar(char) {
const code = char.codePointAt(0);
if (code >= 0x4E00 && code <= 0x9FFF) {
return chineseFont;
} else if (code >= 0x0400 && code <= 0x04FF) {
return cyrillicFont; // 俄语
} else if (code >= 0x00C0 && code <= 0x00FF) {
return latinExtendedFont; // 法语、西语等
} else {
return defaultLatinFont; // 基础英文
}
}
你也可以加载 Noto Sans
系列作为 fallback 字体,它们专门是 Google 推出的覆盖全球字符集的字体库系列。
如果你希望我帮你写一个完整的「多字体混排渲染方案」的封装,也可以继续问我,我们可以用 opentype.js
封装一个智能的渲染器 🔧。
有没有哪个部分你还想深入了解?比如字体 fallback 的具体实现?还是想看看如何自动判断某个字体能不能显示某个字符?我可以给你写工具函数 👍
这是个很棒的问题!要理解“Unicode 范围”,我们需要从字符编码和字体的本质谈起。下面我会从 字符、Unicode、Unicode Block(范围)、字体 的关系入手,带你一步步梳理清楚这个概念。
“字符”就是你能看到、输入、打印的那些东西:
A
,你
,Ω
,é
,中
,𠮷
,😀
…
每个字符在计算机中都有一个数字编码 —— 就是 Unicode 编码。
Unicode 是一个全球统一的字符编码标准,为每个字符分配一个独一无二的编号(叫 code point)。
比如:
字符 | Unicode 编码(十进制) | 十六进制 |
---|---|---|
A | 65 | 0x0041 |
你 | 20320 | 0x4F60 |
é | 233 | 0x00E9 |
Я | 1071 | 0x042F |
😀 | 128512 | 0x1F600 |
为了管理这么多字符,Unicode 把字符按用途或语言进行分组,称为Unicode Block(字符块、范围)。
举例:
范围名称 | 编码范围(十六进制) | 用途 |
---|---|---|
Basic Latin | 0000–007F | 英文、数字、标点 |
Latin-1 Supplement | 0080–00FF | 西欧语种的扩展字符(é ñ ç 等) |
Cyrillic | 0400–04FF | 俄语等斯拉夫语 |
Arabic | 0600–06FF | 阿拉伯语 |
CJK Unified Ideographs | 4E00–9FFF | 中文、日文汉字、韩文汉字 |
Emoji | 1F600–1F64F | 表情符号 |
完整列表可以参考: 🔗 https://www.unicode.org/Public/UCD/latest/ucd/Blocks.txt
字体是字符形状的集合,每种字体内部包含一部分字符的形状(glyph)。
你想渲染一个字符串 "Hello 世界 😀"
:
H, e, l, o
属于 Basic Latin
,用 Roboto
世, 界
属于 CJK Unified Ideographs
,用 Noto Sans SC
😀
属于 Emoticons
,用 Noto Emoji
截至 Unicode 15.1,大约有 330+ 个 Unicode 块。每个块覆盖一类字符,具体数量会随着版本更新不断增加。
你可以查看官方完整列表: 🔗 https://unicode.org/charts/
字符 (char)
└─ 编码(Unicode code point)→ 属于某个 Unicode Block
└─ 某些字体覆盖这个 Block
└─ 渲染时判断用哪个字体 fallback
如果你想要,我可以为你写一个 Unicode Block 检测器,输入一个字符就能告诉你它属于哪个范围,用来动态选字体。要不要来一个?
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有