Je connais donc String#codePointAt(int)
, mais il est indexé par l'offset char
, pas par l'offset du point de code.
Je pense essayer quelque chose comme:
String#charAt(int)
pour obtenir le char
à un indexchar
est dans la plage plage de substitution élevéeString#codePointAt(int)
pour obtenir le point de code et incrémentez l'index de 2char
donnée comme point de code et incrémentez l'index de 1Mais mes préoccupations sont
char
ou d'une seuleOui, Java utilise un encodage UTF-16-esque pour les représentations internes des chaînes, et, oui, il code des caractères en dehors du plan multilingue de base ( BMP ) en utilisant le schéma de maternité de substitution.
Si vous savez que vous aurez affaire à des caractères en dehors du BMP, voici la manière canonique d'itérer sur les caractères d'une chaîne Java:
final int length = s.length();
for (int offset = 0; offset < length; ) {
final int codepoint = s.codePointAt(offset);
// do something with the codepoint
offset += Character.charCount(codepoint);
}
Java 8 ajouté CharSequence#codePoints
qui renvoie un IntStream
contenant les points de code. Vous pouvez utiliser le flux directement pour les parcourir:
string.codePoints().forEach(c -> ...);
ou avec une boucle for en collectant le flux dans un tableau:
for(int c : string.codePoints().toArray()){
...
}
Ces moyens sont probablement plus chers que solution de Jonathan Feinbergs , mais ils sont plus rapides à lire/écrire et la différence de performances sera généralement insignifiante.
Je pensais que j'ajouterais une méthode de contournement qui fonctionne avec les boucles foreach ( ref ), plus vous pouvez la convertir en Java 8 nouveau String # codePoints facilement lorsque vous passez à Java 8:
Vous pouvez l'utiliser avec foreach comme ceci:
for(int codePoint : codePoints(myString)) {
....
}
Voici l'aide mthod:
public static Iterable<Integer> codePoints(final String string) {
return new Iterable<Integer>() {
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int nextIndex = 0;
public boolean hasNext() {
return nextIndex < string.length();
}
public Integer next() {
int result = string.codePointAt(nextIndex);
nextIndex += Character.charCount(result);
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
Ou alternativement si vous voulez juste convertir une chaîne en un tableau d'int (qui pourrait utiliser plus RAM que l'approche ci-dessus):
public static List<Integer> stringToCodePoints(String in) {
if( in == null)
throw new NullPointerException("got null");
List<Integer> out = new ArrayList<Integer>();
final int length = in.length();
for (int offset = 0; offset < length; ) {
final int codepoint = in.codePointAt(offset);
out.add(codepoint);
offset += Character.charCount(codepoint);
}
return out;
}
Heureusement, l'utilisation de "codePoints" gère en toute sécurité la paire de substitution de l'UTF-16 (représentation de chaîne interne de Java).
L'itération sur les points de code est déposée en tant que demande de fonctionnalité chez Sun.
Voir Sun Bug Entry
Il existe également un exemple sur la façon d'itérer sur String CodePoints.