24

Suppose I have a string that contains Ü. How would I find all those unicode characters? Should I test for their code? How would I do that?

For example, given the string "AÜXÜ", I'd like to transform it to "AYXY". I'd like to do the same for other unicode characters, and I would hate to have to store them in a translation map of some sort.

Geo
  • 93,257
  • 117
  • 344
  • 520
  • 3
    How do you know what Ü will map to without your own map? There is no simple mapping and I suspect in different languages any mapping might differ – mmmmmm Nov 04 '09 at 12:44
  • actually you can do it by looking at chars one by one. It depends the "range" of the char, but it's quiet low level, and I assume there already exists something to achieve this task. see http://en.wikipedia.org/wiki/Unicode – Aif Nov 04 '09 at 12:45
  • Also see the solution here: https://rosettacode.org/wiki/Strip_control_codes_and_extended_characters_from_a_string#Java – Stan Nov 11 '16 at 11:50

6 Answers6

16

You could loop through your string and for every character call

If (Character.UnicodeBlock.of(c) != Character.UnicodeBlock.BASIC_LATIN) {
 // replace with Y
}
jitter
  • 53,475
  • 11
  • 111
  • 124
  • Good one to test codepoints, but I don't have the impression that he want to replace *every* character by Y. – BalusC Nov 04 '09 at 12:50
  • Well he says unicode characters by that I understand that he probably means replace all non ascii characters with Y. whatever – jitter Nov 04 '09 at 12:53
15

The definition of "unicode characters" is vague, but will be taken to mean UTF-8 characters not covered by the standard ISO 8859 charset. If this is true in your case, then loop through all characters in the String and test its codepoint to determine whether it is within the given character set.

Alternatively, use a Map<Character, Character> and characters in the map that contain match the keys. For example:

Map<Character, Character> charReplacementMap = new HashMap<Character, Character>() {{
    put('Ü', 'Y');
    // Put more here.
}};

String originalString = "AÜAÜ";
StringBuilder builder = new StringBuilder();

for (char currentChar : originalString.toCharArray()) {
    Character replacementChar = charReplacementMap.get(currentChar);
    builder.append(replacementChar != null ? replacementChar : currentChar);
}

String newString = builder.toString();

Or, do you mean "all characters with diacritics"? If so, then use java.text.Normalizer to remove diacritical marks:

/**
 * Remove any diacritical marks (accents like ç, ñ, é, etc) from
 * the given string (so that it returns plain c, n, e, etc).
 * @param string The string to remove diacritical marks from.
 * @return The string with removed diacritical marks, if any.
 */
public static String removeDiacriticalMarks(String string) {
    return Normalizer.normalize(string, Form.NFD)
        .replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
}

One pitfall, Ü would become U, not Y. Not sure if that's what you're after. If you want to replace by pronounced character, you'll really need to create a mapping. Sure, it's a tedious work, but it's done in less time than you needed to follow this topic.

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • It's how I usually did it. But this would require you add each character in the map. – Geo Nov 04 '09 at 12:49
  • I don't see any other efficient option to replace a certain character by a certain character and that for more than one character. – BalusC Nov 04 '09 at 12:52
  • 1
    If you don't add each character to the map, how do you define the replacement? Or do you want all non-ascii characters replaced by a single ascii character? – C. Ross Nov 04 '09 at 12:52
  • @BalusC - actually, the real definition of what is a Unicode character (codepoint) is very precise. The problem is that the OP does not understand that the ASCII characters are a proper subset of the Unicode codepoints. – Stephen C Nov 04 '09 at 12:54
  • Or do you just want to remove diacritical marks? I've edited my post with it. – BalusC Nov 04 '09 at 12:54
  • That normalizer was really great. Now I don't need to replace anything anymore. Will this work regardless of encoding? – Geo Nov 04 '09 at 13:03
  • @Geo NFD form will separate combined characters into a separate character and accent (NFC does the opposite). `"\\p{InCombiningDiacriticalMarks}+"` will match the accents for replacement. But do you need to handle Greek letters, or Japanese text, and so on? – McDowell Nov 04 '09 at 13:31
  • @McDowell: sounds like Turkish only. At least, I don't know any other language where Ü is pronounced as Y. – BalusC Nov 04 '09 at 13:46
12

You could go the other way round and ask if the character is an ascii character.

public static boolean isAscii(char ch) {
    return ch < 128;
}

You'd have to analyse the string char by char then of course.

(the method is from commons-lang CharUtils which contains loads of useful Character methods)

msp
  • 3,272
  • 7
  • 37
  • 49
2

It isn't clear to me exactly what is gained by transforming "AÜXÜ" to "AYXY". Is this because Ü is pronounced like Y in a particular language? What language? And what other rules might apply?


In terms of terminology...

"a"

The above is a Unicode string. It contains a single UTF-16 encoded character.

If you wish to limit the range of characters to the English alphabet, have a look at the Normalization performed in this answer.

Community
  • 1
  • 1
McDowell
  • 107,573
  • 31
  • 204
  • 267
  • It was just a replacement example. I'll actually replace the character by `_XX_` :) – Geo Nov 04 '09 at 12:53
1

I'm not sure from your example what you're trying to do - if you're just trying to replace all non-ASCII values with Y, then you could loop through the string looking for codepoints outside of the range 0 to 127, and replace them those code points with Y.

Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212
0

The class Character also offers some interesting methods. Take a look at it.

Character.UnicodeBlock.of('a') == Character.UnicodeBlock.BASIC_LATIN; //true

Character.UnicodeBlock.of('�') == Character.UnicodeBlock.BASIC_LATIN; //false
Aliaxander
  • 2,547
  • 4
  • 20
  • 45