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


129

如您所知,问题是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转换所有这些?请帮我 :(


请参阅以下问题:stackoverflow.com/questions/249087/…-关于此主题也应该有一些其他问题,但目前找不到。
schnaader

1
您的第三个例子应该是Ȳ→Y吗?
Dour High Arch

2
为什么要这样做?如果我们知道您的总体目标是什么,我们可能会有所帮助。
David Thornley,2009年

大卫,您知道有些EMO在句子中使用了不同的字符。这里有个例子:ฬ。¢。tђє∂єยη∂єг¢คקђy <-解决这个问题:) @schnaader,我认为这是我想要的,但不是Java。
AhmetB-Google

此对话之前已经完成-请参阅上面的@schnaader。
dkretz

Answers:


197

如何从.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("");
}

4
InCombiningDiacriticalMarks不会转换所有西里尔字母。例如,ОпштинаБогомила未被触摸。如果可以将其转换为Opstina Bogomila或类似的东西
那就

13
它根本不会音译。它仅去除分解的变音标记(“重音符号”)。上一步(Form.NFD)将á分解为+,即将重音字符分解为未重音字符和变音标记。可以将西里尔文Ѽ转换为Ѡ,但不会进一步。
MSalters 2010年

1
乔治在glaforge.appspot.com/article/上发布了使用\\ p {IsM}而不是\\ p {InCombiningDiacriticalMarks} 更好的方法。请注意,我尚未对其进行测试。
ATorras 2012年

2
\\ p {IsM}似乎不适用于áóñéí之类的西班牙口音。相反,“ \\ p {InCombiningDiacriticalMarks} +对此非常有用
Loic

它不适用于所有特殊字符-我向Android提交了一个错误的问题,以便了解-> code.google.com/p/android/issues/detail?id=189515有人知道正确的方法吗?
米哈尔Tajchert

71

从ver。开始,它是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/


这个解决方案是惊人的。它也适用于希腊语!谢谢。
汤姆(Tom)

5
对于从ł和Ł消失的波兰语字符而言,这不是完美的:输入:ŚŻÓŁĄĆĘŹąółęąćńŃ输出:SZOŁACEZaołeacnN–
罗伯特·罗伯特(Robert)

1
不错的实用程序,但是由于其代码与接受的答案中显示的代码完全相同,并且您不想添加对Commons Lang的依赖,因此您可以使用上述代码段。
Polaretto

1
以我的情况常见的apache:Đ不转换为D
Hoang

@ Hoang,Robert也许有机会发送请求请求:)
OndraŽižka17年

19

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

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

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

通过采取这些逻辑步骤,您可以减少可能解析的字符数,使基于字典的查找/替换操作可行。然后,这将成为创建字典的少量乏味工作,并且是执行替换的琐碎任务。如果您的语言(如Java)支持本机Unicode字符并正确地优化了静态结构,则这种查找和替换往往很快就令人眼花。乱。

这源于对允许最终用户搜索包含变音符号的书目数据所需的应用程序进行工作的经验。查找数组(在本例中为例)可能需要1个工作日才能完成,以覆盖所有西欧语言的所有变音符号。


iAn感谢您的回答。实际上,我不是在使用阿拉伯语言或类似语言。您知道有些人把变音符号当作好笑的角色,我必须尽我所能去掉它。例如,我在示例中说了“tђєy->家庭”转换,但似乎很难完全转换。但是,我们可以通过简单的方式进行“òéışöç-> oeisoc”转换。但是执行此操作的确切方法是什么。创建数组并手动替换?还是该语言具有针对此问题的本机功能?
AhmetB-Google 2009年

15

由于将“家庭”转换为“ t y”的编码实际上是随机的,并且不遵循任何可以由所涉及的Unicode代码点的信息解释的算法,因此没有通用的方法可以通过算法解决该问题。

您将需要将Unicode字符映射为相似的拉丁字符。您可能可以通过对代表Unicode代码点的实际字形进行一些智能机器学习来完成此操作。但是我认为,为此付出的努力将比手动构建该映射更大。尤其是如果您有大量示例可以从中构建映射。

需要说明的是:实际上,一些替换可以通过Unicode数据解决(如其他答案所示),但是有些字母与它们所类似于的拉丁字符根本没有合理的关联。

例子:

  • “ђ”(U + 0452西里尔小写字母DJE)与“ d”的关系比与“ h”的关系更大,但用于表示“ h”。
  • “Ŧ”(带划线的U + 0166带有大写字母的拉丁文大写字母T)在某种程度上与“ T”相关(顾名思义),但用于表示“ F”。
  • “ค”(U + 0E04 THAI CHARACTER KHO KHWAI)与任何拉丁字符完全无关,在您的示例中用于表示“ a”

7

原始请求已得到答复。

但是,对于那些正在寻找通用音译代码以将任何字符集音译为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;
    }

7

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

经测试:

最后的选择是最好的。


1
@mehmet只需遵循github.com/xuender/unidecode上的自述文件。导入依赖项后,它应该类似于Unidecode.decode(“ÁÁÃÄÅÅÆÇÈÉÊËÌËÏÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß”)。
cactuschibre

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类。

在这里查看示例


不幸的是,这将无法处理Æ之类的连字。
Dour High Arch

如果您需要以不同的方式检测和处理变音符号类别(即,在LaTeX中转义特殊字符),则此方法特别有用。
vallismortis

4

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


您可能可以从其中之一获取查询表。
凯西·凡·斯通·史东

这是一个了不起的程序包,但是它可以音译角色的声音,例如,它将“北”转换为“北”,因为这就是该角色在普通话中的发音。我认为发问者想将字形转换为它们在视觉上类似于英语的字形。
Dour High Arch

不过,它确实适用于拉丁字符。成为a等。@ahmetalpbalkan我同意Kathy的观点,您可以将其用作构建自己的查找表的资源,逻辑应该非常简单。不幸的是,似乎没有Java版本。
Daniel Vandersluis,2009年

@ahmetalpbalkan这是Java的unidecode
Jakub Jirutka

4

没有简单或通用的方法可以执行您想要的操作,因为您的主观意见是,这些字母看起来很想转换为拉丁字母。它们实际上是具有各自不同名称和声音的单独字母,只是在表面上看起来像是拉丁字母。

如果要进行这种转换,则必须根据您认为非拉丁字母应转换为哪些拉丁字母来创建自己的转换表。

(如果您只想删除变音符号,则此线程中有一些答案:如何从.NET中的字符串中删除变音符号(重音符号?但是您描述了一个更普遍的问题)


+1。这是“删除变音符号”问题的Java版本:stackoverflow.com/questions/1016955/… ; 参见迈克尔·伯格沃德(Michael Borgwardt)和德维奥(devio)的答案
Jonik)2009年


4

将任意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...
}

我同意。您应该创建一个专门针对您的应用程序和预期受众的转换字典。例如,对于一个讲西班牙语的观众,我只会翻译ÁÉÍÓÚÜÑáéíóúü¿¡
罗伯托Bonvallet

罗伯托(Roberto)有成千上万个字符,我不能做这本手册。
AhmetB-Google 2009年

2
您使用的是具有数千个字符的人类语言?日本?您希望どうしようとしていますか会被转换成什么?
Dour High Arch

6
您提供的示例并不理想:U + 00DF拉丁文小写字母SHARP S“ß”与U + 03B2希腊文小写字母Beta“β”不是相同的Unicode字母。
约阿希姆·绍尔

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.