最后更新:
全角与半角的区别 - 对字符计数的影响详解
全角半角转换工具
粘贴文本,即可将英文字母、数字、片假名、标点符号和空格在全角与半角之间即时互转。转换完全在浏览器中完成,输入内容不会发送到服务器。
平假名、汉字和 emoji 不会被转换。波浪号 〜 (U+301C) 也保持原样,只有全角波浪线 ~ (U+FF5E) 会被转换。
转换工具的使用方法
只需三步:(1) 将文本粘贴到输入框,(2) 选择转换方向 (全角 → 半角,或反向),(3) 用复选框指定转换对象 (英文字母和数字、片假名、标点符号、空格)。结果随输入实时更新,无需点击转换按钮。点击"复制结果"即可将转换后的文本用于表单填写或 CSV 数据整理。将结果粘贴到字符计数器,还可以分别查看全角和半角字符的数量。
哪些字符会被转换,哪些不会
本工具不使用 NFKC 之类的一揽子标准化,而是仅依据明确的对照表,转换全角字符与半角字符之间存在一一对应关系的字符。
- 英文字母和数字:A-Z、a-z、0-9 ⇔ A-Z、a-z、0-9
- 片假名:全角片假名 ⇔ 半角片假名,浊音符号和半浊音符号会自动合成与分解 (ガ ⇔ ガ、パ ⇔ パ、ヴ ⇔ ヴ)。长音符 ー ⇔ ー 和小写假名 (ァィゥ 等) 也在转换范围内
- 标点符号:!#%? 等全角符号 ⇔ 对应的半角 ASCII 符号,另外还包括源自半角片假名区块的 。「」、・ ⇔ 全角形的句点 (U+3002)、直角引号 (U+300C / U+300D)、顿号 (U+3001) 和间隔号 (U+30FB),以及日元符号 ¥ (U+FFE5) ⇔ ¥ (U+00A5)
- 空格:全角空格 (U+3000) ⇔ 半角空格 (U+0020)
另一方面,平假名、汉字、emoji (包括 ZWJ 组合序列) 和组合字符在任何方向都不会被改动。下文"灰色地带字符"中介绍的波浪号 〜 (U+301C) 与全角波浪线 ~ (U+FF5E) 是不同的字符,因此被有意排除在转换范围之外。没有半角形式的片假名 (ヰ、ヱ、ヵ、ヶ 等) 也会保持原样。
什么是全角和半角
全角 (Full-width) 和半角 (Half-width) 的概念源于等宽字体时代。全角字符占据一个完整的字符宽度,半角字符占据一半的宽度。按 East Asian Width 属性,各类字符的归属如下。
- 平假名 あ、い、う、え、お / 片假名 ア、イ、ウ、エ、オ / 汉字 文、字、数 —— W (Wide)
- 全角标点 (句点 U+3002、顿号 U+3001、直角引号 U+300C / U+300D、间隔号 U+30FB 等) —— W (Wide)
- 全角英数字 A、B、1、2 —— F (Fullwidth,ASCII 的全角兼容形)
- 半角英文字母 A、B、C / 数字 1、2、3 / 符号 !、@、#、$ —— Na (Narrow)
- 半角片假名 ア、イ、ウ —— H (Halfwidth,不推荐使用)
| 类别 | 全角示例 | 半角示例 | 说明 |
|---|---|---|---|
| 英文字母 | A B C | A B C | 全角英文字母在日常使用中较少见 |
| 数字 | 1 2 3 | 1 2 3 | 全角数字在正式文档中偶尔使用 |
| 片假名 | ア イ ウ | ア イ ウ | 半角片假名在旧系统中常见 |
| 标点符号 | 。 、 ! | . , ! | 中日文通常使用全角标点 |
| 空格 | (U+3000) | (U+0020) | 全角空格宽度是半角的两倍 |
中文汉字、日文平假名和片假名天然就是全角字符,没有对应的半角形式 (半角片假名除外)。而英文字母和数字既有全角形式也有半角形式。
半角片假名之所以被视为"不推荐使用",原因出自 JIS X 0201 规范。1969 年制定的这一规范为了把片假名装进 7 位 / 8 位有限的编码空间,把浊音符号 (゙) 与半浊音符号 (゚) 定义为独立字符。其结果是"ガ"会以"ガ"的形式被计为 2 个字符。即使施加 Unicode 的 NFC 标准化,半角片假名的浊音符号也不会被合成,容易造成字数统计不一致,因此除有特别理由外都应使用全角片假名。
Unicode 如何定义全角与半角 —— East Asian Width 属性
"全角"和"半角"这两种叫法源自日语圈,但在 Unicode 规范中有正式定义,即 UAX #11 (Unicode Standard Annex #11: East Asian Width)。每个码位都会被赋予以下 6 种宽度属性之一。
- F (Fullwidth):全角形字符。ASCII 的全角版 (A、1 等,U+FF01~U+FF60)
- H (Halfwidth):半角形字符。半角片假名 (ア、イ 等,U+FF61~U+FF9F)
- W (Wide):在东亚环境中占宽幅的字符。CJK 统一汉字、平假名、片假名等
- Na (Narrow):在东亚环境中占窄幅的字符。基本拉丁字母 (A~Z) 等
- A (Ambiguous):宽度随上下文变化的字符。希腊字母、部分西里尔字母等
- N (Neutral):东亚环境中不使用的字符
日常被称作"全角"的字符同时包含 F 和 W,"半角"则包含 H 和 Na。尤其需要留意 A (Ambiguous) 这一类,它会随终端和编辑器的设置既可能显示为 1 个字符宽,也可能显示为 2 个字符宽。例如"α" (希腊小写字母 alpha) 在 Windows 命令提示符中显示为全角宽度,而在 macOS 终端中有时显示为半角宽度。
JIS X 0201 与 JIS X 0208 —— 全角半角的历史由来
全角与半角之分,与日本字符编码规范的发展密切相关。1969 年制定的 JIS X 0201 在 ASCII 兼容的 7 位编码之外,把 63 个半角片假名收录进 8 位区域。那是 1 个字符 = 1 字节的世界。
1978 年制定的 JIS X 0208 定义了包含 6,349 个汉字的大规模字符集。1 字节只能表示 256 种取值,因此需要 2 字节的编码空间。正是这种"单字节字符"与"双字节字符"在物理尺寸上的差异,在等宽字体环境中被可视化为"半角"与"全角"的显示宽度之别。
换言之,"全角 = 2 字节"在 Shift_JIS 和 EUC-JP 这类编码中曾经是事实,但在 UTF-8 成为主流的今天已不再成立。尽管如此,这个等式依然根深蒂固,原因是日本 IT 行业在 1990~2000 年代建成的许多系统都以 Shift_JIS 为前提。
全角半角对字符计数的影响
不同平台和系统对全角半角的计数方式不同,这是造成字数统计混乱的主要原因。
| 平台/系统 | 计数方式 | "A" 的计数 | "A" 的计数 |
|---|---|---|---|
| Unicode 字符数 | 每个码点 = 1 | 1 | 1 |
| UTF-8 字节数 | 按字节计算 | 3 字节 | 1 字节 |
| Shift_JIS 字节数 | 按字节计算 | 2 字节 | 1 字节 |
| X (Twitter) | 加权字符 | 1 | 1 |
| 某些日本系统 | 全角=2,半角=1 | 2 | 1 |
特别需要注意的是,某些日本的传统系统 (银行、政府机构等) 仍然使用"全角 = 2 字节、半角 = 1 字节"的计数方式。在这些系统中,"ABC" (半角) 计为 3,而"ABC" (全角) 计为 6。
以"Hello 世界"为例,同一段文本在不同计数方式下的结果如下。
| 计数方式 | "Hello 世界"的结果 |
|---|---|
| Unicode 字数 (通用) | 7 个字符 |
| 字节数 (Shift_JIS) | 9 字节 (5+4) |
| 字节数 (UTF-8) | 11 字节 (5+6) |
| 字节数 (UTF-16) | 14 字节 (全部字符 × 2) |
把主要平台在全角半角计数上的差异也掌握清楚,在实务中很有帮助。
| 平台 | 计数方式 | 全角的处理 |
|---|---|---|
| X (原 Twitter) | 自有的加权方式 | 日文 1 个字符 = 2 个字符份 (280 字符中占 140 字符份) |
| LINE | Unicode 字数 | 全角与半角均为 1 个字符 |
| SMS | 取决于编码 | 日文每条最多 70 个字符 (UCS-2) |
| MySQL VARCHAR(n) | 字数 (utf8mb4) | 全角与半角均为 1 个字符 (但另有字节上限) |
| Oracle VARCHAR2(n BYTE) | 字节数 | UTF-8 下全角 1 个字符消耗 3 字节 |
| Google Ads (标题・描述) | 自有的换算方式 | 全角 1 个字符按 2 个字符计 (2026 年 8 月时点) |
这张表真正想说明的是,同一个"1 个字符"在各种方式下指的并不是同一件事。按码位计数的方式与把全角折算成 2 个字符的方式同时存在,因此在贴着上限写的稿件里,明明本地数着刚好够,到了投稿前的最后一步却突然不够了。写作之前先确认目标平台采用哪一种方式,是最省事的做法。
本站的字符计数器会分别显示全角与半角各自的字数,因此两种方式都能应对。
UTF-8 编码下的字节数差异
在现代 Web 开发中最常用的 UTF-8 编码下,全角和半角字符的字节消耗差异显著。了解字符数与字节数的区别对于数据库设计和 API 开发至关重要。
| 字符类型 | UTF-8 字节数 | 示例 |
|---|---|---|
| 半角英数字 | 1 字节 | A, 1, @ |
| 全角英数字 | 3 字节 | A, 1 |
| 中文汉字 | 3 字节 | 中,文 |
| 日文平假名 | 3 字节 | あ, い |
| 半角片假名 | 3 字节 | ア, イ |
| 全角标点 | 3 字节 | 。、! |
| 半角标点 | 1 字节 | . , ! |
各编码下的字节大小对比
即使是同一个字符,字节数也会因编码而大不相同。下表对比了代表性字符在各编码下的字节大小。
| 字符 | UTF-8 | UTF-16 | Shift_JIS | EUC-JP |
|---|---|---|---|---|
| A (半角英文字母) | 1 字节 | 2 字节 | 1 字节 | 1 字节 |
| あ (平假名) | 3 字节 | 2 字节 | 2 字节 | 2 字节 |
| 漢 (汉字) | 3 字节 | 2 字节 | 2 字节 | 2 字节 |
| A (全角英文字母) | 3 字节 | 2 字节 | 2 字节 | 2 字节 |
| ア (半角片假名) | 3 字节 | 2 字节 | 1 字节 | 2 字节 |
| € (欧元符号) | 3 字节 | 2 字节 | 无法转换 | 无法转换 |
| 𠮷 (CJK 扩展 B) | 4 字节 | 4 字节 (代理对) | 无法转换 | 无法转换 |
值得注意的是,在 UTF-8 下半角片假名"ア"要消耗 3 字节。在 Shift_JIS 中只占 1 字节的半角片假名,到了 UTF-8 就和全角平假名一样是 3 字节。"半角所以数据量小"这种直觉,在 UTF-8 环境下并不总是正确。
用错全角半角会怎样 —— 失败案例集
全角与半角混用会引发以下这些问题。
- 表单弹出"请使用半角输入"的错误提示
- 程序代码中混入全角空格而报错
- 搜索时因全角半角不同而得到不同结果
- 在有字数限制的服务中,计数结果与预期不符
- CSV 文件中的全角逗号","未被识别为分隔符,导致数据损坏
- URL 中混入全角字符,经过百分号编码后 URL 变得异常冗长
常见问题与解决方法
- 全角空格导致的 bug:全角空格 (U+3000) 在代码中看起来像普通空格,但会导致解析错误。许多编程语言和工具不将全角空格视为空白字符。解决方法:使用代码编辑器的"显示不可见字符"功能。
- 全角数字导致的计算错误:全角数字 "123" 不能直接用于数学运算。需要先转换为半角 "123"。
- 混合使用导致的排版问题:全角和半角字符混合使用时,文本对齐可能出现问题。建议在同一文档中统一使用规则。
- 搜索匹配失败:搜索 "ABC" 不会匹配 "ABC"。需要在搜索前进行全角半角标准化。
全角半角的使用规范
在中文写作中,全角半角的使用有一些通用规范:
- 中文标点使用全角:句号 (。)、逗号 (,)、问号 (?) 等使用全角形式
- 英文和数字使用半角:英文字母和阿拉伯数字使用半角形式
- 英文标点使用半角:在英文语境中使用半角标点
- 括号根据内容选择:括号内是中文用全角,是英文用半角
日文写作中的惯例与此略有不同,处理日文文本时可作如下参考。
- 英文字母和数字一般使用半角 (例:2024 年、100 日元)
- 日文句子中的括号使用全角 (例:"你好"对应的直角引号)
- URL 和电子邮件地址必须以半角输入
- 填写表单时遵从其指定的形式 (全角或半角)
编程中全角字符的陷阱
尤为严重的是编程中混入全角空格 (U+3000)。它在外观上很难与半角空格 (U+0020) 区分,即使看到错误信息也往往察觉不到原因。
| 语言 | 错误信息 |
|---|---|
| Python | SyntaxError: invalid character ' ' |
| Java | illegal character: ' ' |
| JavaScript | SyntaxError: Invalid or unexpected token |
| C/C++ | error: stray '\343' in program (UTF-8 的首字节) |
| Ruby | SyntaxError: invalid multibyte char (UTF-8) |
除全角空格之外,把全角冒号":" (U+FF1A) 当作半角冒号":" (U+003A) 使用、混入全角分号";" (U+FF1B) 之类的失误也很常见。在 JSON、YAML 这样的结构化数据中,全角冒号尤其容易成为语法错误的根源。
另外,在电商网站的商品搜索中,如果系统把"T恤" (全角 T) 与"T 恤" (半角 T) 当作不同的搜索词,搜索结果会大不相同。这里的要点是:必须对存储数据和检索查询施加同一套标准化,只处理其中一侧的话,本应命中的结果反而会匹配不上。
编程中的全角半角转换
在编程中经常需要进行全角半角转换。Unicode 中全角 ASCII 字符 (U+FF01~U+FF5E) 与半角 ASCII 字符 (U+0021~U+007E) 之间有固定的偏移量 (0xFEE0),可以通过简单的数学运算进行转换。
不过,片假名的转换要复杂得多:半角片假名将浊音符号 (゙) 和半浊音符号 (゚) 定义为独立字符,"ガ"在半角形式下是"ガ"两个字符,因此需要额外的合成与分解处理。另外,JavaScript 的 normalize("NFKC") 虽然可以一次性完成宽度标准化,但它也会把"㍻"展开为"平成"等,产生超出预期的变换,实际使用时需要谨慎限定适用范围。本文开头的转换工具正是为了避免这类副作用,只使用明确的对照表进行转换。
CSV/TSV 与全角字符的陷阱
在数据交换中广泛使用的 CSV (Comma-Separated Values) 格式里,全角逗号"," (U+FF0C) 与半角逗号"," (U+002C) 混用会引发严重问题。多数 CSV 解析器只把半角逗号识别为分隔符,因此含全角逗号的字段不会被切分,数据列随之错位。
同样,在 TSV (Tab-Separated Values) 格式中,如果用全角空格代替制表符,列的分隔也无法被正确识别。用 Excel 打开 CSV 时若出现乱码或列错位,就应当怀疑混入了全角字符。
URL 编码与全角字符
当 URL 中包含全角字符时,百分号编码 (RFC 3986) 会把每个字节转换为 %XX 形式。在 UTF-8 下占 3 字节的日文字符会膨胀成 %E3%81%82 这样的 9 个字符。
例如"东京都"这 3 个字符,在 URL 中会变成 %E4%B8%9C%E4%BA%AC%E9%83%BD (27 个字符)。考虑到 URL 的长度限制 (一般为 2,048 个字符),含大量全角字符的 URL 很快就会触及上限。在文件名或目录名中使用日文时,设计上必须把这种膨胀考虑在内。
专业人士实践的全角半角管理技巧
以文本为业的专业人士,用下面这些技巧把全角半角问题挡在发生之前。
- 启用文本编辑器的"显示不可见字符"功能。在 VS Code 中设置
editor.renderWhitespace: "all",全角空格就能在视觉上被区分出来。再启用editor.unicodeHighlight.ambiguousCharacters: true,Ambiguous 类别的字符也会被高亮。 - 用正则表达式一次性检出全角英文字母和数字。用
[A-Za-z0-9]搜索全角英数字,并准备好转为半角的脚本,效率会很高。 - 在输入表单中,于服务器端实现自动转换处理。即使用户以全角输入,系统侧也会标准化为半角,从而避免报错。
- 善用日文输入法 (IME) 的快捷键。Windows 下按 F8 转为半角片假名,按 F10 转为半角英数字;Mac 下按 Ctrl+; 默认转为罗马字 (半角英数字),要得到半角片假名,前提是先在"输入法"设置中启用半角片假名的候选 (2026 年 8 月时点)。
- 用 Git 的 pre-commit 钩子检出全角空格。以
grep -rn $'\xe3\x80\x80'一次性检出仓库内的全角空格,在提交前发出警告,这种机制很有效。
Web 表单中全角半角自动转换的实现模式
在日本的 Web 服务中,电话号码、邮政编码、电子邮件地址等输入字段广泛实现了全角到半角的自动转换。下面介绍代表性的实现模式。
用 JavaScript 实现全角英数字到半角转换的基本逻辑,利用的是 Unicode 码位的差值。全角英数字与符号 (U+FF01~U+FF5E) 与对应的半角 ASCII 字符 (U+0021~U+007E) 之间相差 0xFEE0。
function toHalfWidth(str) {
return str.replace(/[!-~]/g, ch =>
String.fromCharCode(ch.charCodeAt(0) - 0xFEE0)
).replace(/ /g, ' ');
}
这个函数把全角英数字和符号转为半角,同时也把全角空格转为半角空格。不过,全角片假名到半角片假名的转换涉及浊音符号和半浊音符号的处理,相当复杂,建议另外使用现成的库。
在 HTML 的 input 元素上,可以用 inputmode 属性来控制输入模式,取代已废弃的 CSS ime-mode 属性。指定 inputmode="numeric" 后,移动端会显示数字键盘,从而降低全角输入的风险。
用正则表达式判定全角半角的实践
判定全角与半角时,利用 Unicode 码位区间的正则表达式很有效。需要先说明一点:East Asian Width 并不在正则表达式的 \p{...} 所能引用的属性之列,写不出 \p{Wide} 这样的形式,因此只能明确列出码位区间。下面按 East Asian Width 的类别,把标点 (U+3000~U+303F)、平假名 (U+3040~U+309F)、片假名 (U+30A0~U+30FF)、CJK 统一汉字 (U+4E00~U+9FFF)、全角形 (U+FF01~U+FF60)、半角片假名 (U+FF61~U+FF9F) 分别写成区间。
// 检出全角字符 (Wide + Fullwidth)
const fullwidthPattern = /[ -〿-ゟ゠-ヿ一-鿿!-⦆]/;
// 检出半角片假名
const halfwidthKatakana = /[。-゚]/;
// 只检出全角英数字 (U+FF10~U+FF19、U+FF21~U+FF3A、U+FF41~U+FF5A)
const fullwidthAlphaNum = /[0-9A-Za-z]/;
如果要在存入数据库之前统一全角半角,NFKC (Normalization Form Compatibility Composition) 标准化很有效。在 JavaScript 中,"A".normalize("NFKC") 会把全角的 A 转换为半角的 A。但 NFKC 也会把 ㍻ 展开为 平成 等,产生并非本意的变换,因此需要慎重评估适用范围。
灰色地带字符
难以简单归类为全角或半角的字符,其实分属两个不同的系统。一个是宽度本身会随环境改变的 A (Ambiguous,不确定宽度) 系:这类字符在 Unicode East Asian Width 属性中被归为 A,在不同的终端和编辑器中可能显示为单倍宽度,也可能显示为双倍宽度,希腊字母 α 和部分西里尔字母就属于这一系。另一个是映射系:宽度在规范上早已确定,但外观几乎相同的另一个码位同时存在,于是在编码转换的环节被混为一谈。
映射系的典型例子是波浪号 〜 (U+301C) 与全角波浪线 ~ (U+FF5E)。两者外观几乎相同,但在 Unicode 中是不同的字符,而且宽度在规范上都属于较宽的一侧 (East Asian Width 依次为 W 和 F),并不是宽度不确定。真正的麻烦出在映射上:Windows 的 Shift_JIS 实现曾把波浪号 (U+301C) 映射到全角波浪线 (U+FF5E),导致跨操作系统交换文本时出现乱码,这一问题被称为"波浪号问题"。
日元符号 ¥ (U+00A5) 与反斜杠 \ (U+005C) 同样属于映射系。两者的 East Asian Width 都是 Na (半角宽度),与全角的 ¥ (U+FFE5) 是彼此不同的字符。混乱的根源在于 JIS X 0201 把日元符号分配到了 ASCII 反斜杠的位置 (0x5C),于是在日语环境的某些字体中两者显示为同一形状。
本文开头的转换工具遵循这一历史教训:波浪号 (U+301C) 不做转换,只转换全角波浪线 ~ (U+FF5E) ⇔ ~ (U+007E);日元符号按 ¥ (U+FFE5) ⇔ ¥ (U+00A5)、反斜杠按 \ (U+FF3C) ⇔ \ (U+005C) 分别处理,绝不混淆外观相似的字符。
数据库中统一全角半角的最佳实践
- 输入时标准化:在应用层于 INSERT 进数据库之前施加 NFKC 标准化,全角英数字到半角英数字的转换会自动完成。
- 检索时标准化:对检索查询施加同样的标准化,吸收存储数据与检索条件之间的写法差异。MySQL 中使用
COLLATE utf8mb4_unicode_ci即可实现不区分全角半角的排序规则比较。 - 列设计:明确 VARCHAR 的长度指定是按字数 (MySQL) 还是按字节数 (Oracle),在 UTF-8 环境下要按全角 1 个字符 = 3 字节来设定字节上限。
- 索引设计:若需要不区分全角半角的检索,准备一个存放标准化后取值的独立列,并对该列建立索引,是效率较高的做法。
总结
全角与半角的区别不只是外观问题,它直接关系到字数统计、字节数计算、数据库设计、URL 设计以及编程的正确性。其根底是 JIS X 0201/0208 的历史沿革,以及 Unicode 的 East Asian Width 属性这一技术规范。准确掌握各编码下的字节大小差异,并善用 NFKC 标准化、正则表达式检出这些实用技巧,就能把全角半角引发的问题挡在发生之前。理解不同系统的计数方式差异、统一使用规范,是避免相关问题的关键。使用字符计数器可以分别显示全角和半角字符的数量,帮助您在核对全角半角构成的同时进行准确的字数管理。