检查Unicode字符串是否为空格 - 字节为字节!

时间:2010-10-29 23:52:46

标签: unicode encoding utf-8 ascii whitespace

快速&脏Q:我可以安全地假设UTF-8,UTF-16或UTF-32代码点(字符)的字节是ASCII空白字符(除非代码点是代表一个)?

我会解释:

假设我有一个UTF-8编码的字符串。此字符串包含一些需要存储多个字节的字符。我需要找出这个字符串中的任何字符是否是ASCII空格字符(空格,水平制表符,垂直制表符,回车符,换行符等 - Unicode定义了一些空白字符,但忘了它们)。

所以我做的是循环遍历字符串并检查是否有任何字节与定义空格字符的字节匹配。以此为例0D(十六进制)用于回车。请注意,我们在这里讨论字节,而不是字符。

这会有用吗?是否存在UTF-8代码点,其中第一个字节为0D,第二个字节为其他字节 - 此代码点不代表回车符?也许相反?是否存在第一个字节奇怪的代码点,第二个(或第三个或第四个)字节是0D - 这个代码点不代表回车符?

UTF-8向后兼容ASCII,所以我真的希望它适用于UTF-8。据我所知,它可能会,但我不清楚细节,不能肯定地说。

对于UTF-16和UTF-32,我怀疑它是否会起作用,但我对这些细节几乎一无所知,所以请随意给我一些惊喜......


这个棘手问题的原因是我有代码检查适用于ASCII的空格,我需要知道它是否可能在Unicode上中断。由于一系列原因,我别无选择,只能逐字节检查。我希望向后兼容ASCII可能会给我至少UTF-8免费支持。

4 个答案:

答案 0 :(得分:7)

对于UTF-8,是的,你可以。所有非ASCII字符都由高位设置的字节表示,所有ASCII字符都设置为高位。

为了清楚起见,非ASCII字符编码中的每个字节都设置了高位;这是设计的。

您不应该在字节级别上使用UTF-16或UTF-32。这几乎肯定是行不通的。实际上很多东西都会破坏,因为每个第二个字节可能都是'\0'(除非你通常用另一种语言工作)。

答案 1 :(得分:5)

正确编码的 UTF-8中,所有ASCII字符将被编码为每个字节一个字节,并且每个字节的数值将等于Unicode和ASCII代码点。此外,任何非ASCII字符都将使用仅设置了第8位的 字节进行编码。因此,字节值0D将始终表示回车符,而不是多字节UTF-8序列的第二个或第三个字节。

但是,有时会滥用UTF-8解码规则以其他方式存储ASCII字符。例如,如果采用双字节序列C0 A0和UTF-8解码它,则得到一个字节值20,即空格。 (每当你找到字节C0或C8时,它就是ASCII字符的双字节编码的第一个字节。)我已经看到这样做来编码最初被认为是单个字的字符串,但后来的要求增加到允许值有空格。为了不破坏现有代码(使用诸如strtoksscanf之类的东西来识别空格分隔的字段),使用这个标准化的UTF-8而不是真正的UTF-8来编码该值。

但是,您可能不需要担心这一点。如果你的程序输入使用了那种格式,那么你的代码可能并不意味着在那个时候检测特殊编码的空格,所以你可以安全地忽略它。

答案 2 :(得分:3)

是的,但请注意下面以这种方式处理非字节流的陷阱。

对于UTF-8,任何连续字节总是以位10开头,使它们大于0x7f,没有可能它们被误认为是ASCII空间。

您可以在下表中看到:

Range              Encoding  Binary value
-----------------  --------  --------------------------
U+000000-U+00007f  0xxxxxxx  0xxxxxxx

U+000080-U+0007ff  110yyyxx  00000yyy xxxxxxxx
                   10xxxxxx

U+000800-U+00ffff  1110yyyy  yyyyyyyy xxxxxxxx
                   10yyyyxx
                   10xxxxxx

U+010000-U+10ffff  11110zzz  000zzzzz yyyyyyyy xxxxxxxx
                   10zzyyyy
                   10yyyyxx
                   10xxxxxx

您还可以看到,ASCII范围之外的代码点的非连续字节也设置了高位,因此它们也永远不会被误认为是空格。

有关详细信息,请参阅wikipedia UTF-8

首先不应逐字节处理UTF-16和UTF-32。您应该始终处理单元本身,16位或32位值。如果你这样做,你也会受到保护。如果你逐字节处理这些,你就会发现一个0x20字节不是空格(例如,16位UTF-16值的第二个字节)的危险。

对于UTF-16,由于该编码中的扩展字符是由个体值在0xd8000xdfff范围内的代理对形成的,因此这些代理对组件可能没有危险也误认为是空格。

有关详细信息,请参阅wikipedia UTF-16

最后,UTF-32(wikipedia link here)足以表示所有Unicode代码点,因此不需要特殊编码。

答案 3 :(得分:0)

强烈建议在处理Unicode时不要使用字节。两个主要平台(Java和.Net)本身支持unicode,并提供了确定这类事物的机制。对于例如在Java中,您可以为您的用例使用Character类的isSpace()/ isSpaceChar()/ isWhitespace()方法。