10

我正在寻找一种方法来比较两个在字典上等效但在字节级别不相同的 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 ?

4

2 回答 2

8

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

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

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

输出

true

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

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

于 2013-01-23T19:42:06.407 回答
7

您需要研究两种Unicode 规范化形式:

第一个是 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 用作搜索/排序键。

于 2013-01-23T19:44:33.663 回答