除了使用String.replaceAll()方法并逐个替换字母之外,还有更好的方法来摆脱重音并使这些字母规则吗? 例子:
输入:或者čpžsíáýd
输出:orcpzsiayd
它不需要包括所有有口音的字母,比如俄语字母或汉语字母。
除了使用String.replaceAll()方法并逐个替换字母之外,还有更好的方法来摆脱重音并使这些字母规则吗? 例子:
输入:或者čpžsíáýd
输出:orcpzsiayd
它不需要包括所有有口音的字母,比如俄语字母或汉语字母。
当前回答
面对同样的问题,这里是使用Kotlin扩展的解决方案
val String.stripAccents: String
get() = Regex("\\p{InCombiningDiacriticalMarks}+")
.replace(
Normalizer.normalize(this, Normalizer.Form.NFD),
""
)
使用
val textWithoutAccents = "some accented string".stripAccents
其他回答
从java.text.Normalizer开始。
string = Normalizer.normalize(string, Normalizer.Form.NFD);
// or Normalizer.Form.NFKD for a more "compatible" deconstruction
这将从大多数字符中分离所有重音符号。然后,你只需要将每个字符与字母进行比较,并排除那些不是字母的字符。
string = string.replaceAll("[^\\p{ASCII}]", "");
如果你的文本是Unicode,你应该使用这个:
string = string.replaceAll("\\p{M}", "");
对于Unicode, \\P{M}匹配基本字形,\\P{M}(小写)匹配每个重音。
感谢GarretWilson提供的指针和正则表达式.info提供的Unicode指南。
需要注意的是,Normalizer本身不足以删除变音符。例如,下面的代码不会将重音的é替换为不重音的e:
import static java.text.Normalizer.normalize;
import static java.text.Normalizer.Form.*;
public class T {
public static void main( final String[] args ) {
final var text = "Brévis";
System.out.println(
normalize( text, NFD ) + " " +
normalize( text, NFC ) + " " +
normalize( text, NFKD ) + " " +
normalize( text, NFKC )
);
}
}
我认为最好的解决方案是将每个char转换为HEX,并用另一个HEX替换它。因为有两种Unicode类型:
Composite Unicode
Precomposed Unicode
例如,Composite Unicode编写的“Ồ”不同于precompose Unicode编写的“Ồ”。您可以复制我的示例字符并转换它们以查看差异。
In Composite Unicode, "Ồ" is combined from 2 char: Ô (U+00d4) and ̀ (U+0300)
In Precomposed Unicode, "Ồ" is single char (U+1ED2)
我为一些银行开发了这个功能,以便在将信息发送到核心银行(通常不支持Unicode)之前转换信息,当最终用户使用多种Unicode类型输入数据时,就会遇到这个问题。所以我认为,转换为HEX并替换它是最可靠的方法。
因为这个解决方案已经在Maven资源库的stringutils . striptones()中可用,并且可以在@DavidS提到的Ł中使用。 但我需要这是工作在Ø和Ł所以修改如下。可能对其他人也有帮助。
更新
这是StringUtils的修改版本。stripaccent (String obj),它包含旧的功能,同时处理Ø和Ł字符。
public static String stripAccents(final String input) {
if (input == null) {
return null;
}
final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
for (int i = 0; i < decomposed.length(); i++) {
if (decomposed.charAt(i) == '\u0141') {
decomposed.setCharAt(i, 'L');
} else if (decomposed.charAt(i) == '\u0142') {
decomposed.setCharAt(i, 'l');
}else if (decomposed.charAt(i) == '\u00D8') {
decomposed.setCharAt(i, 'O');
}else if (decomposed.charAt(i) == '\u00F8') {
decomposed.setCharAt(i, 'o');
}
}
// Note that this doesn't correctly remove ligatures...
return Pattern.compile("\\p{InCombiningDiacriticalMarks}+").matcher(decomposed).replaceAll("");
}
输入字符串Ł Tĥïŝ 这是一个时髦的字符串O O
面对同样的问题,这里是使用Kotlin扩展的解决方案
val String.stripAccents: String
get() = Regex("\\p{InCombiningDiacriticalMarks}+")
.replace(
Normalizer.normalize(this, Normalizer.Form.NFD),
""
)
使用
val textWithoutAccents = "some accented string".stripAccents
根据语言的不同,这些可能不被认为是重音(改变字母的发音),而是变音符符号
https://en.wikipedia.org/wiki/Diacritic#Languages_with_letters_containing_diacritics
“波斯尼亚语和克罗地亚语都有符号“č”、“ovic”、“đ”、“š”和“ž”,这些符号被认为是单独的字母,在字典和其他按字母顺序排列单词的语境中都是这样列出的。”
删除它们可能会从本质上改变单词的意思,或者将字母变成完全不同的字母。