到目前为止,在含有非ASCII字符的QR码中,UTF-8是首选的编码方式吗?

8
谷歌将UTF-8作为默认编码器,这是一种非常流行的编码方式。从我所看到的来看,他们甚至没有添加字节顺序标记。
问题在于,大多数扫描仪似乎仍然使用JIS8(QR 2000)而不是iso-8859(QR 2005)作为默认值,因此使用iso-8859进行编码通常不起作用。
似乎utf-8是唯一的选择,即使它违反了规范。
编辑:我将使用没有ECI和BOM的utf-8。虽然违反了所有规范和精神,但目前效果最好。
2个回答

12
规范说明ISO-8859-1是字节模式编码的默认值。然而,在实践中,日本经常使用Shift-JIS或UTF-8。使用UTF-8是正确的选择。要正确地执行此操作,您需要在流中放置一些指示,表明它是UTF-8。规范允许这样做。您需要在字节段之前加上一个ECI segment,表示UTF-8。如果您向zxing编码器发送编码为UTF-8的提示,则它将为您完成此操作。

1
经过一些测试:谷歌编码器(因此也包括ZXing在线编码器)似乎没有使用ECI。更重要的是,许多扫描器应用程序不理解ECI段。我认为最好将其省略。 - Gonzo
还有一个问题:使用BOM吗? - Gonzo
3
不要在UTF-8流中使用BOM,这会在某些环境下造成很多问题。 - tchrist
2
测试结果表明 ECI 无法使用。对于 BOM,我可能会采用 tchrist 的做法并将其省略。这是来自 UTF-8 维基百科页面的内容:“因为检查文本是否有效的 UTF-8 非常可靠(大多数随机字节序列都不是有效的 UTF-8),所以不应该使用 [BOM]。” - Gonzo
3
是的,我对此有所错误。BOM在解析流中变成了一个(不可见)字符U+FEFF。我会看看忽略它有多难。但你应该省略BOM。 - Sean Owen
显示剩余2条评论

6

零宽不断空格(BOM)无济于事

我的经验表明,零宽不断空格(BOM)无济于事。如果QR扫描仪无法从正确编码的UTF-8字符串(数据流中的8位字节模式)中显示一个字符串,即使使用ECI添加BOM也没有任何区别。

即使编码正确,扫描仪也会失败

以无法正确显示UTF-8字符的扫描仪为例,拿小米手机MIUI Global v11.0.3(带有其本机扫描器应用程序)为例。即使在ECI中指定了该字符集,这些手机也无法正确显示以UTF-8编码的西里尔文字符串。西里尔字符会显示为问号。但是,如果在西里尔文本中添加一个中文/日文字符(例如“日”),小米就可以正确显示整个文本,而这与BOM无关。

这些是实际重要的字符,而不是编码

您认为在QR码中使用UTF-8而不是ISO-8859-1更好,因为ISO-8859-1不是2000年发布的早期QR码标准(ISO/IEC 18004:2000)的默认编码。该标准按照JIS X 0201(JIS8,也称为ISO-2022-JP)规定了8位拉丁文/假名字符集作为8位模式的默认编码,而在2005年发布的更新标准中将默认编码更改为ISO-8859-1。因此,您认为“使用iso-8859进行编码通常不起作用”。 这取决于您是否只需要US-ASCII字符(具体来说,20-7E范围内的可打印ANSI X3.4-1986字符),而且您不需要在加泰罗尼亚语、法语、加利西亚语、德语、奥克语和西班牙语等语言中使用umlaut/diaeresis的ISO-8859-1字符。

如果您只需要US-ASCII,则使用ISO-8859-1而不需要ECI是安全的,而不是使用带有ECI的UTF-8。无论如何,20-7E范围内的US-ASCII字符的八位字节字符串无论是编码为ISO-8859-1还是UTF-8都是相同的。扫描仪使用的启发式软件应该能够自动确定所使用的字符集,如果您只使用US-ASCII字符,则可以自动找到它们。如果需要umlaut/diaeresis字符,则使用UTF-8。这不是因为QR码标准在2000年和2005年修订版之间默认编码从JIS X 0201更改为ISO-8859-1,而是因为QR扫描仪使用启发式来自动检测编码,在某些情况下,这个启发式会失败。

为什么QR扫描仪使用启发式来检测编码

众所周知,QR码有四种文本存储模式:(1) 数字模式,(2) 字母数字模式,(3) 8位字节模式,以及(4) 汉字模式。

因此,QR码标准并不支持UTF-8编码。要在8位字符串中使用UTF-8编码(而不是默认的“ISO-8859-1”或“JIS8”),实现必须在该字符串之前插入一个扩展通道解释(ECI)。ECI是QR码的可选附加功能,但至少在2000年时最早定义在QR码标准中。ECI使得可以使用字符集以外的数据编码方式。它还使得可以对其他行业特定要求进行编码,例如使用定义的压缩方案压缩的紧缩数据或其他数据解释。

ECI协议在由AIM公司开发的规范中定义,需要购买,价格为50美元,网址为https://www.aimglobal.org/technical-symbology.html

扫描仪可能会忽略ECI协议

不幸的是,并非所有的QR码扫描器都能处理ECI协议,即使只是将默认编码更改为UTF-8这样的基本事项也不行。大多数实现使用启发式算法,即字符编码检测算法之一来猜测编码,即使在解码的QR码的ECI中明确指定了编码。他们使用启发式算法不仅是因为2000年至2005年间默认编码从JIS8变为ISO-8859-1导致的。主要原因是缺乏适当的ECI协议支持,可能是由于QR码规范和AIM ECI协议规范是不同的文档。一些QR编码器不通过ECI指定字符编码,而是使用不同的编码方式对8位字符串进行编码(如JIS8、Shift_JIS、ISO-8859-1、UTF-8),因此扫描仪需要应对这种情况。

您曾写道,“似乎只有utf-8是唯一的选择”,但扫描仪使用的启发式算法可能会连UTF-8都失败,就像我给出的小米例子一样。您还写道,UTF-8“违反了规范”,但只有当没有通过ECI显式地指定UTF-8编码时才是这样。

ECI和UTF-8的替代方案,但并不是完全的解决方案

顺便提一下,使用ECI并不是唯一的选择。您可以使用umlaut / diaeresis编码拉丁字符,或使用“Kanji”模式编码Cyrillic字符。在这种模式下,“Shift_JIS”用于编码JIS X 0208字符的范围为8140-9FFCE040-EBBF。 在此模式下,您不能通过字节代码20对其他范围中的字符进行编码,但是您可以将其编码为JIS X 0208行1列21(即2121)。由于JIS X 0208具有罗马字母(第3行),希腊字母(第6行)和西里尔字母(第7行)以及特殊字符(第1和2行)的行,因此您可以在JIS字符范围8140-9FFCE040-EBBF内完全使用JIS X 0208编码包括umlaut / diaeresis拉丁字符或Cyrillic文本(包括空格和标点符号)。在这种情况下,不需要使用ECI扩展。但是,并不能保证扫描软件中的启发式算法不会破坏您正确编码的文本。

结论

使用UTF-8并通过ECI指定它不是完全的解决方案(因为一些扫描仪在这种情况下仍将使用容易出错的启发式算法),但至少可以帮助符合标准的扫描仪,不像BOM根本没有帮助。


1
你所提到的内部编码模式只是一种优化常见数据比特流压缩的手段。与ECI不同,读取器的传输协议并不会向主机指示编码模式的更改,因此应用程序接收到的是一个字节数组,必须根据当前生效的代码页进行解释:除非有ECI序列更改它,否则为Latin-1。AIM技术符号委员会和“WG1”的成员正在更新ECI标准并推广其使用:https://www.linkedin.com/pulse/enhanced-channel-interpretation-terry-burton/ - Terry Burton
2
对于模型配置,应用程序或主机驱动程序不可能通过单向接口“窥视”条形码内部代码字/比特流以确定正在生效的精确模式。因此,已解码的消息是可用的,并且为避免歧义,确定其被解释为Latin-1,除非ECI生效(由消息开头的符号标识符指示)。 - Terry Burton
2
在移动应用程序或嵌入式应用程序中,阅读器和运行某些应用程序的主机之间没有物理区别,因此该模型接口对于实际目的是不可见的。因此,“压缩模式(汉字等)”(用于代码字优化目的)和字符编码(用于解释目的)之间的区分不再明显。这导致了分层违规,开发人员使用任何可用信息来窥视QR码的内部编码,以推断无意义的含义。 - Terry Burton
2
QR Code 2005标准的目标是系统化早期QR Code标准中不符合主流框架假设的元素。(例如,在先前版本中忽略了在ECI未生效时定义默认字符编码的问题。) 问题是/仍然是,许多实现将消息数据输入工具包的文本小部件中,这会导致有效字符集的自动检测,从条形码要成为完整传输的角度来看,这是灾难性的,而不是大多数情况下似乎可以正常工作直到出现问题。 - Terry Burton
2
随着越来越多的应用程序强制使用Latin-1编码来处理非ECI消息,情况正在逐渐改善。当ECI支持普遍可用时,您可以指定输出消息或消息段旨在被解释为Shift JIS(ECI \ 000020),并且还可以使用汉字压缩模式在QR码符号的内部比特流中高效地编码这些消息字节。更近期的条形码(如HanXin)支持多字节语言的几种附加压缩模式,但使用相同的ECI协议通过模型接口框架来表示解释。 - Terry Burton
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接