编码问题是在开发过程中经常困扰我的一个主题.每个平台都坚持自己的编码,很可能在游戏中有一些非UTF-8默认值.(我通常在Linux上工作,默认为UTF-8,我的同事主要使用德语Windows,默认为ISO-8859-1或类似的Windows代码页)
我相信,UTF-8是开发i18nable应用程序的合适标准.然而,根据我的经验,编码错误通常是发现较晚的(即使我位于德国,我们有一些特殊字符,与ISO-8859-1一起提供了一些可检测的差异).
我相信具有完全非ASCII字符集的开发人员(或那些知道使用这种字符集的语言的开发人员)在提供测试数据方面处于领先地位.但是,对于我们其他人来说,必须有一种方法来缓解这种情况.
这里的人们使用什么[技术工具|激励]?您如何让您的联合开发人员关注这些问题?您如何测试合规性?这些测试是手动还是自动进行的?
提前添加一个可能的答案:
我最近发现了fliptitle.com(它们提供了一种简单的方法来编写奇怪的字符"uʍopǝpısdn"*)并且我打算使用它们来提供易于验证的UTF-8字符串(因为大多数使用的字符)有一些奇怪的二进制编码位置)但肯定必须有更系统的测试,模式或技术来确保UTF-8的兼容性/使用.
注意:即使有一个公认的答案,我想知道更多的技术和模式,如果有的话.如果您有更多想法,请添加更多答案.选择一个接受答案并不容易.虽然有理由选择其他答案,但我选择正则表达式的答案来解决问题的最小预期角度.太糟糕了只有一个答案可以接受.
谢谢您的意见.
*)那些由于字体问题而无法看到这些字符的"颠倒"写的"倒置"
谢谢你的fliptitle!
我也正在尝试制定一个合适的测试计划,以确保应用程序支持整个系统中的Unicode字符串.
我是双语的,但是只使用ISO-8859-1的两种语言.因此,我一直在努力确定什么是"真实","有意义"的方式来测试各种Unicode可能性.
我刚看到这个:
国际测试基础 - 测试非英语和非ASCII支持
在为我的应用程序设计了一些测试之后,我意识到我已经整理了一小部分可能对其他人有帮助的编码值.
我在测试中使用以下国际字符串:
(注意:这里有一些UTF-8编码的文本...希望你能在浏览器中看到这个)
ユーザー别サイト
简体中文English
크 로 스 플 랫 폼 으 로
מדוריםמבוקשים
أفضلالبحوث
Σεγνωρίζω.距离
ДесятуюМеждународную
แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช
∮E⋅da= Q,N→∞,ΣF(1)=Π克(ⅰ)
的问题索绪尔étrangère
MANANA奥莱
(UTF-8外文/非英文文本结束)
然而,在测试过程中的各个阶段,我意识到仅仅有关于字符串在各自的外国字母表中呈现时应该看起来的信息是不够的.我还需要知道正确的Unicode代码点编号,以及至少两种编码(UCS-2和UTF-8)中这些字符串的正确十六进制值.
这是等效的代码点编号和十六进制值:
str = L"\u30E6\u30FC\u30B6\u30FC\u5225\u30B5\u30A4\u30C8"; // JAPAN // Little endian UTF-16/UCS-2: e6 30 fc 30 b6 30 fc 30 25 52 b5 30 a4 30 c8 30 00 00 // Hex of UTF-8: e3 83 a6 e3 83 bc e3 82 b6 e3 83 bc e5 88 a5 e3 82 b5 e3 82 a4 e3 83 88 00 str = L"\u7B80\u4F53\u4E2D\u6587"; // CHINA // Little endian UTF-16/UCS-2: 80 7b 53 4f 2d 4e 87 65 00 00 // Hex of UTF-8: e7 ae 80 e4 bd 93 e4 b8 ad e6 96 87 00 str = L"\uD06C\uB85C\uC2A4 \uD50C\uB7AB\uD3FC\uC73C\uB85C"; // KOREA // Little endian UTF-16/UCS-2: 6c d0 5c b8 a4 c2 20 00 0c d5 ab b7 fc d3 3c c7 5c b8 00 00 // Hex of UTF-8: ed 81 ac eb a1 9c ec 8a a4 20 ed 94 8c eb 9e ab ed 8f bc ec 9c bc eb a1 9c 00 str = L"\u05DE\u05D3\u05D5\u05E8\u05D9\u05DD \u05DE\u05D1\u05D5\u05E7\u05E9\u05D9\u05DD"; // ISRAEL // Little endian UTF-16/UCS-2: de 05 d3 05 d5 05 e8 05 d9 05 dd 05 20 00 de 05 d1 05 d5 05 e7 05 e9 05 d9 05 dd 05 00 00 // Hex of UTF-8: d7 9e d7 93 d7 95 d7 a8 d7 99 d7 9d 20 d7 9e d7 91 d7 95 d7 a7 d7 a9 d7 99 d7 9d 00 str = L"\u0623\u0641\u0636\u0644 \u0627\u0644\u0628\u062D\u0648\u062B"; // EGYPT // Little endian UTF-16/UCS-2: 23 06 41 06 36 06 44 06 20 00 27 06 44 06 28 06 2d 06 48 06 2b 06 00 00 // Hex of UTF-8: d8 a3 d9 81 d8 b6 d9 84 20 d8 a7 d9 84 d8 a8 d8 ad d9 88 d8 ab 00 str = L"\u03A3\u1F72 \u03B3\u03BD\u03C9\u03C1\u03AF\u03B6\u03C9 \u1F00\u03C0\u1F78"; // GREECE // Little endian UTF-16/UCS-2: a3 03 72 1f 20 00 b3 03 bd 03 c9 03 c1 03 af 03 b6 03 c9 03 20 00 00 // Hex of UTF-8: ce a3 e1 bd b2 20 ce b3 ce bd cf 89 cf 81 ce af ce b6 cf 89 20 e1 bc 80 cf 80 e1 bd b8 00 str = L"\u0414\u0435\u0441\u044F\u0442\u0443\u044E \u041C\u0435\u0436\u0434\u0443\u043D\u0430\u0440\u043E\u0434\u043D\u0443\u044E"; // RUSSIA // Little endian UTF-16/UCS-2: 14 04 35 04 41 04 4f 04 42 04 43 04 4e 04 20 00 1c 04 35 04 36 04 34 04 43 04 3d 04 30 04 40 04 3e 04 34 04 3d 04 43 04 4e 04 00 00 // Hex of UTF-8: d0 94 d0 b5 d1 81 d1 8f d1 82 d1 83 d1 8e 20 d0 9c d0 b5 d0 b6 d0 b4 d1 83 d0 bd d0 b0 d1 80 d0 be d0 b4 d0 bd d1 83 d1 8e 00 str = L"\u0E41\u0E1C\u0E48\u0E19\u0E14\u0E34\u0E19\u0E2E\u0E31\u0E48\u0E19\u0E40\u0E2A\u0E37\u0E48\u0E2D\u0E21\u0E42\u0E17\u0E23\u0E21\u0E41\u0E2A\u0E19\u0E2A\u0E31\u0E07\u0E40\u0E27\u0E0A"; // THAILAND // Little endian UTF-16/UCS-2: 41 0e 1c 0e 48 0e 19 0e 14 0e 34 0e 19 0e 2e 0e 31 0e 48 0e 19 0e 40 0e 2a 0e 37 0e 48 0e 2d 0e 21 0e 42 0e 17 0e 23 0e 21 0e 41 0e 2a 0e 19 0e 2a 0e 31 0e 07 0e 40 0e 27 0e 0a 0e 00 00 // Hex of UTF-8: e0 b9 81 e0 b8 9c e0 b9 88 e0 b8 99 e0 b8 94 e0 b8 b4 e0 b8 99 e0 b8 ae e0 b8 b1 e0 b9 88 e0 b8 99 e0 b9 80 e0 b8 aa e0 b8 b7 e0 b9 88 e0 b8 ad e0 b8 a1 e0 b9 82 e0 b8 97 e0 b8 a3 e0 b8 a1 e0 b9 81 e0 b8 aa e0 b8 99 e0 b8 aa e0 b8 b1 e0 b8 87 e0 b9 80 e0 b8 a7 e0 b8 8a 00 str = L"\u222E E\u22C5da = Q, n \u2192 \u221E, \u2211 f(i) = \u220F g(i)"; // MATHEMATICS // Little endian UTF-16/UCS-2: 2e 22 20 00 45 00 c5 22 64 00 61 00 20 00 3d 00 20 00 51 00 2c 00 20 00 20 00 6e 00 20 00 92 21 20 00 1e 22 2c 00 20 00 11 22 20 00 66 00 28 00 69 00 29 00 20 00 3d 00 20 00 0f 22 20 00 67 00 28 00 69 00 29 00 00 00 // Hex of UTF-8: e2 88 ae 20 45 e2 8b 85 64 61 20 3d 20 51 2c 20 20 6e 20 e2 86 92 20 e2 88 9e 2c 20 e2 88 91 20 66 28 69 29 20 3d 20 e2 88 8f 20 67 28 69 29 00 str = L"fran\u00E7ais langue \u00E9trang\u00E8re"; // FRANCE // Little endian UTF-16/UCS-2: 66 00 72 00 61 00 6e 00 e7 00 61 00 69 00 73 00 20 00 6c 00 61 00 6e 00 67 00 75 00 65 00 20 00 e9 00 74 00 72 00 61 00 6e 00 67 00 e8 00 72 00 65 00 00 00 // Hex of UTF-8: 66 72 61 6e c3 a7 61 69 73 20 6c 61 6e 67 75 65 20 c3 a9 74 72 61 6e 67 c3 a8 72 65 00 str = L"ma\u00F1ana ol\u00E9"; // SPAIN // Little endian UTF-16/UCS-2: 6d 00 61 00 f1 00 61 00 6e 00 61 00 20 00 6f 00 6c 00 e9 00 00 00 // Hex of UTF-8: 6d 61 c3 b1 61 6e 61 20 6f 6c c3 a9 00
此外,这里有一些图像显示了在各种编辑器中可能发生的一些常见的"错误渲染",即使底层字节是格式良好的UTF8.如果您看到这些渲染中的任何一个,则可能意味着您正确生成了UTF8字符串,但您的编辑器/查看器正在尝试使用UTF8以外的某些编码来解释它们.
示例渲染数量.1
示例渲染数量.2
有一个正则表达式来测试字符串是否有效UTF-8:
$field =~ m/\A( [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )*\z/x;
但这并不能确保文本实际为UTF-8.
例如:字母ö(U + 00F6)的字节序列和相应的UTF-8序列是0xC3B6.
因此,当您输入0xC3B6作为输入时,您可以说它是有效的UTF-8.但你不能肯定地说已经提交了这封信.
这是因为想象不是使用UTF-8而是使用ISO 8859-1.序列0xC3B6分别代表字符Ã(0xC3)和(0xB6).
所以序列0xC3B6可以使用ISO 8859-1代表ö使用UTF-8或(尽管后者相当不寻常).
所以最后它只是猜测.