【问题标题】:Compare two strings that are lexicographically equivalent but not identical at the byte level比较两个在字典上等价但在字节级别不相同的字符串
【发布时间】:2013-01-07 09:53:37
【问题描述】:

我正在寻找一种方法来比较两个 Java 字符串,它们在字典上是等效的,但在字节级别上并不相同。

更准确地说,取以下文件名“baaaé.png”,在字节级别它可以用两种不同的方式表示:

[98, 97, 97, 97, -61, -87, 46, 112, 110, 103] --> "é" 编码为 2 个字节

[98, 97, 97, 97, 101, -52, -127, 46, 112, 110, 103] --> "é" 编码为 3 个字节

    byte[] ch = {98, 97, 97, 97, -61, -87, 46, 112, 110, 103};
    byte[] ff = {98, 97, 97, 97, 101, -52, -127, 46, 112, 110, 103};

    String st = new String(ch,"UTF-8");
    String st2 = new String(ff,"UTF-8");
    System.out.println(st);
    System.out.println(st2);
    System.out.println(st.equals(st2));

将生成以下输出:

baaaé.png
baaaé.png
false

有没有办法进行比较以使 equals 方法返回 true ?

【问题讨论】:

  • 这里的渲染不一样。
  • @dystroy 这使我们重新考虑“字典上等价的”语句:)
  • @dystroy (强烈)首选的网络规范化形式是 NFC。显然,您的网络浏览器采用了简单的快捷方式,并且仅支持 NFC,不支持 NFD。对于它的价值,我的也是如此。显然,网络浏览器不会费心实施 NFD。但是,我可以将这两个示例复制并粘贴到一个同时支持 NFC 和 NFD 的不同应用程序中,并且它们的显示方式完全相同。

标签: java string utf-8


【解决方案1】:

您可以使用具有适用强度的Collator 类来规范化不同的重音符号等内容。这将允许您成功地比较字符串。

在这种情况下,美国语言环境和 TERTIARY 强度足以使字符串相等

Collator usCollator = Collator.getInstance();
usCollator.setStrength(Collator.TERTIARY);
System.out.println(usCollator.equals(st, st2));

输出

true

您还可以使用Java 的Normalizer 类在不同形式的Unicode 之间进行转换。这将转换您的字符串,但它们最终会是相同的,允许您使用标准字符串工具进行比较

最后,take 可能想看看ICU(Unicode 的国际组件)项目,它提供了许多工具,可以以多种不同的方式处理 Unicode 字符串。

【讨论】:

  • 我已经测试了 Normalizer 类,它运行良好。谢谢。
【解决方案2】:

您需要研究两种Unicode normalization forms:

第一个是 NFC 与 NFD。您在问题中给出的示例是 NFC 和 NFD 之间差异的一个很好的示例。您的第一个字符串在 NFC 中,而您的第二个字符串在 NFD 中。

在 Unicode 中,许多重音字符可以用两种不同的方式表示:作为基本字符后跟一个组合重音字符,或者作为预先组合的重音字符。 NFC 在可用时使用预先组合的字符。 NFD 总是使用分解的形式。

通常我们不会混合使用 NFC 和 NFD。大多数环境都指定了首选形式。非常简单:MacOS X 文件名使用 NFD,几乎所有其他文件名都使用 NFC。但是如果你得到的输入可能是“其他”规范化形式,你可以很容易地转换它:这个过程很简单(使用 Unicode 字符数据库提供的信息)并且无损(即你可以在 NFC 之间来回切换和 NFD,如果您愿意,不会丢失信息)。

java 提供了一个名为 Normalizer 的内置类,可以将字符串转换为给定的 Unicode 格式。

还有另外 2 种规范化形式:NFKC 和 NFKD。这些表格不用于一般用途,而仅用于字典比较。它们解释了这样一个事实,例如,在搜索或比较中 ¼ 应被视为与 1/4 相同。但它们并不意味着 ¼ 和 1/4 是相同的,或者通常应该将一个转换为另一个。

从 NFC 到 NFKC 以及从 NFD 到 NFKD 的转换再次简单明了(您需要字符数据库),但这次是有损的。您需要保留原始 NFC/NFD 文本并仅将 NFKC/NFKD 用作搜索/排序键。

【讨论】:

  • java 提供了一个名为 Normalizer 的内置类,可以将字符串转换为给定的 Unicode 形式
  • +1 为您提供详细的答案,清楚地解释了问题的根本原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 2013-05-13
  • 2010-12-25
  • 1970-01-01
相关资源
最近更新 更多