将符号、重音字母转换为英文字母

问题是,如你所知,有成千上万个字符 abc 0,我想把所有相似的字符转换成英文字母中的字母。

例如,下面是一些转换:

ҥ->H
Ѷ->V
Ȳ->Y
Ǭ->O
Ƈ->C
tђє Ŧค๓เℓy --> the Family
...

我看到有超过20个字母 A/A 的版本,我不知道如何将它们分类。他们看起来就像大海捞针。

Unicode 字符的完整列表位于 http://www.ssec.wisc.edu/~tomw/java/unicode.htmlhttp://unicode.org/charts/charindex.html。试着向下滚动,看看字母的变化。

我怎样才能用 Java 转换所有这些? 请帮助我: (?)

140301 次浏览

将任意 Unicode“转换”为 ASCII 的问题在于字符的含义是依赖于区域性的。例如,对于讲德语的人来说,“ ß”应该转换成“ ss”,而对于讲英语的人来说,可能会转换成“ B”。

此外,Unicode 对于相同的字形有多个代码点。

结果就是,唯一的方法就是创建一个包含每个 Unicode字符和你想要转换成的 ASCII 字符的大型表。您可以通过将带有重音符号的字符规范化为规范化形式 KD,但不是所有字符都规范化为 ASCII,从而获得快捷方式。此外,Unicode 没有定义字形的哪些部分是“重音符号”。

下面是一个应用程序的一小段摘录:

switch (c)
{
case 'A':
case '\u00C0':  //  À LATIN CAPITAL LETTER A WITH GRAVE
case '\u00C1':  //  Á LATIN CAPITAL LETTER A WITH ACUTE
case '\u00C2':  //  Â LATIN CAPITAL LETTER A WITH CIRCUMFLEX
// and so on for about 20 lines...
return "A";
break;


case '\u00C6'://  Æ LATIN CAPITAL LIGATURE AE
return "AE";
break;


// And so on for pages...
}

您可以尝试使用 unidecode,它可以作为 红宝石Cpan 上的 perl 模块使用。从本质上讲,它就像一个巨大的查找表,每个 Unicode字符都与一个 ascii 字符或字符串相关。

试图“全部转换”是解决问题的错误方法。

首先,你需要了解你正在尝试做的事情的局限性。正如其他人指出的那样,发音符号的存在是有原因的: 它们本质上是该语言字母表中独一无二的字母,有着自己的意义/声音等等: 去掉这些标记就等同于替换一个英语单词中的随机字母。这是在你开始考虑西里尔语言和其他基于脚本的文本,如阿拉伯语,它们根本不能“转换”为英语之前。

如果您的 必须的,不管出于什么原因,转换字符,那么唯一合理的方法来处理它,首先减少手头任务的范围。考虑一下输入的来源——如果你正在为“西方世界”编写一个应用程序(使用任何好的短语) ,那么你将不太可能需要解析阿拉伯字符。类似地,Unicode字符集包含数百个数学和图形符号,用户没有(简单)方法直接输入这些符号,所以你可以假设它们可以被忽略。

通过采取这些逻辑步骤,您可以减少需要解析的可能字符的数量,从而使基于字典的查找/替换操作变得可行。然后,它就变成了创建字典的一小部分略显枯燥的工作,以及执行替换的一个琐碎任务。如果您的语言支持本机 Unicode 字符(就像 Java 一样)并正确地优化静态结构,那么这种查找和替换往往会非常快。

这来自于在一个应用程序中工作的经验,该应用程序需要允许最终用户搜索包含发音字符的书目数据。查找数组(就像在我们的例子中一样)可能需要1个人一天的时间才能生成,以覆盖所有西欧语言的所有发音符号。

如果需要转换“ òé öç-> oeisoc”,你可以从这里开始:

public class AsciiUtils {
private static final String PLAIN_ASCII =
"AaEeIiOoUu"    // grave
+ "AaEeIiOoUuYy"  // acute
+ "AaEeIiOoUuYy"  // circumflex
+ "AaOoNn"        // tilde
+ "AaEeIiOoUuYy"  // umlaut
+ "Aa"            // ring
+ "Cc"            // cedilla
+ "OoUu"          // double acute
;


private static final String UNICODE =
"\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9"
+ "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD"
+ "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177"
+ "\u00C3\u00E3\u00D5\u00F5\u00D1\u00F1"
+ "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF"
+ "\u00C5\u00E5"
+ "\u00C7\u00E7"
+ "\u0150\u0151\u0170\u0171"
;


// private constructor, can't be instanciated!
private AsciiUtils() { }


// remove accentued from a string and replace with ascii equivalent
public static String convertNonAscii(String s) {
if (s == null) return null;
StringBuilder sb = new StringBuilder();
int n = s.length();
for (int i = 0; i < n; i++) {
char c = s.charAt(i);
int pos = UNICODE.indexOf(c);
if (pos > -1){
sb.append(PLAIN_ASCII.charAt(pos));
}
else {
sb.append(c);
}
}
return sb.toString();
}


public static void main(String args[]) {
String s =
"The result : È,É,Ê,Ë,Û,Ù,Ï,Î,À,Â,Ô,è,é,ê,ë,û,ù,ï,î,à,â,ô,ç";
System.out.println(AsciiUtils.convertNonAscii(s));
// output :
// The result : E,E,E,E,U,U,I,I,A,A,O,e,e,e,e,u,u,i,i,a,a,o,c
}
}

JDK 1.6提供了可用于此任务的 java.text. Normalizer 类。

参见示例 给你

没有简单或普遍的方法来做你想做的事情,因为这只是你的主观意见,这些字母看起来像拉丁字母,你想转换成。它们实际上是独立的字母,有自己独特的名字和发音,只是表面上看起来像一个拉丁字母。

如果希望进行转换,则必须根据您认为非拉丁字母应该转换为的拉丁字母创建自己的翻译表。

(如果你只想去掉变音符号,这里有一些答案: 如何从.NET 中的字符串中删除变音符号(重音符号) ?然而你描述了一个更普遍的问题)

如何从.NET 中的字符串中删除变音符号(重音符号) ?转发我的帖子

这个方法在 java (纯粹是为了去除发音标记又名重音)中工作得很好。

它基本上将所有重音字符转换为它们的去重音字符,然后是它们的组合变音符。现在您可以使用正则表达式去掉音调符号。

import java.text.Normalizer;
import java.util.regex.Pattern;


public String deAccent(String str) {
String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD);
Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
return pattern.matcher(nfdNormalizedString).replaceAll("");
}

由于将“ the Family”转换为“ t something something ly”的编码实际上是随机的,不遵循任何可以用所涉及的 Unicode 编码点的信息来解释的算法,因此没有通用的算法来解决这个问题。

您将需要构建 Unicode 字符到它们相似的拉丁字符的映射。您可以通过对表示 Unicode 代码点的实际字形进行一些智能机器学习来实现这一点。但是我认为这比手工构建映射要费力得多。特别是如果您有大量的示例,可以从中构建映射。

澄清一下: 一些替换实际上可以通过 Unicode 数据解决(如其他答案所示) ,但是一些字母与它们相似的拉丁字符没有合理的关联。

例子:

  • “”(U + 0452西里尔字母小写字母 DJE)与“ d”的关系比与“ h”的关系更密切,但用于表示“ h”。
  • “”(U + 0166大写拉丁字母 T WITH STROKE)在某种程度上与“ T”(顾名思义)有关,但是用来表示“ F”。
  • “ something”(U + 0 E04 THAI 字符 KHO KHWAI)与任何拉丁字符都没有关系,在您的示例中用于表示“ a”

这是 Apache Commons Lang的一部分。

org.apache.commons.lang3.StringUtils.stripAccents("Añ");

返回 An

也请参阅 http://www.drillio.com/en/software-development/java/removing-accents-diacritics-in-any-language/

最初的请求已经得到了回应。

然而,对于那些可能正在寻找通用音译代码将任何字符在 Java 中转换为拉丁语/英语的人,我发布了以下答案。

音译的天真含义: 翻译后的字符串的最终形式/目标字符集听起来像原来形式的字符串。 如果我们想把任何字符转换成拉丁文(英文字母) ,那么 ICU4(java 中的 ICU4J 库)就可以完成这项工作。

下面是 java 中的代码片段:

    import com.ibm.icu.text.Transliterator; //ICU4J library import


public static String TRANSLITERATE_ID = "NFD; Any-Latin; NFC";
public static String NORMALIZE_ID = "NFD; [:Nonspacing Mark:] Remove; NFC";


/**
* Returns the transliterated string to convert any charset to latin.
*/
public static String transliterate(String input) {
Transliterator transliterator = Transliterator.getInstance(TRANSLITERATE_ID + "; " + NORMALIZE_ID);
String result = transliterator.transliterate(input);
return result;
}

我迟到了,但在今天面对这个问题之后,我发现这个答案非常好:

String asciiName = Normalizer.normalize(unicodeName, Normalizer.Form.NFD)
.replaceAll("[^\\p{ASCII}]", "");

参考文献: Https://stackoverflow.com/a/16283863

字符串测试:

测试:

最后的选择是最好的。

下列课程可以起到作用:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter