views:

546

answers:

6

In PHP I would use this:

$text = "Je prends une thé chaud, s'il vous plaît";
$search = array('é','î','è'); // etc.
$replace = array('e','i','e'); // etc.
$text = str_replace($search, $replace, $text);

But the Java String method "replace" doesn't seem to accept arrays as input. Is there a way to do this (without having to resort to a for loop to go through the array)?

Please say if there's a more elegant way than the method I'm attempting.

+1  A: 

You're going to have to do a loop:

String text = "Je prends une thé chaud, s'il vous plaît";
Map<Character, String> replace = new HashMap<Character, String>();
replace.put('é', "e");
replace.put('î', "i");
replace.put('è', "e");
StringBuilder s = new StringBuilder();
for (int i=0; i<text.length(); i++) {
  char c = text.charAt(i);
  String rep = replace.get(c);
  if (rep == null) {
    s.append(c);
  } else {
    s.append(rep);
  }
}
text = s.toString();

Note: Some characters are replaced with multiple characters. In German, for example, u-umlaut is converted to "ue".

Edit: Made it much more efficient.

cletus
Except in Java. (Sorry, couldn't resist.)
Samir Talwar
Ugh. Please don't use the regexp-based method for that.
Michael Borgwardt
On second glance, I suppose you have to if you want to replace single characters with multiple ones, but I'm not sure the OP wants that. It would have to be implemented on a per-locale basis and probably end in an ad-hoc mess - I don't think all languages have clear-cut established rules for substituting accented characters like German has.
Michael Borgwardt
This will be very inefficient for long strings (O(n^2)), because for each accented character the whole string is traversed.
starblue
A: 

There's no standard method as far as I know, but here's a class that does what you want:

http://www.javalobby.org/java/forums/t19704.html

finnw
A: 

You'll need a loop.

An efficient solution would be something like the following:

    Map<Character, Character> map = new HashMap<Character, Character>();
    map.put('é', 'e');
    map.put('î', 'i');
    map.put('è', 'e');

    StringBuilder b = new StringBuilder();
    for (char c : text.toCharArray())
    {
        if (map.containsKey(c))
        {
            b.append(map.get(c));
        }
        else
        {
            b.append(c);
        }
    }
    String result = b.toString();

Of course in a real program you would encapsulate both the construction of the map and the replacement in their respective methods.

starblue
+2  A: 

There's no method that works identically to the PHP one in the standard API, though there may be something in Apache Commons. You could do it by replacing the characters individually:

s = s.replace('é','e').replace('î', 'i').replace('è', 'e');

A more sophisticated method that does not require you to enumerate the characters to substitute (and is thus more likely not to miss anything) but does require a loop (which will happen anyway internally, whatever method you use) would be to use java.text.Normalizer to separate letters and diacritics and then strip out everything with a character type of Character.MODIFIER_LETTER.

Michael Borgwardt
+3  A: 

A really nice way to do it is using the replaceEach() method from the StringUtils class in Apache Commons Lang 2.4.

String text = "Je prends une thé chaud, s'il vous plaît";
String[] search = new String[] {"é", "î", "è"};
String[] replace = new String[] {"e", "i", "e"};
String newText = StringUtils.replaceEach(text, 
    search, 
    replace);

Results in

Je prends une the chaud, s'il vous plait
Harry Lime
It's rarely worth adding a library dependency for a function thats trivial to implement.
cletus
Trivial to implement, not so trivial to test maybe. By using a library as widely used as commons-lang you can be reasonably confident that it works well.
Harry Lime
One could just as well say that it's rarely worth re-implementing a utility (adding more of own code to test and maintain) when a perfectly good implementation already exists in a widely-used library.
Jonik
There's almost certainly far more than this one function in Apache Commons that would be useful to your project.
Michael Borgwardt
@Michael: I agree; although you probably meant in Commons *Lang* (as Apache Commons consists of several independently released libraries). @Harry, could you actually correct this in the answer -> "in Apache Commons Lang 2.4"
Jonik
@Jonik Made that change. Thanks.
Harry Lime
+2  A: 

I'm not a Java guy, but I'd recommend a generic solution using the Normalizer class to decompose accented characters and then remove the Unicode "COMBINING" characters.

devio
Michael Borgwardt mentioned stripping out Character.MODIFIER_LETTER chars. Which one is it, or did you basically mean the same thing?
Jonik
+1 Interesting!
starblue
Formally, Unicode category Lm, to which Character.MODIFIER_LETTER corresponds. That's clearly what's needed here: http://www.dpawson.co.uk/xsl/rev2/UnicodeCategories.html. Category Mc "Mark, spacing combining" only seems to apply to certain Asian languages.
Michael Borgwardt
I meant Unicode characters whose name contains "COMBINING". This seems to be the Mn category (Mark, non-spacing) as per Michael's link
devio
Jonik/Michael: Just removing Lm won't work for combined letter like "Æ". You have to do a "KD" normalization before removing Lm.
J-16 SDiZ