그래서 나는에 대해 알고 String#codePointAt(int)
있지만 char
코드 포인트 오프셋이 아니라 오프셋에 의해 인덱싱됩니다 .
나는 다음과 같은 것을 시도하는 것에 대해 생각하고 있습니다.
- 인덱스
String#charAt(int)
를 얻기 위해 사용char
- 대리자
char
가 높은 범위 에 있는지 테스트- 그렇다면
String#codePointAt(int)
코드 포인트를 가져오고 인덱스를 2 씩 증가시킵니다. - 그렇지 않은 경우 주어진
char
값을 코드 포인트로 사용 하고 인덱스를 1 씩 증가시킵니다.
- 그렇다면
하지만 내 걱정은
- 당연히 높은 대리 범위에있는 코드 포인트가 두 개의
char
값 으로 저장되는지 아니면 하나의 값 으로 저장되는지 잘 모르겠습니다. - 이것은 문자를 반복하는 끔찍한 비용이 드는 방법처럼 보입니다.
- 누군가 더 나은 것을 생각해 냈을 것입니다.
답변
예, Java는 문자열의 내부 표현을 위해 UTF-16-esque 인코딩을 사용하며, 예, 대리 체계를 사용하여 BMP (Basic Multilingual Plane) 외부의 문자를 인코딩합니다 .
BMP 외부의 문자를 다룰 것이라는 것을 알고 있다면 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);
}
답변
코드 포인트를 포함하는 CharSequence#codePoints
을 반환하는 Java 8이 추가되었습니다 IntStream
. 스트림을 직접 사용하여 반복 할 수 있습니다.
string.codePoints().forEach(c -> ...);
또는 스트림을 배열로 수집하여 for 루프를 사용합니다.
for(int c : string.codePoints().toArray()){
...
}
이러한 방법은 Jonathan Feinbergs의 솔루션 보다 비용이 많이 들지만 읽기 / 쓰기 속도가 더 빠르며 성능 차이는 일반적으로 중요하지 않습니다.
답변
답변
foreach 루프 ( ref ) 와 함께 작동하는 해결 방법을 추가하고 Java 8 로 이동할 때 Java 8의 새로운 String # codePoints 메서드로 쉽게 변환 할 수 있다고 생각했습니다 .
다음과 같이 foreach와 함께 사용할 수 있습니다.
for(int codePoint : codePoints(myString)) {
....
}
다음은 도우미 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();
}
};
}
};
}
또는 문자열을 int 배열로 변환하려는 경우 (위의 접근 방식보다 더 많은 RAM을 사용할 수 있음) :
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;
}
고맙게도 “codePoints”를 사용하여 UTF-16 (자바의 내부 문자열 표현)의 대리 쌍을 안전하게 처리합니다.