使用方法
- 把要转换的文本粘进文本框,上限 20 万码元。页面打开时框里已经预置两行示例:第一行
straße fußball café résumé,第二行istanbul ısparta izmir,共 2 行、49 个码点、7 个词。 - 选「转换节拍」。全大写调用
toUpperCase(),全小写调用toLowerCase(),首字母大写按空白切词后把每个词的首字母转大写、其余字母转小写(连空格原样保留)。 - 选「语言环境 locale」。默认的 Unicode 映射下示例第二行是
ISTANBUL ISPARTA IZMIR;切到tr会变成İSTANBUL ISPARTA İZMİR,因为土耳其语里i的大写是İ(U+0130),不是I(U+0049)。 - 按需勾选「转换前先做 NFC 归一化」(默认勾选)。从 macOS Finder 或某些编辑器复制的文本常用分解形式,
é会存成e加 U+0301 两个码位,不归一直接大写得到E加 U+0301;归一后是一个码位 U+00C9。 - 点「转换大小写」,或在文本框里按 Ctrl + Enter 重算。结果上方四张卡给出行数、输入码点数、输出码点数与码点变化——示例在全大写下输出 51 个码点,比输入的 49 多 2,来源是两个
ß各自展开成SS。
这个字母转大写工具能解决什么问题
一是批量统一常量、枚举与缩写。SQL 关键字、配置项键名、错误码前缀常常要求全大写,一段一段手改容易漏;这里一次转换,并且能立刻从「码点变化」卡片看出有没有 ß 这类会变长的字符混进来。
二是在付印或入库前查出长度会变的行。德文地址里 Straße 转成 STRASSE 会多出一个字符,如果下游字段按原长度截断就会被切掉尾巴。本页把 +2 这种变化直接显示在结果上方,不用自己去数。
三是处理土耳其语这种带点 i 的语言。默认映射下 i 大写是 I,而土耳其语要求 İ;反过来 I 转小写是 ı(U+0131)。做跨国站点的数据清洗时,这个差别会让字符串匹配直接失败,切到 tr 就能看到正确结果。
四是把大小写不敏感的比较做对。比较前应该先统一成同一档;但要注意 ß 大写变 SS、ẞ 小写变 ß 都不是等长替换,靠大写来对齐长度会出错,比较请用小写档。
本页不做这些事:不做标题式大小写(把 a、an、the、of 这类小词留在小写,那是英文标题大小写转换的活);不生成驼峰、帕斯卡、蛇形命名(见驼峰大小写转换器);不做拼写检查与词形还原;也不判断某个词是不是专有名词。
原理与规则说明
这个字母转大写工具的核心只有三个原生方法:String.prototype.toUpperCase()、String.prototype.toLowerCase() 和带参数的 toLocaleUpperCase(locale),外加可选的 String.prototype.normalize('NFC')。按 ECMA-262 的规定,toUpperCase() 必须按 Unicode 的默认大小写映射逐码位替换,而且允许结果与输入长度不同——它不是 ASCII 时代那种减 32 的字节运算。
为什么不默认传 locale。不传参数时走的是 Unicode 默认映射,与语言无关,在任何浏览器、任何版本上结果都一样,可以被测试锁死;传 'tr' 之后结果依赖运行环境的 ICU 数据版本,同一段文本在不同浏览器上可能出现细微差别。所以本页把 locale 做成显式选项:只在明确要处理土耳其语(或立陶宛语)时才切,常规英文、德文、法文一律用默认档。实测 i 在默认档大写为 U+0049,在 tr 档大写为 U+0130;I 在 tr 档小写为 U+0131。
遵循的两份 Unicode 数据。一对一的部分来自 UnicodeData.txt 的简单大小写映射(simple case mapping),一对多的部分来自 SpecialCasing.txt 的完整大小写映射(full case mapping)。ß 之所以变成两个字母 SS,就是 SpecialCasing.txt 里的无条件映射条目,不是工具的自由发挥。ASCII 段依然规整:a(U+0061)与 A(U+0041)相差 32,26 个小写字母全部会变。
输入到输出的中间量。文本先按 \r\n|\r|\n 拆成行数组;全大写、全小写直接对整行调用对应方法;首字母大写则按 (\s+) 切词并保留空白片段(所以连续空格与制表符原样保留),逐词把首字符转大写、剩余部分转小写,最后用 \n 拼回。整条链路不触碰换行,输入几行输出就是几行。
阈值与规模(均为实测,非估算)。文本上限 20 万 UTF-16 码元,超出直接提示分批,不做截断。对 BMP 全部 63488 个非代理码位扫描:toUpperCase() 后与自身不同的有 1273 个,其中长度大于 1 的一对多映射有 102 个。示例文本 49 个码点、43 个拉丁字母,全大写后 51 个码点,差值为 2,正好等于两个 ß 的贡献。
最常见的误用是把「转大写」当成可逆操作。ẞ(U+1E9E)转小写得到 ß(U+00DF),再把 ß 转大写得到 SS——回不到原来的 ẞ。同理 İ 转小写会散成 i 加 U+0307 两个码点。要保留原始写法,就只转一次并保存原始文本,不要来回倒。
完整示例(数值均为实测)
示例是页面上的两行文本:straße fußball café résumé 与 istanbul ısparta izmir,输入 49 个码点。下表是三种节拍与两种 locale 组合后的实测输出与码点数,可以直接和结果区对照。
| 节拍 / locale | 输出(两行) | 码点数 |
|---|---|---|
| 全大写 / 默认 | STRASSE FUSSBALL CAFÉ RÉSUMÉ ISTANBUL ISPARTA IZMIR | 51(+2) |
| 全大写 / tr | STRASSE FUSSBALL CAFÉ RÉSUMÉ İSTANBUL ISPARTA İZMİR | 51(+2) |
| 全小写 / 默认 | straße fußball café résumé istanbul ısparta izmir | 49(0) |
| 首字母大写 / 默认 | Straße Fußball Café Résumé Istanbul Isparta Izmir | 49(0) |
| 首字母大写 / tr | Straße Fußball Café Résumé İstanbul Isparta İzmir | 49(0) |
只有「全大写」这一档会变长:straße 变 STRASSE、fußball 变 FUSSBALL,各贡献 +1,合计 +2。其余节拍对这段输入不改变码点总数。切到 tr 之后变化的只是第二行的三个 i:istanbul 变成 İSTANBUL、izmir 变成 İZMİR,码点数仍是一个对一个,总数不变。
输入范围与对照表
输入范围与处理边界:
- 长度上限 20 万 UTF-16 码元;示例的 49 个码点只占上限的 0.0245%。超限时给出提示并停止转换,不截断已有内容。
- 按行处理,行数不变。换行是行分隔符,不会变成空格;空行保留。
- 空白原样保留。与「按空格压成一个」的排版型工具不同,本页只替换字母的码位,多个连续空格、制表符都不动。
- 中文、数字、标点不参与转换。汉字没有大小写,原样输出;只有夹杂的拉丁字母、希腊字母会被替换。
- NFC 归一化只合成、不拆解。它把
e加 U+0301 合成 U+00E9,不会把已经预组合的字符拆开。
不同输入元素走的是不同映射通道,下面这张表是处理口径的实测对照:
| 输入元素 | 处理方式 | 码点是否变化 | 实测示例 |
|---|---|---|---|
| 拉丁小写字母 | 按简单大小写映射逐个替换 | 不变(26 个字母全变) | a → A,码点差 32 |
| 德文 ß | 按完整大小写映射展开 | +1 | straße → STRASSE |
| 预组合 é | 一对一替换 | 不变 | café → CAFÉ |
| 分解形式 e + U+0301 | 勾选 NFC 后先合成再替换 | 减少 1(勾选时) | café 由 5 码位降到 4 码位 |
| 汉字与中文标点 | 不在映射表内,原样保留 | 不变 | 字母转大写 → 字母转大写 |
| 换行与连续空格 | 按行处理,空白原样保留 | 不变 | 2 行输入仍是 2 行 |
| 数字与半角标点 | 无大小写映射,原样输出 | 不变 | 2026 → 2026 |
结果边界与 Unicode 映射的坑
- 长度会变,且只在大写方向变。示例全大写 +2,因为
ß展开成SS;反过来SS转小写仍是ss,不会自动变回ß。小写方向也会变长的例子是İ(1→2)。 - 102 个码位是一对多映射。对 BMP 全部 63488 个非代理码位扫描,大写后长度大于 1 的有 102 个,大写后与自身不同的共 1273 个。如果你的文本里有希腊语带调符字符,
ΐ这种会一次多出两个码点。 - 大写不保证可逆。
ẞ→ß→SS,回不到ẞ。需要保留原文就别来回转换。 - 不要拿大写结果做长度对齐或截断。下游字段若按输入长度截取,
Straße变STRASSE后会被切尾;先转换再算长度。 - locale 只在你明确需要时切换。切到
tr后,英文里正常的i也会变成İ,混排文本会因此出现意料外的字符。默认档对英文、德文、法文都是正确且可复现的。 - NFC 归一化改变的是码点数而不是字形。勾选后
café从 5 个码位(分解形式)变成 4 个,显示效果相同,但字符串长度、索引与正则匹配都会随之改变。 - 中文不受影响。汉字不在大小写映射表里,代码块里的中文注释、标点全部原样保留。
常见问题
为什么转换后字符数变多了?是不是出错了?
没有出错。ß(U+00DF)按 Unicode 完整大写映射要展开成 SS,一个字符变成两个,这是 SpecialCasing.txt 的规定。示例里有两个 ß,所以全大写后从 49 个码点变成 51 个,结果区上方的「码点变化」卡片显示 +2。
locale 选 tr 到底改了什么?什么场景才需要?
只改带点的 i 这一组:默认档 i 大写是 I(U+0049),tr 档是 İ(U+0130);I 转小写默认档是 i,tr 档是 ı(U+0131)。处理土耳其语人名、地名、站点数据时才需要;英文文本切过去反而会得到 İSTANBUL 这种混排结果。
「转换前先做 NFC 归一化」什么时候必须取消勾选?
当你在检查文本的归一化状态时不要勾:勾上会把分解形式合成预组合形式,文本本身被改写,你就看不出原始输入是不是 NFD 了。正常做转换、要入库或要交给下游系统时保持勾选,能保证 é 是一个码位而不是两个。
「首字母大写」和英文标题大小写转换有什么不一样?
本页的首字母大写是逐词机械处理:每个词首字母转大写、其余转小写,不认识小词,所以 the quick brown fox 会得到 The Quick Brown Fox。标题式会把 a、an、the、of、in、on、and、or、to 这类小词留在小写,那是英文标题大小写转换的规则。
能把大写后的文本还原成原来的大小写吗?
大多数字符可以,但有几个不可逆:ẞ 转小写是 ß,再转大写得到 SS 而不是 ẞ;İ 转小写散成 i 加 U+0307。大小写信息在转换时就被丢弃了,需要保留原文请另存一份。
为什么 İ 转小写后字符数从 1 变成 2?
因为 İ(U+0130)的小写映射是 i 加上组合用上点 U+0307,共两个码位。这是 Unicode 里少数「小写方向变长」的条目,和 ß 在大写方向变长是同一类现象。
输入上限是多少,超了会怎样?
上限 20 万 UTF-16 码元。超限时结果区清空并在错误区提示当前码元数与 20 万上限,让你分批转换,不会静默截断——截断会让你误以为文本已经全部处理完。
我的文本会被上传到服务器吗?中文内容会受影响吗?
不会上传,转换全部由浏览器原生字符串方法完成,不发任何网络请求,可以在开发者工具的 Network 面板自查。中文字符没有大小写映射,原样输出;只有拉丁、希腊等有大小写之分的字母会被替换。
相关工具
- 字母转小写:只做整段转小写这一件事,做大小写不敏感比较前统一口径时更直接。
- 英文标题大小写转换:按小词表做标题式大小写,适合文章标题与栏目名。
- 驼峰大小写转换器:转成 camelCase,适合变量名与函数名。
- Pascal命名转换:转成 PascalCase,常用于类名与组件名。
- Snake大小写转换器:转成 snake_case,数据库字段名与配置文件常用。
- 每行首字母大写:只把每一行第一个字母大写,不逐词处理,适合名单与地点列表。
- 文本工具:查看全部文本工具。