Java:PHP 的 ord() 的实现对 ASCII 以外的字符产生不同的结果

Posted

技术标签:

【中文标题】Java:PHP 的 ord() 的实现对 ASCII 以外的字符产生不同的结果【英文标题】:Java: Implementation of PHP's ord() yields different results for chars beyond ASCII 【发布时间】:2017-09-14 21:27:44 【问题描述】:

我正在尝试编写与 phpord() 等效的 Java:

public static int ord(char c) 
    return (int) c;


public static int ord(String s) 
    return s.length() > 0 ? ord(s.charAt(0)) : 0;

这似乎适用于序数值高达127 的字符,即在 ASCII 中。但是,对于来自扩展 ASCII 表或更远的字符,PHP 会返回 195(及更高版本)。 Mr. Llama 到 the answer on a related question 的评论解释如下:

详细来说,é 显示 ASCII 195 的原因是因为它实际上是一个两字节字符 (UTF-8),其中第一个字节是 ASCII 195。——骆驼先生

因此,我更改了我的 ord(char c) 方法以屏蔽除最重要的字节之外的所有字节:

public static int ord(char c) 
    return (int) (c & 0xFF);

不过,结果不同。两个例子:

ord('é') (U+00E9) 在 PHP 中给出 195 而我的 Java 函数产生 233 ord('⸆') (U+2E06) 在 PHP 中给出 226 而我的 Java 函数产生 6

我设法通过首先将 String 转换为 byte 数组,显式使用 UTF-8 编码,为接受 String 的方法获得相同的行为

public static int ord(String s) 
    return s.length() > 0 ? ord((char)s.getBytes(StandardCharsets.UTF_8)[0]) : 0;

但是,使用接受char 的方法仍然像以前一样运行,我还没有找到解决方案。此外,我不明白为什么更改实际上有效:Charset.defaultCharset() 在我的平台上返回UTF-8。所以……

如何使我的函数的行为与 PHP 相似? 为什么更改为 ord(String s) 确实有效?

非常感谢您提供解释性答案,因为我想准确了解发生了什么。

【问题讨论】:

Java 似乎是正确的; 233 确实是é 的代码:ascii-code.com。 195 是Ã 的代码,所以谁知道 WTF 在 PHP 的幕后工作。 其实好像和这个有很大关系:***.com/questions/35575721/ord-doesnt-work-with-utf-8 @OliverCharlesworth 是正确的,PHP 的 ord() 不能正确处理 ASCII 范围之外的字符。但是,我正在尝试复制这种行为。 【参考方案1】:

在 Java 中为 char is a UTF-16 code unit。将 UTF-16 转换为 UTF-8 不只是 & 0xFF,例如 UTF-16 中的 01FF 是 UTF-8 中的 C7 BF,所以 PHP 的 ord() 应该给出 0xC7 (199),但 @ 987654330@ 是 255。

String 版本有效,因为它实际上正在转换为 UTF-8。

最简单的方法是反转你的两个重载,因为String 有一个方便的方法来获取 UTF-8:

public static int ord(String s) 
    return s.length() > 0 ? (s.getBytes(StandardCharsets.UTF_8)[0] & 0xff) : 0;

和convert the char to a String:

public static int ord(char c) 
    return c < 0x80 ? c : ord(Character.toString(c))


虽然这可行,但由于不必要的 char→String→int 转换,它效率不高。 Unicode 代码点 c 的 UTF-8 编码的第一个字节实际上可以通过以下方式找到:

if (c < 0x80) 
    return c;
 else if (c < 0x800) 
    return 0xc0 | c >> 6;
 else if (c < 0x10000) 
    return 0xe0 | c >> 12; 
 else 
    return 0xf0 | c >> 18;

您可能还想阅读What is Unicode, UTF-8, UTF-16? 了解一些背景信息。

【讨论】:

啊,这说明了一切!很棒的答案,谢谢。我使用 Java 大约 3 年了,从不知道它在内部使用了 UTF-16。我会确保仔细阅读链接的参考资料。

以上是关于Java:PHP 的 ord() 的实现对 ASCII 以外的字符产生不同的结果的主要内容,如果未能解决你的问题,请参考以下文章

sql 第2行显示如何GROUP BY Last Name,然后ORDER BY两件事 - 首先是COUNT(OrderID),然后是LastName,在ASC ord中排序

基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件

基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件

基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件

python中ord()函数和chr()函数用法

ord函数-php