在 Java 中,使用从 InputStream.read() 返回的 int 调用 Character.isXxx() 方法是否安全?
In Java, is it safe to call Character.isXxx() methods with an int returned from InputStream.read()?
读取文本文件时,我想做这样的事情:
InputStream input = ...;
int read = input.read();
if (Character.isWhitespace(read)) {
// do something with the whitespace
}
另一种方法是检查负 read()
return 值(又名,输入结束)并显式转换:
InputStream input = ...;
int read = input.read();
if (read >= 0 && Character.isWhitespace((char) read)) {
// do something with the whitespace
}
但是,这涉及到额外的分支和转换,我希望我的代码尽可能高效,所以我更喜欢第一种方法。
但是,我希望我的代码更健壮 :),我不确定第一种方法是否会产生细微的问题。根据我收集到的信息,Unicode 将 0xFFFF
和 0xFFFFFFFF
都定义为非字符,所以我认为它是安全的。但专家怎么说?
为了确保,问题涉及我的方法是否对 所有 Character.isXxx()
方法安全,而不仅仅是 Character.isWhitespace()
.
是的,很安全。对于 0xFFFFFFFF
的情况,所有 isXxx 方法 return 都是假的。实际上,对于 0x000FFFFF
以外的所有内容都是如此,因为这些值在 Unicode 中未定义。对于 0xFFFF
,它大部分是相同的,尽管 isBmpCodePoint
是正确的。
InputStream.read()
方法读取一个 单个 8 位字节 并且 returns 它作为 32 位 int
范围内的0x00 - 0xFF
,或 returns -1
EOF。
接受 32 位 int
作为输入的 Character.isXXX()
方法需要 0x00 - 0x10FFFF
范围内的 完整 Unicode 代码点 。如果文件由 7 位 ASCII 字符组成(其中字节 0x00 - 0x7F
映射到代码点 U+0000 - U+007F
),则单个字节 可能 按原样表示完整代码点,或 ISO-8859-1(其中字节 0x00 - 0xFF
映射到代码点 U+0000 - U+00FF
)。如果文件使用 any 其他编码,则无法保证任何给定字节将按原样映射到具有相同值的代码点,尤其是如果字节大于 0x7F
(大多数 7/8 位编码使用相同的字节值来实现 ASCII 兼容性 - 但并非全部如此!)。
接受 16 位 char
作为输入的 Character.isXXX()
方法需要 0x00 - 0xFFFF
范围内的 UTF-16 代码单元 .单个 char
可以按原样保留一个 Unicode 代码点,直到代码点 U+FFFF
。但是,这些方法 不 支持 UTF-16 代理项,因此无法处理 U+FFFF
以上的 Unicode 代码点(需要 2 char
值来表示它们)。
那么,为了回答您的问题 - 您能否 read()
文件中的任何给定字节并将其按原样传递给 Character.isXXX()
方法并获得可靠的结果?答案是——这取决于文件的实际编码。如果文件以 7 位 ASCII 或 8 位 ISO-8859-1 编码,则可以。否则,可能,但通常仅适用于字节 0x7F,因为字节 0x80 - 0xFF
是特定于编码的,并且将取决于特定编码如何在字节和 Unicode 代码点之间映射(假设文件甚至开始使用 7/8 位编码)。
读取文本文件时,我想做这样的事情:
InputStream input = ...;
int read = input.read();
if (Character.isWhitespace(read)) {
// do something with the whitespace
}
另一种方法是检查负 read()
return 值(又名,输入结束)并显式转换:
InputStream input = ...;
int read = input.read();
if (read >= 0 && Character.isWhitespace((char) read)) {
// do something with the whitespace
}
但是,这涉及到额外的分支和转换,我希望我的代码尽可能高效,所以我更喜欢第一种方法。
但是,我希望我的代码更健壮 :),我不确定第一种方法是否会产生细微的问题。根据我收集到的信息,Unicode 将 0xFFFF
和 0xFFFFFFFF
都定义为非字符,所以我认为它是安全的。但专家怎么说?
为了确保,问题涉及我的方法是否对 所有 Character.isXxx()
方法安全,而不仅仅是 Character.isWhitespace()
.
是的,很安全。对于 0xFFFFFFFF
的情况,所有 isXxx 方法 return 都是假的。实际上,对于 0x000FFFFF
以外的所有内容都是如此,因为这些值在 Unicode 中未定义。对于 0xFFFF
,它大部分是相同的,尽管 isBmpCodePoint
是正确的。
InputStream.read()
方法读取一个 单个 8 位字节 并且 returns 它作为 32 位 int
范围内的0x00 - 0xFF
,或 returns -1
EOF。
接受 32 位 int
作为输入的 Character.isXXX()
方法需要 0x00 - 0x10FFFF
范围内的 完整 Unicode 代码点 。如果文件由 7 位 ASCII 字符组成(其中字节 0x00 - 0x7F
映射到代码点 U+0000 - U+007F
),则单个字节 可能 按原样表示完整代码点,或 ISO-8859-1(其中字节 0x00 - 0xFF
映射到代码点 U+0000 - U+00FF
)。如果文件使用 any 其他编码,则无法保证任何给定字节将按原样映射到具有相同值的代码点,尤其是如果字节大于 0x7F
(大多数 7/8 位编码使用相同的字节值来实现 ASCII 兼容性 - 但并非全部如此!)。
接受 16 位 char
作为输入的 Character.isXXX()
方法需要 0x00 - 0xFFFF
范围内的 UTF-16 代码单元 .单个 char
可以按原样保留一个 Unicode 代码点,直到代码点 U+FFFF
。但是,这些方法 不 支持 UTF-16 代理项,因此无法处理 U+FFFF
以上的 Unicode 代码点(需要 2 char
值来表示它们)。
那么,为了回答您的问题 - 您能否 read()
文件中的任何给定字节并将其按原样传递给 Character.isXXX()
方法并获得可靠的结果?答案是——这取决于文件的实际编码。如果文件以 7 位 ASCII 或 8 位 ISO-8859-1 编码,则可以。否则,可能,但通常仅适用于字节 0x7F,因为字节 0x80 - 0xFF
是特定于编码的,并且将取决于特定编码如何在字节和 Unicode 代码点之间映射(假设文件甚至开始使用 7/8 位编码)。