字符串长度计算器
粘贴字符串后,该工具会从四个不同维度显示其长度:JavaScript 风格的 .length(UTF-16 编码单元)、Unicode 代码点、字素簇(用户感知为单个字符)以及 UTF-8 字节(数据库列实际存储的内容)。对于包含表情符号、旗帜或组合标记的字符串,这些数值会互不相同,而这种差异正是诸多 bug 的根源。
字符串长度的四种含义
-
1
UTF-16 代码单元
`str.length` 在 JavaScript 中返回的值:大多数字符返回 1,超出 U+FFFF 范围的代码点(如表情符号、古文字)则返回 2。
-
2
代码点
每个 Unicode 标量对应一个。表情符号各占 1 个;而 ZWJ 序列则包含多个。
-
3
字素簇
用户所称的“一个字符”。`🇺🇸` 包含 2 个代码点,但对应 1 个字素;`n̈` 同样包含 2 个代码点,但对应 1 个字素。
-
4
UTF-8 字节
数据库存储的内容:ASCII 字符各占 1 字节;常用欧洲字符占 2 字节;CJK 占 3 字节;大多数表情符号占 4 字节。
示例
| 字符串 | JS .length | 代码点 | 字素 | UTF-8 字节 |
|---|---|---|---|---|
hello |
5 | 5 | 5 | 5 |
café |
4 | 4 | 4 | 5 |
😀 |
2 | 1 | 1 | 4 |
🇺🇸 |
4 | 2 | 1 | 8 |
👨👩👧(家庭) |
8 | 5 | 1 | 18 |
n̈(n + 分音符) |
2 | 2 | 1 | 3 |
为什么数字会不一样
JavaScript 字符串采用 UTF-16 编码,因此超出 U+FFFF 范围的代码点会以代理对形式存储,即两个 UTF-16 代码单元,例如 "😀".length === 2。用户对此颇有微词,因为他们把 😀 看作一个独立字符。
字素的定义则更进一步:国旗实际上由两个表示地区标识的代码点组合而成,但用户会将其视为单一旗帜。例如 JavaScript 中的 "🇺🇸".length === 4,听起来有些荒谬,但事实如此。若需遍历字素,可使用 Intl.Segmenter(现代方案)、grapheme-splitter 库,或手动处理。
UTF-8 字节:你的数据库实际存储的内容
对于类型为 VARCHAR(255) 的列:
- 在 MySQL
utf8(实际为 utf8mb3)中,255 指的是字节数;而café占用 5 字节,因此可存储 51 个副本。 - 在 MySQL
utf8mb4(真正的 UTF-8,包含表情符号)中,仍然以字节计数,但其编码支持 4 字节序列。 - 在 Postgres
VARCHAR(255)中,255 表示字符数(代码点),而非字节。 - 在 SQL Server
VARCHAR中,计数方式因排序规则(collation)而异;NVARCHAR则按 2 字节的 UCS-2 单元计数。
若按用户可见的字符上限来设置数据库字段大小,在 UTF-8 列中建议使用“字节数 × 4”作为安全系数,每个字素的每个代码点最多可占用 4 字节,而 ZWJ 序列还会占用更多空间。
Twitter 风格的字符计数
Twitter 按自定义规则统计推文:以代码点为单位,但表情符号和 CJK 表意文字各计为 2。纯 ASCII 的推文最多可包含 280 个字符;而使用 140 个表情符号的推文上限仅为 140 个“字符”。
短信字符计数:GSM 7 位编码下上限为 160 个字符。一旦使用非 GSM 字符(如 á、é、ñ 或表情符号),编码就会切换为 UCS-2,消息长度随之降至 70 个字符。
实际应用
- 数据库列大小设置,在编写迁移脚本前,先检查字节数。
- API 配额限制,大多数 API 以字节而非字符为计量单位。
- 表单验证,向用户显示与其预期相符的准确字符数(字素)。
- 性能调试,这条正则表达式为什么遍历得这么慢?因为输入在代码单元上的长度是字素长度的 3 倍。
常见问题
该表情符号是由多个代码点组成的 ZWJ 序列(例如家庭表情符号由 7 个代码点构成)。Twitter 根据 Unicode 权重规则将其计为 2 个字符,而你的编辑器则显示为 1 个字素。两者在技术上都正确,只是衡量的对象不同。
在 UTF-8 数据库中,为确保安全,建议按每个预期字符 4 字节来预留。包含 100 个字符(字素)的字段应设为 VARCHAR(400) 字节;若数据库像 Postgres 那样按字符计数,则使用 VARCHAR(100) 并配合相应的字符集处理。
在 JavaScript 中,这取决于规范化形式。NFC 组合形式(U+00E1)长度为 1;NFD 分解形式(U+0061 + U+0301)长度为 2。可见字符相同,但字节序列不同。
家庭和职业类表情符号由很长的 ZWJ 序列组成。不完全支持这些序列的字体会把每个代码点分别渲染为独立字形,因此 👨💻 会显示为 👨+💻。升级操作系统字体即可解决此问题。
相关工具
小于或等于符号
复制 ≤ 符号及相关数学比较符号。包含适用于电子表格、论文和网页的 Unicode、HTML 实体及 LaTeX 标记。
可复制的箭头符号
一键复制常用 Unicode 箭头:直线、双线、斜向、钩形、环形和三角样式,适合文档、聊天和设计。
泰语数字转文字工具
在浏览器本地将最多 18 位数字写成泰语,或用 ASCII 数字或泰文数字将准确的泰铢和萨当金额写成文字,不进行舍入。
象形文字翻译器
用古埃及书吏表示单个读音的符号,把你的名字拼写成埃及象形文字。可以加上王名圈,复制符号或下载 PNG 图片。
Instagram字体生成器
生成Unicode字体样式(粗体、斜体、手写体、等宽体、花体),可直接粘贴至您的Instagram个人简介、姓名、配文及评论中。
城市名生成器
为世界观构建、地图、游戏、故事和模拟数据生成虚构的城市、城镇、村庄和首都名称,每个结果均附简短说明。
此工具还提供其他语言版本
- Stränglängdsberäknare [SV]
- Công cụ tính chiều dài chuỗi ký tự [VI]
- Zeichenlängenrechner [DE]
- Kalkulator Panjang String [ID]
- 文字列長計算ツール [JA]
- Kalkulator długości ciągu znaków [PL]
- مقياس طول السلسلة النصية [AR]
- Calculadora de Comprimento de String [PT]
- Calculadora de Longitud de Cadenas [ES]
- Calculateur de longueur de chaîne [FR]
- 문자열 길이 계산기 [KO]
- Stringlengteberekenaar [NL]
- เครื่องคำนวณความยาวของสตริง [TH]
- String Length Calculator [EN]
- Calcolatore della lunghezza della stringa [IT]
- Калькулятор длины строки [RU]
- Dize Uzunluğu Hesaplayıcı [TR]