Java。在比较字符串时忽略重音符号。

58

这个问题很简单。在JAVA中是否有任何函数可用于比较两个字符串并忽略带重音字符而返回true?

例如:

String x = "Joao";
String y = "João";

返回相等的结果。

谢谢


9
但它们并不相等,既然它们不相等,为什么你希望它们相等呢?请注意,这里有一个“不”字。 - user177800
6
@fuzzy两者通常是相同的名字(这是约翰的葡萄牙语版本)。有些人只是懒得加上重音符号。 - Samuel Carrijo
8
是的,但从他的例子来看,他似乎想要比较名字,并不太担心出现错误的结果。 - Samuel Carrijo
10
这对于搜索非常有用。用户在QWERTY键盘上打音标太麻烦了。也许问题应该重新表述为确定两个字符串是否“相似”而不是相等。 - Marijn van Vliet
1
这在需要比较国际数据的系统中尤其有效。 1- 可能全世界很少有系统能够正确处理多语言。正如下面的帖子中提到的,即使是Java也存在有缺陷的Unicode支持。 2- 当您有服务接受来自第三方的数据时,所有这些都会失败。因为没有人能够一致地处理数据。 3- 正如之前所提到的,人们根本就不会正确地输入数据。要么是因为懒惰,要么是因为打错字等原因... 4- Joao可能是一个西班牙用户,不幸的是使用英文计算机。 - user432024
显示剩余8条评论
6个回答

69

我认为你应该使用Collator类。它允许你设置强度和区域设置,并适当地比较字符。

根据Java 1.6 API:

您可以设置Collator的strength属性来确定在比较中考虑的差异级别。提供了四种强度:PRIMARY、SECONDARY、TERTIARY和IDENTICAL。强度与语言特征的确切分配因区域设置而异。例如,在捷克语中,"e"和"f"被视为主要差异,而"e"和"ě"是次要差异,"e"和"E"是三级差异,"e"和"e"相同。

我认为这里重要的一点(人们试图表达的)是“Joao”和“João”永远不应该被视为相等,但如果你正在进行排序,你不希望它们基于它们的ASCII值进行比较,否则你会得到像Joao、John、João这样的东西,这是不好的。使用Collator类肯定会正确处理这个问题。


3
@Software Monkey: 我也同意,尽管我写了被采纳的答案。:-P - C. K. Young
1
各位,请查看此处所创建的一些代码 here,这些代码遵循了你们指定的准则,所以非常感谢。然而,我没有找到可以进行“区分音调但区分大小写”比较的方法,按照 Collator 的规则来说...我有什么遗漏了吗? - Joao Coelho
1
@Joao,您无法使用Collator类来实现此操作,因为强度设置为最低级别。因此,要获得区分大小写,您需要使用TERTIARY,但对于不区分重音符号,您只需要使用PRIMARY。因此,它们不能同时使用。您最好使用Chris Jester-Young的解决方案来过滤掉重音符号,然后正常比较字符串。 - DaveJohnston

26

我并不同意该问题的前提(请不要告诉别人我这么说了),但你可以使用java.text.Normalizer,并用NFD来进行规范化:这会将重音从它所附着的字母中分离出来。然后你可以过滤掉重音符号并进行比较。


6
StringUtils.stripAccents将这两个步骤合并为一个。详见:http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/StringUtils.html - cquezel
1
这在需要比较国际数据的系统中尤其有效。 1- 可能全世界很少有系统能够正确处理多语言。正如下面的帖子中提到的,即使是Java也存在有缺陷的Unicode支持。 2- 当您有服务接受来自第三方的数据时,所有这些都会失败。因为没有人能够一致地处理数据。 3- 正如之前所提到的,人们根本就不会正确地输入数据。要么是因为懒惰,要么是因为打错字等原因... 4- Joao可能是一个西班牙用户,不幸的是使用英文计算机。 - user432024

10

如果您想忽略重音进行比较/排序,则可以使用来自Apache StringUtils库的stripAccents函数:

 public int compareStripAccent(String a, String b) {
    return StringUtils.stripAccents(a).compareTo(StringUtils.stripAccents(b));
}

9

如果您将Java的Collator配置为忽略变音符号,则对于"a"和"á",它都会返回0。

public boolean isSame(String a, String b) {
    Collator insenstiveStringComparator = Collator.getInstance();
    insenstiveStringComparator.setStrength(Collator.PRIMARY);
    return insenstiveStringComparator.compare(a, b) == 0;
}

isSame("a", "á") 会返回 true。


2
public boolean insenstiveStringComparator (String a, String b) {
    java.text.Collator collate = java.text.Collator.getInstance();
    collate.setStrength(java.text.Collator.PRIMARY);
    collate.setDecomposition(java.text.Collator.CANONICAL_DECOMPOSITION); 
    return collate.equals(a, b);    
}

-2
这种转换的问题在于,重音字符到非重音字符之间并不总是有明确的映射关系。这取决于代码页、本地化等因素。例如,带重音符号的a是否等同于没有重音符号的"a"?对人来说不是问题,但对计算机来说更加棘手。
据我所知,Java没有内置的转换功能,可以查找当前的本地化选项并进行这种转换。您可能需要一些处理Unicode更好的外部库,比如ICU(http://site.icu-project.org/)。

Java确实有这个功能,它被称为Collater,专门用于解决这种问题。 - Benny Bottema

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接