140

问题是,如您所知,Unicode 图表中有数千个字符,我想将所有相似的字符转换为英文字母表中的字母。

例如,这里有一些转换:

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

我看到字母 A/a 有 20 多个版本。而且我不知道如何对它们进行分类。它们看起来就像大海捞针。

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

如何使用 Java 转换所有这些?请帮我 :(

4

12 回答 12

205

如何从 .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("");
}
于 2009-07-31T22:06:03.700 回答
74

从版本开始,它是Apache Commons Lang的一部分。3.0。

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

返回An

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

于 2012-11-03T13:28:05.087 回答
19

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

首先,您需要了解您正在尝试做的事情的局限性。正如其他人所指出的那样,变音符号的存在是有原因的:它们本质上是该语言字母表中的唯一字母,具有自己的含义/声音等:删除这些标记与替换英文单词中的随机字母相同。这是在您考虑西里尔语言和其他基于脚本的文本(例如阿拉伯语)之前,这些文本根本无法“转换”为英语。

如果您出于某种原因必须转换字符,那么解决此问题的唯一明智方法是首先缩小手头任务的范围。考虑输入的来源 - 如果您正在为“西方世界”编写应用程序(使用尽可能好的短语),那么您不太可能需要解析阿拉伯字符。同样,Unicode 字符集包含数百个数学和图形符号:用户没有(简单的)方法可以直接输入这些符号,因此您可以假设它们可以被忽略。

通过采取这些逻辑步骤,您可以减少可能要解析的字符数,以使基于字典的查找/替换操作可行。然后它就变成了创建字典的少量稍微无聊的工作,以及执行替换的微不足道的任务。如果您的语言支持本机 Unicode 字符(如 Java 那样)并正确优化静态结构,那么这种查找和替换往往会非常快。

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

于 2009-06-17T20:18:12.157 回答
16

由于将“家庭”变成“tђє Ŧค๓เℓy”的编码实际上是随机的,并且不遵循任何可以通过所涉及的 Unicode 代码点信息解释的算法,因此没有通用的方法来解决这个算法。

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

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

例子:

  • “ђ”(U+0452 CYRILLIC SMALL LETTER DJE)与“d”的关系比与“h”的关系更大,但用于表示“h”。
  • “Ŧ”(U+0166 LATIN CAPITAL LETTER T WITH STROKE)与“T”(顾名思义)有些相关,但用于表示“F”。
  • "ค" (U+0E04 THAI CHARACTER KHO KHWAI) 根本与任何拉丁字符无关,在您的示例中用于表示“a”
于 2009-09-09T08:50:27.777 回答
12

字符串测试:ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß

测试:

  • Apache Commons Lang3的输出:AAAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • ICU4j的输出:AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • JUnidecode的输出:AAAAAAECEEEEIIIIDNOOOOOOUUUUUss(Ý 问题和另一个问题
  • Unidecode的输出:AAAAAAECEEEEIIIIDNOOOOOOUUUUYss

最后的选择是最好的。

于 2017-04-12T13:23:35.450 回答
8

原始请求已经得到答复。

但是,我为那些可能正在寻找通用音译代码以在 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;
    }
于 2014-11-10T06:13:57.563 回答
6

如果需要转换“òéışöç->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 类。

在此处查看示例

于 2009-06-17T22:33:32.943 回答
5

将任意 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...
}
于 2009-06-17T18:49:31.890 回答
4

您可以尝试使用unidecode,它可以作为ruby​​ gemcpan 上的 perl 模块使用。本质上,它就像一个巨大的查找表,其中每个 unicode 代码点都与一个 ascii 字符或字符串相关。

于 2009-06-17T19:14:07.793 回答
4

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

如果你想要这种转换,你必须根据你认为非拉丁字母应该转换成的拉丁字母来创建自己的翻译表。

(如果您只想删除变音符号,此线程中有一些答案:How do I remove diacritics (accents) from a string in .NET?但是您描述了一个更普遍的问题)

于 2009-06-27T12:04:57.840 回答
4

我迟到了,但是今天遇到这个问题后,我发现这个答案非常好:

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

参考: https ://stackoverflow.com/a/16283863

于 2016-08-14T22:11:46.353 回答
2

以下课程可以解决问题:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
于 2017-06-26T10:50:43.413 回答