判断字符宽度
之前曾在《C# 中容易忽视的 Encoding.GetByteCount 内存问题》中提到过,可以使用 Encoding.Default.GetByteCount 方法来判断字符是全宽(宽度为 2)还是半宽(宽度为 1)。
这个方法实际上是计算对字符编码后产生的字节数,只是在中文环境下,宽字符在使用默认编码后一般都会占用两个字节,使得在大多数场景下都没有什么问题。但根据 Unicode 标准,EAST ASIAN WIDTH 才是准确的字符宽度定义,适用于东亚文本的字符的宽度计算。
标准中定义了六类字符宽度:
- 全角(Fullwidth):在 Unicode 标准中定义的全角字符,例如“0123, ABCD”等。
- 半角(Halfwidth):在 Unicode 标准中定义的半角字符,例如“。「」、・”等。
- 宽(Width):始终为宽的其它字符,一般仅在东亚上下文中出现,例如中文字符。
- 窄(Narrow):始终窄的的其它字符,它们一般都有对应的全角或宽字符,例如“0123, ABCD”等。
- 不明确(Ambiguous):根据不同情况可能显示不同宽窄的字符,
- 中性(Neutral):其它所有字符,一般不用于东亚文本,
标准建议,宽字符包括 W、F 和 A(在东亚上下文中),窄字符包括 N、Na、H 和 A(非东亚上下文中)。下图是一个解析宽度的示例。
图 1 字符类别及其解析宽度的示例,图片来自 http://www.unicode.org/reports/tr11/
但在实际测试时发现,A 类别的处理要复杂很多,并非所有 A 类别字符都会显示为宽(或窄),而且不同字体也会有不同的处理方式。
以 \u00A1\u00A4\u00A7\u01CE\u22BF\u2312
这六个字符为例,它们均为 A 类别,但在 Consolas 字体下,前四个字符显示为窄,后两个字符显示为宽;在新宋体下,第一和第四个字符显示为窄,其它字符显示为宽。
图 2 不同字体显示不一致
由于这种场景实在过于复杂,因此目前将 A 类别统一当作窄字符来计算,在用到这类字符的场景下再单独考虑。
将 Unicode 13.0.0 下的 EAST ASIAN WIDTH 统一扫描后,整理得到以下宽字符范围:
# 1100 ~ 115F Hangul Jamo
1100..115F
# User interface symbols
231A..231B
2329..232A
23E9..23EC
23F0..23F0
23F3..23F3
25FD..25FE
2614..2615
2648..2653
267F..267F
2693..2693
26A1..26A1
26AA..26AB
26BD..26BE
26C4..26C5
26CE..26CE
26D4..26D4
26EA..26EA
26F2..26F3
26F5..26F5
26FA..26FA
26FD..26FD
2705..2705
270A..270B
2728..2728
274C..274C
274E..274E
2753..2755
2757..2757
2795..2797
27B0..27B0
27BF..27BF
2B1B..2B1C
2B50..2B50
2B55..2B55
# 2E80 ~ 2EFF CJK Radicals Supplement
# 2F00 ~ 2FDF Kangxi Radicals
# 2FF0 ~ 2FFF Ideographic Description Characters
# 3000 ~ 303E CJK Symbols and Punctuation
2E80..303E
# 3040 ~ 309F Hiragana
# 30A0 ~ 30FF Katakana
# 3100 ~ 312F Bopomofo
# 3030 ~ 318F Hangul Compatibility Jamo
# 3190 ~ 319F Kanbun
# 31A0 ~ 31BF Bopomofo Extended
# 31C0 ~ 31EF CJK Strokes
# 31F0 ~ 31FF Katakana Phonetic Extensions
# 3200 ~ 32FF Enclosed CJK Letters and Months
# 3300 ~ 33FF CJK Compatibility
# 3400 ~ 4DBF CJK Unified Ideographs Extension A
3040..4DBF
# 4E00 ~ 9FFC CJK Unified Ideographs
# A000 ~ A48F Yi Syllables
# A490 ~ A4CF Yi Radicals
4E00..A4CF
# A960 ~ A97F Hangul Jamo Extended-A
A960..A97F
# AC00 ~ D7A3 Hangul Syllables
AC00..D7A3
# F900 ~ FAFF CJK Compatibility Ideographs
F900..FAFF
# FE10 ~ FE19 Vertical forms
FE10..FE19
# FE30 ~ FE4F CJK Compatibility Forms
# FE50 ~ FE6F Small Form Variants
FE30..FE6F
# FF00 ~ FF60 Fullwidth ASCII variants
FF01..FF60
# FFE0 ~ FFE6 Fullwidth symbol variants
FFE0..FFE6
具体实现可以参见 https://github.com/CYJB/Cyjb/blob/master/Cyjb/CharUtil.cs。
作者:CYJB
出处:http://www.cnblogs.com/cyjb/
GitHub:https://github.com/CYJB/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。