2017-02-22 10 views
0

특정 문장의 색인을 생성해야하는 응용 프로그램을 작성 중입니다. 현재 Java 및 PostgreSQL을 사용 중입니다. 문장은 악센트와 다른 비 ASCII 기호를 사용하여 프랑스어 및 스페인어와 같은 여러 언어로 표시 될 수 있습니다.색인 생성을 위해 문자열을 ASCII 7 문자로 줄이는 방법은 무엇입니까?

각 단어에 대해 사용자가 악센트 (음역)에 민감하지 않은 검색을 수행 할 수 있도록 색인 가능 항목을 만들고 싶습니다. 예를 들어, 사용자가 "nacion"을 검색하면 응용 프로그램에 저장된 원래 단어가 "Naci ó n"이더라도 찾아야합니다.

가장 좋은 전략은 무엇일까요? 필자는 반드시 PostgreSQL에만 국한되지는 않으며 내부 색인 값도 원래 단어와 유사해야합니다. 이상적으로는 유니 코드 문자열을 대/소문자 구분없이 ASCII 문자열로 변환하는 일반적인 솔루션이어야합니다.

지금까지 색인 된 값을 저장하기 전에 일부 문자를 ASCII로 대체 한 다음 쿼리 문자열에서 동일하게 수행하는 사용자 정의 함수를 사용하고 있습니다.

public String toIndexableASCII (String sStrIn) { 
    if (sStrIn==null) return null; 
    int iLen = sStrIn.length(); 
    if (iLen==0) return sStrIn; 
    StringBuilder sStrBuff = new StringBuilder(iLen); 
    String sStr = sStrIn.toUpperCase(); 

    for (int c=0; c<iLen; c++) { 
    switch (sStr.charAt(c)) { 
     case 'Á': 
     case 'À': 
     case 'Ä': 
     case 'Â': 
     case 'Å': 
     case 'Ã': 
     sStrBuff.append('A'); 
     break; 
     case 'É': 
     case 'È': 
     case 'Ë': 
     case 'Ê': 
     sStrBuff.append('E'); 
     break; 
     case 'Í': 
     case 'Ì': 
     case 'Ï': 
     case 'Î': 
     sStrBuff.append('I'); 
     break; 
     case 'Ó': 
     case 'Ò': 
     case 'Ö': 
     case 'Ô': 
     case 'Ø': 
     sStrBuff.append('O'); 
     break; 
     case 'Ú': 
     case 'Ù': 
     case 'Ü': 
     case 'Û': 
     sStrBuff.append('U'); 
     break; 
     case 'Æ': 
     sStrBuff.append('E'); 
     break; 
     case 'Ñ': 
     sStrBuff.append('N'); 
     break; 
     case 'Ç': 
     sStrBuff.append('C'); 
     break; 
     case 'ß': 
     sStrBuff.append('B'); 
     break; 
     case (char)255: 
     sStrBuff.append('_'); 
     break; 
     default: 
     sStrBuff.append(sStr.charAt(c)); 
    } 
    } 

    return sStrBuff.toString(); 
} 
+0

ASCII 7로 바이트를 해석하면 달성하려는 "정보 손실"을 제공하지 않습니다. "coraçón"이 "coracon"과 같아서 검색 할 때 사용자가 액센트를 넣었는지 여부는 중요하지 않습니다. Google과 같은 맞춤법 검사 나 근접 검사가 필요하지 않습니다. "그게 ...?" 하지만 "é"== "e"가 필요합니다. –

+1

요청한 매핑을 "음역"이라고합니다. –

+0

감사합니다. 나는 음역을 추가하는 질문을 편집했고, Google에 도움이되었다. –

답변

2
String s = "Nación"; 

    String x = Normalizer.normalize(s, Normalizer.Form.NFD); 

    StringBuilder sb=new StringBuilder(s.length()); 
    for (char c : x.toCharArray()) { 
     if (Character.getType(c) != Character.NON_SPACING_MARK) { 
      sb.append(c); 
     } 
    } 

    System.out.println(s); // Nación 
    System.out.println(sb.toString()); // Nacion 

이 작동 방법 : 그것은 NFD 분해 (óo◌́됩니다)에 국제 문자를 분할 한 다음 결합 구별 부호를 제거합니다.

Character.NON_SPACING_MARK에는 분음 기호 (유니 코드는 Bidi 클래스 NSM [Non-Spacing Mark])가 포함되어 있습니다.

+1

정규화 된 버전을 저장하는 것과는 대조적으로 ** 두 문자열을 비교하려면 ** 보다 견고한 솔루션을 사용할 수 있습니다. http://stackoverflow.com/questions/12889760/sort-list-of-strings-with-localization을 참조하십시오. –

1

현재 코드에 대한 하나 개의 명백한 개선 : 당신의 매핑으로 Map<Character, Character> 당신 에 미리 작성된를 사용합니다.

그런 다음지도에 매핑이 있는지 간단히 확인하십시오. 그렇게; 그것을 사용하십시오; 그렇지 않으면 원래 문자를 사용하십시오.

Androbin이 설명 하듯이 객체에 의존하지 않고 trove과 같은 기본 유형으로 작업하는 특수한지도가 있습니다. 따라서 솔루션과 요구 사항에 따라 다릅니다. 너는 그것을 들여다 볼 수있다.

+0

고맙게도 Map # getOrDefault가 있습니다 – Androbin

+0

효율성을 위해 기본 맵을 권장합니다. – Androbin

+0

예를 들어 FastUtil, HPPC, Koloboke 및 Trove가 있습니다. – Androbin