除了使用String.replaceAll()方法并逐个替换字母之外,还有更好的方法来摆脱重音并使这些字母规则吗? 例子:
输入:或者čpžsíáýd
输出:orcpzsiayd
它不需要包括所有有口音的字母,比如俄语字母或汉语字母。
除了使用String.replaceAll()方法并逐个替换字母之外,还有更好的方法来摆脱重音并使这些字母规则吗? 例子:
输入:或者čpžsíáýd
输出:orcpzsiayd
它不需要包括所有有口音的字母,比如俄语字母或汉语字母。
当前回答
根据语言的不同,这些可能不被认为是重音(改变字母的发音),而是变音符符号
https://en.wikipedia.org/wiki/Diacritic#Languages_with_letters_containing_diacritics
“波斯尼亚语和克罗地亚语都有符号“č”、“ovic”、“đ”、“š”和“ž”,这些符号被认为是单独的字母,在字典和其他按字母顺序排列单词的语境中都是这样列出的。”
删除它们可能会从本质上改变单词的意思,或者将字母变成完全不同的字母。
其他回答
因为这个解决方案已经在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
编辑:如果你不困于Java <6,速度不是关键,/或翻译表太有限,请使用David的回答。重点是使用Normalizer(在Java 6中引入),而不是在循环中使用转换表。
虽然这不是“完美”的解决方案,但当你知道范围(在我们的例子中是latin1,2)时,它工作得很好,在Java 6之前工作(虽然不是一个真正的问题),并且比大多数建议的版本快得多(可能是也可能不是一个问题):
/**
* Mirror of the unicode table from 00c0 to 017f without diacritics.
*/
private static final String tab00c0 = "AAAAAAACEEEEIIII" +
"DNOOOOO\u00d7\u00d8UUUUYI\u00df" +
"aaaaaaaceeeeiiii" +
"\u00f0nooooo\u00f7\u00f8uuuuy\u00fey" +
"AaAaAaCcCcCcCcDd" +
"DdEeEeEeEeEeGgGg" +
"GgGgHhHhIiIiIiIi" +
"IiJjJjKkkLlLlLlL" +
"lLlNnNnNnnNnOoOo" +
"OoOoRrRrRrSsSsSs" +
"SsTtTtTtUuUuUuUu" +
"UuUuWwYyYZzZzZzF";
/**
* Returns string without diacritics - 7 bit approximation.
*
* @param source string to convert
* @return corresponding string without diacritics
*/
public static String removeDiacritic(String source) {
char[] vysl = new char[source.length()];
char one;
for (int i = 0; i < source.length(); i++) {
one = source.charAt(i);
if (one >= '\u00c0' && one <= '\u017f') {
one = tab00c0.charAt((int) one - '\u00c0');
}
vysl[i] = one;
}
return new String(vysl);
}
在我使用32位JDK的HW上进行的测试表明,这在~100ms内执行了从àèéľšťč89FDČ到aeelstc89FDC的100万次转换,而Normalizer方式使其在3.7s(慢37倍)。如果您的需求与性能有关,并且您知道输入范围,那么这可能适合您。
喜欢:-)
面对同样的问题,这里是使用Kotlin扩展的解决方案
val String.stripAccents: String
get() = Regex("\\p{InCombiningDiacriticalMarks}+")
.replace(
Normalizer.normalize(this, Normalizer.Form.NFD),
""
)
使用
val textWithoutAccents = "some accented string".stripAccents
一种快速安全的方式
public static String removeDiacritics(String str) {
if (str == null)
return null;
if (str.isEmpty())
return "";
int len = str.length();
StringBuilder sb
= new StringBuilder(len);
//iterate string codepoints
for (int i = 0; i < len; ) {
int codePoint = str.codePointAt(i);
int charCount
= Character.charCount(codePoint);
if (charCount > 1) {
for (int j = 0; j < charCount; j++)
sb.append(str.charAt(i + j));
i += charCount;
continue;
}
else if (codePoint <= 127) {
sb.append((char)codePoint);
i++;
continue;
}
sb.append(
java.text.Normalizer
.normalize(
Character.toString((char)codePoint),
java.text.Normalizer.Form.NFD)
.charAt(0));
i++;
}
return sb.toString();
}
从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 )
);
}
}