어떤 가장 쉽/최선/가 올바른 방법으로 반복의 캐릭터를 통해 문자열에서 Java?
문제
StringTokenizer
?변환 String
을 char[]
고 반복되는?다른 뭔가?
해결책
나는 루프를 사용하여 문자열을 반복하고 사용합니다. 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 외부의 캐릭터를 다루는 경우 여기에 설명 된 다른 기술의 대부분을 기록하십시오 (유니 코드 기본 다국어 평면), 즉 코드 포인트 U0000-Fuffff 범위 외부에 있습니다. 이 외부의 코드 포인트는 대부분 죽은 언어에 할당되기 때문에 거의 발생하지 않습니다. 그러나이 외부에는 유용한 문자가 있습니다. 예를 들어 수학 표기법에 사용되는 일부 코드 포인트 및 일부는 중국어로 적절한 이름을 인코딩하는 데 사용됩니다.
이 경우 코드는 다음과 같습니다.
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 () / charat ()로 각각을 charat ()로 변환 한 후 (물론 컴파일러가 전체 루프를 최적화 할 수 없도록 문자열에서 무언가를하십시오 :-)).
2.6 GHZ PowerBook (Mac :-)) 및 JDK 1.5의 결과 :
- 테스트 1 : charat + string-> 3138msec
- 테스트 2 : 배열로 변환 된 문자열 -> 9568msec
- 테스트 3 : StringBuilder charat-> 3536msec
- 테스트 4 : 캐릭터 및 문자열 -> 12151msec
결과가 크게 다르기 때문에 가장 간단한 방법도 가장 빠른 방법 인 것 같습니다. 흥미롭게도, StringBuilder의 charat ()는 문자열보다 약간 느린 것 같습니다.
BTW 나는 ' uffff'캐릭터의 남용을 정말 끔찍한 해킹으로 간주 할 때 캐릭터를 사용하지 않는 것이 좋습니다. 큰 프로젝트에는 항상 두 가지 다른 목적으로 동일한 종류의 해킹을 사용하는 두 사람이 있으며 코드는 정말 신비롭게 충돌합니다.
테스트 중 하나입니다.
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");
이를위한 몇 가지 전용 클래스가 있습니다.
import java.text.*;
final CharacterIterator it = new StringCharacterIterator(s);
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
// process c
...
}
당신이 가지고 있다면 구아바 ClassPath에서 다음은 매우 읽기 쉬운 대안입니다. Guava는이 경우에 대해 상당히 현명한 사용자 정의 목록 구현을 가지고 있으므로 비효율적이지 않아야합니다.
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
에 Java8 우리는 그것을 해결할 수 있습니다:
String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));
str.codePoints().forEachOrdered(i -> System.out.print((char)i));
방법은 문자()반환합니다 IntStream
에서 언급했듯이 doc:
스트림을 반환합니다 int 제로 확장하는 문자 값에서 이 시퀀스입니다.모든 문자는 매핑드 대리점은 전달 을 통해 해석되지 않은.는 경우에는 순서가 변화하는 동안 스트림 읽는 것,결과는 정의되지 않습니다.
방법 codePoints()
또한 반환합니다 IntStream
당 doc:
스트림을 반환합니다드점의 값이다.모 대리 쌍에서 발생하는 순으로 결합에 의한 경우 문자입니다.toCodePoint 및 결과 전달됩니다.모 다른 코드 단위를 포함,일반 BMP 문자,짝이 없는 대리고,정의되지 않은 코드 단위로 확장을 int 값 는 다음을 전달됩니다.
는 방법은 문자 및 코드에 지점이 다른가요? 에서 언급했듯이 이 기사:
유니코드 3.1 추가 보완 문자,총을 가져 문자 보다는 더 많은 것 216 수 있는 문자 수 에 의해 구별된 하나의 16 비트
char
.따라서,char
값없 더 이상은 하나를 매핑하는 기본적인 의미에서 단위 유니코드입니다.JDK5 업데이트를 지원하는 더 큰 세트의 문자 값이 있습니다.을 변경하는 대신 정의char
유형의 일부를 새로 보충 자에 의해 표현되는 대리 쌍 의 두 개의char
값이 있습니다.을 줄이는 이름의 혼란,코드 point 을 참조하는 데 사용되는 횟수를 나타내는 특정 유니코드 문자를 포함하여 보충 것들입니다.
마지막으로 이유 forEachOrdered
지 forEach
?
의 행동 forEach
은 명시적으로 비결정적인 곳으로 forEachOrdered
수행 활동의 각 요소에 대한 이 스트림에서 가 발생기의 스트림 으면 스트림에 정의된가 발생할 순서입니다.그래서 forEach
을 보장하지 않는 주문이 되지 않습니다.또한 이 질문 니다.
대 차이 문자 코드점,문자 및 기소 이 질문.
코드 포인트를 반복 해야하는 경우 String
(이것 좀 봐 대답) 더 짧거나 읽기 쉬운 방법은 CharSequence#codePoints
Java 8에 추가 된 방법 :
for(int c : string.codePoints().toArray()){
...
}
또는 루프 대신 스트림을 직접 사용합니다.
string.codePoints().forEach(c -> ...);
도 있습니다 CharSequence#chars
캐릭터의 스트림을 원한다면 ( IntStream
, 없기 때문에 CharStream
).
나는 사용하지 않을 것이다 StringTokenizer
JDK의 클래스 중 하나이므로 유산입니다.
Javadoc의 말 :
StringTokenizer
새로운 코드에서 사용이 권장되지만 호환성 이유로 유지되는 레거시 클래스입니다. 이 기능을 원하는 사람은 누구나 분할 방법을 사용하는 것이 좋습니다.String
아니면 그java.util.regex
대신 패키지.
성능이 필요하다면, 당신은 당신입니다 테스트해야합니다 당신의 환경에서. 다른 방법은 없습니다.
여기에 예제 코드 :
int tmp = 0;
String s = new String(new byte[64*1024]);
{
long st = System.nanoTime();
for(int i = 0, n = s.length(); i < n; i++) {
tmp += s.charAt(i);
}
st = System.nanoTime() - st;
System.out.println("1 " + st);
}
{
long st = System.nanoTime();
char[] ch = s.toCharArray();
for(int i = 0, n = ch.length; i < n; i++) {
tmp += ch[i];
}
st = System.nanoTime() - st;
System.out.println("2 " + st);
}
{
long st = System.nanoTime();
for(char c : s.toCharArray()) {
tmp += c;
}
st = System.nanoTime() - st;
System.out.println("3 " + st);
}
System.out.println("" + tmp);
에 Java 온라인 나는 얻다:
1 10349420
2 526130
3 484200
0
Android x86 API 17에서 나는 얻는다 :
1 9122107
2 13486911
3 12700778
0
보다 Java 튜토리얼 : 문자열.
public class StringDemo {
public static void main(String[] args) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
char[] tempCharArray = new char[len];
char[] charArray = new char[len];
// put original string in an array of chars
for (int i = 0; i < len; i++) {
tempCharArray[i] = palindrome.charAt(i);
}
// reverse array of chars
for (int j = 0; j < len; j++) {
charArray[j] = tempCharArray[len - 1 - j];
}
String reversePalindrome = new String(charArray);
System.out.println(reversePalindrome);
}
}
길이를 넣으십시오 int len
그리고 사용 for
고리.
StringTokenizer는 문자열을 개별 문자로 나누는 작업에 완전히 적합하지 않습니다. 와 함께 String#split()
예를 들어 아무것도 일치하지 않는 정규식을 사용하여 쉽게 할 수 있습니다.
String[] theChars = str.split("|");
그러나 StringTokenizer는 Regexes를 사용하지 않으며 문자간에 아무것도 일치하지 않는 구분 기자 문자열이 없습니다. 거기 ~이다 하나의 귀여운 작은 핵은 같은 것을 달성하는 데 사용할 수 있습니다. 문자열 자체를 구분 기자 문자열로 사용하고 (모든 문자를 구분 기자로 만들고) 구분 장치를 반환하도록하십시오.
StringTokenizer st = new StringTokenizer(str, str, true);
그러나 나는이 옵션들을 해고 할 목적으로만 언급합니다. 두 기술 모두 원래 문자열을 문자 프리미티브 대신 1 차 문자열로 나누고, 둘 다 객체 생성 및 문자열 조작의 형태로 많은 오버 헤드를 포함합니다. 그것을 루프로 charat ()를 호출하는 것과 비교하여 사실상 오버 헤드가 발생하지 않습니다.
위의 답변은 코드 포인트 값으로 반복하지 않는 많은 솔루션의 문제를 지적합니다. 대리 문자. Java Docs 도이 문제를 설명합니다 여기 ( "유니 코드 문자 표현"참조). 어쨌든, 여기에는 보충 유니 코드 세트에서 실제 대리 문자를 사용하고 변환하는 코드가 있습니다. 뒤 문자열로. .tochars ()는 숯불 배열을 반환합니다. 대리를 다루는 경우 반드시 두 숯이 있습니다. 이 코드는 작동해야합니다 어느 유니 코드 문자.
String supplementary = "Some Supplementary: 𠜎𠜱𠝹𠱓";
supplementary.codePoints().forEach(cp ->
System.out.print(new String(Character.toChars(cp))));
이 예제 코드가 도움이 될 것입니다!
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Solution {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 10);
map.put("b", 30);
map.put("c", 50);
map.put("d", 40);
map.put("e", 20);
System.out.println(map);
Map sortedMap = sortByValue(map);
System.out.println(sortedMap);
}
public static Map sortByValue(Map unsortedMap) {
Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
sortedMap.putAll(unsortedMap);
return sortedMap;
}
}
class ValueComparator implements Comparator {
Map map;
public ValueComparator(Map map) {
this.map = map;
}
public int compare(Object keyA, Object keyB) {
Comparable valueA = (Comparable) map.get(keyA);
Comparable valueB = (Comparable) map.get(keyB);
return valueB.compareTo(valueA);
}
}