StringTokenizer
? 변환 String
A와 char[]
그 이상과 반복 처리? 다른 것?
답변
for 루프를 사용하여 문자열을 반복하고 charAt()
각 문자를 검사하도록합니다. 문자열은 배열로 구현되므로이 charAt()
메서드는 일정한 시간 작업입니다.
String s = "...stuff...";
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
//Process char
}
그게 내가 할 것입니다. 가장 쉬운 것 같습니다.
정확성에 관한 한, 나는 그것이 여기에 있다고 믿지 않습니다. 그것은 모두 당신의 개인적인 스타일에 근거합니다.
답변
두 가지 옵션
for(int i = 0, n = s.length() ; i < n ; i++) {
char c = s.charAt(i);
}
또는
for(char c : s.toCharArray()) {
// process c
}
첫 번째는 아마도 더 빠르며, 두 번째는 더 읽기 쉽습니다.
답변
BMP (Unicode Basic Multilingual Plane ) 외부의 문자 , 즉 u0000-uFFFF 범위를 벗어난 코드 포인트 를 처리하는 경우 여기에 설명 된 다른 기술 대부분이 분류됩니다 . 외부의 코드 포인트는 대부분 죽은 언어에 할당되므로 거의 발생하지 않습니다. 그러나이 밖에는 유용한 표기법이 있습니다. 예를 들어 수학 표기법에 사용되는 코드 포인트와 중국어로 적절한 이름을 인코딩하는 데 사용되는 코드 포인트가 있습니다.
이 경우 코드는 다음과 같습니다.
String str = "....";
int offset = 0, strLen = str.length();
while (offset < strLen) {
int curChar = str.codePointAt(offset);
offset += Character.charCount(curChar);
// do something with curChar
}
이 Character.charCount(int)
방법에는 Java 5 이상이 필요합니다.
답변
StringTokenizer가 여기서 과도하게 사용된다는 데 동의합니다. 실제로 위의 제안을 시도하고 시간이 걸렸습니다.
내 테스트는 매우 간단했습니다. 약 백만 개의 문자로 StringBuilder를 만들고 문자열로 변환 한 다음 charAt () / char 배열로 변환 한 후 / CharacterIterator를 사용하여 천 번 (각각 컴파일러가 전체 루프를 최적화하지 못하도록 문자열에서 무언가를 수행하십시오 :-)).
내 2.6 GHz Powerbook (맥 :-)) 및 JDK 1.5의 결과 :
- 테스트 1 : charAt + String-> 3138msec
- 테스트 2 : 문자열을 배열로 변환-> 9568msec
- 테스트 3 : StringBuilder charAt-> 3536msec
- 테스트 4 : CharacterIterator 및 문자열-> 12151msec
결과가 크게 다르기 때문에 가장 간단한 방법도 가장 빠른 것 같습니다. 흥미롭게도 StringBuilder의 charAt ()는 String보다 약간 느립니다.
BTW 나는 ‘\ uFFFF’문자의 남용을 “반복의 끝”으로 간주하여 CharacterIterator를 사용하지 않는 것이 좋습니다. 큰 프로젝트에는 항상 두 종류의 서로 다른 목적으로 같은 종류의 핵을 사용하는 두 사람이 있으며 코드는 실제로 신비하게 충돌합니다.
테스트 중 하나는 다음과 같습니다.
int count = 1000;
...
System.out.println("Test 1: charAt + String");
long t = System.currentTimeMillis();
int sum=0;
for (int i=0; i<count; i++) {
int len = str.length();
for (int j=0; j<len; j++) {
if (str.charAt(j) == 'b')
sum = sum + 1;
}
}
t = System.currentTimeMillis()-t;
System.out.println("result: "+ sum + " after " + t + "msec");
답변
Java 8 에서는 다음과 같이 해결할 수 있습니다.
String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));
str.codePoints().forEachOrdered(i -> System.out.print((char)i));
chars () 메소드 IntStream
는 doc 에서 언급 한대로를 반환합니다 .
이 순서로부터 char 값을 제로 확장하는 int의 스트림을 돌려줍니다. 대리 코드 포인트에 매핑되는 모든 문자는 해석되지 않은 상태로 전달됩니다. 스트림을 읽는 동안 시퀀스가 변경되면 결과가 정의되지 않습니다.
이 메소드 codePoints()
는 또한 IntStream
문서마다를 반환합니다 .
이 순서로부터 코드 포인트 치의 스트림을 돌려줍니다. 시퀀스에서 발생하는 대리 쌍은 Character.toCodePoint에 의해 결합되고 결과가 스트림으로 전달됩니다. 일반 BMP 문자, 쌍을 이루지 않은 서로 게이트 및 정의되지 않은 코드 단위를 포함한 다른 코드 단위는 int 값으로 0 확장되어 스트림으로 전달됩니다.
문자와 코드 포인트는 어떻게 다릅니 까? 이 기사 에서 언급했듯이 :
유니 코드 3.1은 보충 문자를 추가하여 단일 문자 16 비트로 구별 할 수있는 216 자 이상의 총 문자 수를 가져옵니다
char
. 따라서char
값이 더 이상 유니 코드의 기본 의미 단위에 일대일로 맵핑되지 않습니다. JDK 5는 더 큰 문자 값 세트를 지원하도록 업데이트되었습니다.char
유형 의 정의를 변경하는 대신 새로운 보충 문자 중 일부는 두char
값 의 서로 게이트 쌍으로 표시됩니다 . 이름 혼동을 줄이기 위해 코드 포인트는 보충 문자를 포함하여 특정 유니 코드 문자를 나타내는 숫자를 나타내는 데 사용됩니다.
마지막으로 왜 forEachOrdered
그렇지 forEach
않습니까?
의 동작이 forEach
명확하게 결정적되는 위치로서 forEachOrdered
수행이 스트림의 각 요소에 대한 액션, 스트림의 발생 순서 스트림 정의 발생 순서를 갖는 경우. 따라서 forEach
주문이 유지된다는 보장은 없습니다. 또한이 질문 을 확인하십시오 .
문자, 코드 포인트, 글리프 (glyph) 및 그래 핀 (grapheme)의 차이점에 대해서는 이 질문을 확인하십시오 .
답변
이를위한 몇 가지 전용 클래스가 있습니다.
import java.text.*;
final CharacterIterator it = new StringCharacterIterator(s);
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
// process c
...
}
답변
당신이있는 경우 구아바을 클래스 패스에 다음 꽤 읽을 수있는 대안이다. 구아바는이 경우 상당히 합리적인 사용자 정의 목록 구현을 가지고 있기 때문에 비효율적이지 않아야합니다.
for(char c : Lists.charactersOf(yourString)) {
// Do whatever you want
}
업데이트 : @Alex가 지적했듯이 Java 8에서도 CharSequence#chars
사용해야합니다. 유형조차도 IntStream이므로 다음과 같은 문자로 매핑 할 수 있습니다.
yourString.chars()
.mapToObj(c -> Character.valueOf((char) c))
.forEach(c -> System.out.println(c)); // Or whatever you want