2010-07-09 99 views
11

我用变音字符一些比利时城市列表:(列日,Quiévrain,Franière等),我想改变这些特殊字符与包含大写字母相同名称的列表进行比较,但没有变音符号(列日,QUIEVRAIN,FRANIERE)有特殊字符比较词时忽略变音字符(E,E,...)

是我第一次尝试做的是使用大写:

LIEGE.contentEqual(Liège.toUpperCase())但这并不合适,因为Liège的大写字母是LIÈGE而不是LIEGE

我有一些复杂的想法,如替换每个字符,但这听起来很愚蠢和一个漫长的过程。

有关如何以智能的方式做到这一点的任何想法?

+0

类似的问题,包括Java答案http://stackoverflow.com/questions/249087/how-do-i-remove-diacritics-accents-from-a-string-in-net – Rup 2010-07-09 11:03:59

+0

可能重复的[转换符号,重音字母to English Alphabet。](http://stackoverflow.com/questions/1008802/converting-symbols-accent-letters-to-english-alphabet) – Pentium10 2010-07-09 11:18:42

+0

感叹!过去,你可以在360上使用单一的“TR”指令来做到这一点,但从那时起事情就变得更加复杂了。 – 2012-10-16 21:05:31

回答

7

在Java中

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"; 

    /** 
    * remove accented from a string and replace with ascii equivalent 
    */ 
    public static String removeAccents(String s) { 
     if (s == null) 
      return null; 
     StringBuilder sb = new StringBuilder(s.length()); 
     int n = s.length(); 
     int pos = -1; 
     char c; 
     boolean found = false; 
     for (int i = 0; i < n; i++) { 
      pos = -1; 
      c = s.charAt(i); 
      pos = (c <= 126) ? -1 : UNICODE.indexOf(c); 
      if (pos > -1) { 
       found = true; 
       sb.append(PLAIN_ASCII.charAt(pos)); 
      } else { 
       sb.append(c); 
      } 
     } 
     if (!found) { 
      return s; 
     } else { 
      return sb.toString(); 
     } 
    } 
+0

这种方法看起来漫长而复杂,但这是我成功使用的唯一方法! 2其他人似乎更好,但不起作用。非常感谢。 – 2010-07-09 11:43:35

+0

你怎么能说Collat​​or不起作用? 有了它,你不必使用等于,但你必须与0. – 2010-07-09 12:28:18

+0

这是容易出错。你可以忘记字母,比如'ø',不是? – 2010-07-09 18:17:45

1

Collat​​or类是做到这一点(见相应javadoc)的好方法。这是一个单元测试,展示了如何使用它:

import static org.junit.Assert.assertEquals; 

import java.text.Collator; 
import java.util.Locale; 

import org.junit.Test; 

public class CollatorTest { 
    @Test public void liege() throws Exception { 
     Collator compareOperator = Collator.getInstance(Locale.FRENCH); 
     compareOperator.setStrength(Collator.PRIMARY); 

     assertEquals(0, compareOperator.compare("Liege", "Liege")); // no accent 
     assertEquals(0, compareOperator.compare("Liège", "Liege")); // with accent 
     assertEquals(0, compareOperator.compare("LIEGE", "Liege")); // case insensitive 
     assertEquals(0, compareOperator.compare("LIEGE", "Liège")); // case insensitive with accent 

     assertEquals(1, compareOperator.compare("Liege", "Bruxelles")); 
     assertEquals(-1, compareOperator.compare("Bruxelles", "Liege")); 
    } 
} 

编辑: 遗憾地看到我的回答没有满足您的需求;也许这是因为我已经把它作为单元测试来呈现?这适合你吗?我personnaly更好地找到它,因为它是和它使用的SDK(不需要的字符串替换)

Collator compareOperator = Collator.getInstance(Locale.FRENCH); 
compareOperator.setStrength(Collator.PRIMARY); 
if (compareOperator.compare("Liège", "Liege") == 0) { 
    // if we are here, then it's the "same" String 
} 

希望这有助于

+0

与变换相关的问题,即去除变音符号,而不仅仅是比较。 – 2012-08-07 15:41:17

+0

这不是我读这个问题的方式:最终目标是*比较*字符串,但他只是在比较之前考虑转换:“我想转换这些特殊字符进行比较”。在我的回答中,你不需要改变比较'这就是为什么我仍然认为我的答案是有用的。 – 2012-09-05 09:58:26

14

至于退房这种方法你可以使用java.text.Normalizer:

public String unaccent(String s) { 
    String normalized = Normalizer.normalize(s, Normalizer.Form.NFD); 
    return normalized.replaceAll("[^\\p{ASCII}]", ""); 
} 

注意,在Java 5中也有sun.text.Normalizer,但强烈不鼓励其使用,因为它是Sun的专有API的一部分,并在Java中已被删除6

+0

不幸的是,我猜Android SDK不提供我最新的Java 6功能... 我收到此消息:“Normalizer无法解析“并且我无法导入java.text.Normalizer – 2010-07-09 11:38:32

+1

仅供参考Java 1.5在Android上,所以没有Normalizer – Pentium10 2010-07-09 12:24:42

+0

不错!我不知道这个API(但我仍然在使用Java 1.5) 谢谢 – 2010-07-09 18:20:46

6

这也是迄今为止它,我发现最简单的解决方案适用于我们的应用程序。

Normalizer.normalize(string, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); 

但是我不知道Normalizer是否可以在Android平台上使用。

+0

仅供参考Java 1.5在Android上,所以没有Normalizer – Pentium10 2010-07-09 12:25:16

+0

这两个步骤通过StringUtils.stripAccents合并为一个,它使用sun.text.Normalizer在java之前6 http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/StringUtils.html – cquezel 2013-05-31 19:26:20

3

如果您仍然需要为Android API 8或更低(Android 2.2系统,Java 1.5中),您不必正规化类,这里是我的代码,我觉得比Pentium10回答修改:

public class StringAccentRemover { 

    @SuppressWarnings("serial") 
    private static final HashMap<Character, Character> accents = new HashMap<Character, Character>(){ 
     { 
      put('Ą', 'A'); 
      put('Ę', 'E'); 
      put('Ć', 'C'); 
      put('Ł', 'L'); 
      put('Ń', 'N'); 
      put('Ó', 'O'); 
      put('Ś', 'S'); 
      put('Ż', 'Z'); 
      put('Ź', 'Z'); 

      put('ą', 'a'); 
      put('ę', 'e'); 
      put('ć', 'c'); 
      put('ł', 'l'); 
      put('ń', 'n'); 
      put('ó', 'o'); 
      put('ś', 's'); 
      put('ż', 'z'); 
      put('ź', 'z'); 
     } 
    }; 
    /** 
    * remove accented from a string and replace with ascii equivalent 
    */ 
    public static String removeAccents(String s) { 
     char[] result = s.toCharArray(); 
     for(int i=0; i<result.length; i++) { 
      Character replacement = accents.get(result[i]); 
      if (replacement!=null) result[i] = replacement; 
     } 
     return new String(result); 
    } 

} 
0

由于类Normalizer在升级Froyo或以前的Android版本不支持,我已经联合thisthis(我都投了),和优化它,获得一对夫妇的辅助方法。方法未识别只是将变音符转换为普通字符,而方法slugify生成输入字符串的塞。希望对某人有用。这里是源代码:

import java.util.Arrays; 
import java.util.Locale; 
import java.util.regex.Pattern; 

public class SlugFroyo { 
    private static final Pattern STRANGE = Pattern.compile("[^a-zA-Z0-9-]"); 
    private static final Pattern WHITESPACE = Pattern.compile("[\\s]"); 

    private static final String DIACRITIC_CHARS = "\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 static final String PLAIN_CHARS = "AaEeIiOoUu" // grave 
      + "AaEeIiOoUuYy" // acute 
      + "AaEeIiOoUuYy" // circumflex 
      + "AaOoNn" // tilde 
      + "AaEeIiOoUuYy" // umlaut 
      + "Aa" // ring 
      + "Cc" // cedilla 
      + "OoUu"; // double acute 

    private static char[] lookup = new char[0x180]; 

    static { 
     Arrays.fill(lookup, (char) 0); 
     for (int i = 0; i < DIACRITIC_CHARS.length(); i++) 
      lookup[DIACRITIC_CHARS.charAt(i)] = PLAIN_CHARS.charAt(i); 
    } 

    public static String slugify(String s) { 
     String nowhitespace = WHITESPACE.matcher(s).replaceAll("-"); 
     String unaccented = unaccentify(nowhitespace); 
     String slug = STRANGE.matcher(unaccented).replaceAll(""); 
     return slug.toLowerCase(Locale.ENGLISH); 
    } 

    public static String unaccentify(String s) { 
     StringBuilder sb = new StringBuilder(s); 
     for (int i = 0; i < sb.length(); i++) { 
      char c = sb.charAt(i); 
      if (c > 126 && c < lookup.length) { 
       char replacement = lookup[c]; 
       if (replacement > 0) 
        sb.setCharAt(i, replacement); 
      } 
     } 
     return sb.toString(); 
    } 
}