기호, 악센트 문자를 영어 알파벳으로 변환


129

문제는 아시다시피 유니 코드 차트에 수천 개의 문자 가 있으며 모든 유사한 문자를 영어 알파벳 문자로 변환하고 싶습니다.

예를 들어 다음은 몇 가지 변환입니다.

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

그리고 A / a가 20 개가 넘는 버전이 있다는 것을 알았습니다. 그리고 그것들을 분류하는 방법을 모르겠습니다. 그들은 건초 더미에서 바늘처럼 보입니다.

유니 코드 문자의 전체 목록은 http://www.ssec.wisc.edu/~tomw/java/unicode.html 또는 http://unicode.org/charts/charindex.html에 있습니다 . 아래로 스크롤하여 글자의 변형을보십시오.

이 모든 것을 Java로 어떻게 변환 할 수 있습니까? 도와주세요 :(


이 질문을 참조하십시오 : stackoverflow.com/questions/249087/…- 이 주제에 대한 다른 질문이 있지만 지금은 찾을 수 없습니다.
schnaader 2016 년

1
세 번째 예는 Ȳ → Y 여야합니까?
Dour High Arch

2
왜 이러고 싶니? 귀하의 전반적인 목표가 무엇인지 알면 더 도움이 될 수 있습니다.
David Thornley

데이비드 당신은 일부 EMO가 문장에서 다른 문자를 사용한다는 것을 알고 있습니다. 여기 예가 있습니다 : ฬ. ¢. tђє ฬ ย η∂єг ¢ ค ק ђ Ŧ ค ๓ เ ℓy <-이것을 해결하십시오 :) @schnaader, 나는 그것이 내가 찾고 있지만 Java에서는 그렇지 않다고 생각합니다.
AhmetB-Google

이 대화는 전에 이루어졌습니다-위의 @schnaader를 참조하십시오.
dkretz 2016 년

답변:


197

.NET의 문자열에서 분음 부호 (악센트)어떻게 제거합니까? 에서 게시물 다시 게시

이 방법은 자바에서 잘 작동합니다 (순수하게 발음 구별 부호를 제거하기 위해) .

기본적으로 악센트 부호가있는 모든 문자를 악센트 부호가없는 상대 문자로 변환 한 다음 분음 부호를 조합합니다. 이제 정규 표현식을 사용하여 분음 부호를 제거 할 수 있습니다.

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 또는 다른 것으로 변환 할 수 있다면 좋을 것입니다
iwein

13
전혀 음역하지 않습니다. 분해 된 분음 부호 ( "악센트") 만 제거합니다. 이전 단계 (Form.NFD)는 a + '로 분류됩니다. 즉, 강조된 문자를 강조되지 않은 문자와 발음 구별 부호로 분해합니다. 이것은 키릴 Ѽ을 Ѡ로 변환하지만 더 이상은 아닙니다.
MSalters

1
조지는 더 나은에서 대신 \\ P {InCombiningDiacriticalMarks}의 \\의 P {주의}을 사용할 수 게시 glaforge.appspot.com/article/... 나는 그것을 테스트하지 않습니다.
ATorras

2
\\ p {IsM}은 á ó ú ñ é í와 같은 스페인어 악센트에 대해서는 작동하지 않는 것 같습니다. 반대로, "\\ p {InCombiningDiacriticalMarks} +는 이것을 위해 잘 작동합니다
Loic

모든 특수 문자에 대해 작동하지는 않습니다. Android에서 잘못된 문제를 제출하여 해당 정보를 알 수 없었습니다.-> code.google.com/p/android/issues/detail?id=189515 올바른 방법을 아는 사람이 있습니까?
Michał Tajchert

71

아파치 커먼즈 랭 의 일부입니다 . 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
내 경우에는 아파치 공통으로 : DJ가되지 D로 변환
호앙

@Hoang, Robert 아마 풀 요청을 보낼 수있는 기회 :)
Ondra Žižka

19

"모두 변환"을 시도하는 것은 문제에 대한 잘못된 접근입니다.

첫째, 당신이하려는 일의 한계를 이해해야합니다. 다른 사람들이 지적했듯이 분음 부호는 이유가 있습니다. 그들은 본질적으로 그 언어의 알파벳에서 고유 한 의미 / 소리 등을 가진 독특한 문자입니다. 그러한 표시를 제거하는 것은 영어 단어에서 임의의 문자를 바꾸는 것과 같습니다. 이것은 키릴 자모 언어와 아랍어와 같은 다른 스크립트 기반 텍스트를 고려하기 전에 진행됩니다.이 텍스트는 단순히 영어로 "변환"될 수 없습니다.

어떤 이유로 든 문자를 변환 해야하는 경우 ,이를 처리하는 유일한 현명한 방법으로 먼저 작업의 범위를 줄입니다. 입력의 소스를 고려하십시오- "서구 세계"에 대한 응용 프로그램을 코딩하는 경우 (어구처럼 좋은 문구를 사용하는 경우) 아랍어 문자를 구문 분석해야 할 가능성은 거의 없습니다. 마찬가지로 유니 코드 문자 집합에는 수백 개의 수학 및 그림 기호가 포함됩니다. 사용자가 직접 입력 할 수있는 쉬운 방법이 없으므로 무시할 수 있습니다.

이러한 논리적 단계를 수행하면 사전 기반 조회 / 바꾸기 작업이 가능한 지점으로 구문 분석 할 수있는 문자 수를 줄일 수 있습니다. 그런 다음 사전을 만드는 소량의 약간 지루한 작업과 교체를 수행하는 사소한 작업이됩니다. 언어가 기본 유니 코드 문자를 지원하고 (Java에서와 같이) 정적 구조를 올바르게 최적화하면 이러한 찾기 및 바꾸기는 맹목적으로 빠른 경향이 있습니다.

이는 최종 사용자가 분음 부호 문자가 포함 된 서지 데이터를 검색하는 데 필요한 응용 프로그램에서 작업 한 경험에서 비롯됩니다. 룩업 어레이는 (우리의 경우와 마찬가지로) 모든 서유럽 언어에 대한 모든 분음 부호를 포함하기 위해 1 일이 소요되었습니다.


답변 해 주셔서 감사합니다. 사실 저는 아랍어 나 그와 비슷한 것을 다루지 않습니다. 당신은 일부 사람들이 분음 부호를 재미있는 문자로 사용한다는 것을 알고 있습니다. 예를 들어, 예제에서 "tђє Ŧ ค ๓ เ ℓy-> Family"변환이라고 말했지만 완전히 변환하기는 어렵습니다. 그러나 간단한 방법으로 "òéışöç-> oeisoc"변환을 수행 할 수 있습니다. 그러나 이것을하는 정확한 방법은 무엇입니까? 배열을 만들고 수동으로 교체 하시겠습니까? 아니면이 언어 에이 문제에 대한 기본 기능이 있습니까?
AhmetB-Google

15

"패밀리"를 "tђє Ŧ ค ๓ เ ℓy"로 변환하는 인코딩은 사실상 임의적이며 관련 유니 코드 코드 포인트의 정보로 설명 할 수있는 알고리즘을 따르지 않기 때문에이 알고리즘을 알고리즘 적으로 해결할 수있는 일반적인 방법은 없습니다.

유니 코드 문자를 유사한 라틴 문자로 매핑해야합니다. 유니 코드 코드 포인트를 나타내는 실제 글리프에 대한 일부 스마트 머신 러닝 으로이 작업을 수행 할 수 있습니다. 그러나 나는 이것을 위해 노력하는 것이 수동으로 그 매핑을 구축하는 것보다 클 것이라고 생각합니다. 특히 당신이 당신의 매핑을 구축 할 수있는 많은 양의 예제가 있다면.

명확히하기 위해 : 대체의 일부는 실제로 유니 코드 데이터를 통해 해결할 수 있지만 (다른 답변이 보여주는 것처럼) 일부 문자는 라틴 문자와 비슷한 연관성이 없습니다.

예 :

  • "ђ"(U + 0452 CYRILLIC SMALL LETTER DJE)는 "h"보다 "d"와 관련이 있지만 "h"를 나타내는 데 사용됩니다.
  • "Ŧ"(U + 0166 라틴 대문자 문자 T 스트로크)은 "T"(이름에서 알 수 있듯이)와 다소 관련이 있지만 "F"를 나타내는 데 사용됩니다.
  • "ค"(U + 0E04 THAI CHARACTER KHO KHWAI)는 라틴 문자와 전혀 관련이 없으며 귀하의 예에서 "a"를 나타내는 데 사용됩니다

7

원래 요청은 이미 답변되었습니다.

그러나 자바에서 라틴어 / 영어로 문자 세트를 음역하기 위해 일반 음역 코드를 찾고있는 사람들을 위해 아래 답변을 게시하고 있습니다.

음역의 순진한 의미 : 최종 형식의 번역 된 문자열 / 대상 문자 집합은 원래 형식의 문자열과 같은 소리가납니다. 문자셋을 라틴어 (영어 알파벳)로 음역하려면 ICU4 (java의 ICU4J 라이브러리)가 작동합니다.

다음은 자바의 코드 스 니펫입니다.

    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 2016

이 방법은 분음 부호의 클래스를 다르게 감지하고 처리해야하는 경우 (예 : LaTeX에서 특수 문자 이스케이프 처리) 특히 유용합니다.
vallismortis 2016 년

4

루비 젬cpan펄 모듈unidecode제공되는을 사용해보십시오 . 본질적으로, 각 유니 코드 코드 포인트가 ASCII 문자 또는 문자열과 관련되는 거대한 조회 테이블로 작동합니다.


이 중 하나에서 룩업 테이블을 얻을 수 있습니다.
Kathy Van Stone

이것은 놀라운 패키지이지만 캐릭터의 소리를 음역합니다. 예를 들어 "북"을 "베이"로 변환하면 캐릭터가 북경어처럼 들리기 때문입니다. 질문자는 글리프를 시각적으로 영어와 비슷한 것으로 변환하려고한다고 생각합니다.
Dour High Arch 2016

그러나 라틴 문자의 경우 그렇게합니다. · 등이됩니다. @ahmetalpbalkan 캐시에 동의합니다. 캐시 테이블을 작성하는 데 리소스로 사용할 수 있습니다. 논리는 매우 간단합니다. 불행히도 Java 버전이없는 것 같습니다.
Daniel Vandersluis 2016 년

@ahmetalpbalkan 다음은 unidecode Java 용.
야쿱 Jirutka

4

이 문자들이 당신이 변환하고자하는 라틴 문자를 닮았다는 주관적인 의견이기 때문에 원하는 것을하는 쉬운 방법이나 일반적인 방법은 없습니다. 그것들은 실제로 별개의 이름과 소리를 가진 별개의 문자이며, 라틴 문자처럼 생겼습니다.

해당 변환을 원할 경우 비 라틴 문자가 변환되어야하는 라틴 문자를 기반으로 고유 한 변환 테이블을 작성해야합니다.

(만 diacritial 마크를 제거하려는 경우,이 스레드의 일부 답변이 있습니다 : ? 내가 .NET에서 문자열에서 분음 부호 (악센트)를 제거하려면 어떻게해야 좀 더 일반적인 문제를 설명하지만)


+1. 다음은 '분음 부호 제거'질문의 Java 버전입니다. stackoverflow.com/questions/1016955/… ; Michael Borgwardt와 devio의 답변보기
Jonik


4

임의의 유니 코드를 ASCII로 "변환"하는 문제는 문자의 의미가 문화에 따라 다르다는 것입니다. 예를 들어, 독일어를 사용하는 사람에 대한 "ß"는 "ss"로 변환되어야하지만 영어를 사용하는 사람은 "B"로 변환해야합니다.

유니 코드에는 동일한 글리프에 대한 여러 코드 포인트가 있다는 사실을 추가하십시오.

결론은이 작업을 수행 할 수있는 유일한 방법은 각 유니 코드 문자와 변환하려는 ASCII 문자가 포함 된 방대한 테이블을 만드는 것입니다. 정규화 양식 KD에 악센트가있는 문자를 정규화하여 바로 가기를 수행 할 수 있지만 모든 문자가 ASCII로 정규화되는 것은 아닙니다. 또한 유니 코드는 글리프의 어떤 부분이 "악센트"인지 정의하지 않습니다.

다음은이 작업을 수행하는 앱에서 발췌 한 내용입니다.

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

2
"수천"의 문자가있는 어떤 언어를 사용하고 있습니까? 일본어? ど う し よ う と し て ま ま か가 무엇으로 변환 될 것으로 기대하십니까?
Dour High Arch

6
제시 한 예는 이상적이지 않습니다. U + 00DF 라틴 소형 문자 샤프 S "ß"는 U + 03B2 녹색 소형 문자 베타 "β"와 동일한 유니 코드 문자가 아닙니다.
Joachim Sauer

2

다음 클래스는 트릭을 수행합니다.

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.