스캐너와 StringTokenizer 및 String.Split


155

방금 Java의 스캐너 클래스에 대해 배웠으며 이제 StringTokenizer 및 String.Split과 어떻게 비교 / 경쟁하는지 궁금합니다. StringTokenizer 및 String.Split은 문자열에서만 작동하므로 스캐너를 문자열로 사용하려는 이유는 무엇입니까? 스캐너는 분할을위한 원 스톱 쇼핑이 목적입니까?

답변:


240

그들은 본질적으로 코스의 말입니다.

  • Scanner문자열을 구문 분석하고 다른 유형의 데이터를 가져와야하는 경우를 위해 설계되었습니다. 매우 유연하지만 특정 표현식으로 구분 된 문자열 배열을 얻는 가장 간단한 API를 제공하지는 않습니다.
  • String.split()그리고 Pattern.split()당신이 후자를 수행하기위한 쉬운 구문을 제공하지만 본질적으로 그들은 모두 할 것이 있습니다. 결과 문자열을 구문 분석하거나 특정 토큰에 따라 구분 기호를 반쯤 변경하려는 경우 도움이되지 않습니다.
  • StringTokenizer보다 제한 String.split()적이고 사용하기가 조금 더 복잡합니다. 기본적으로 고정 하위 문자열로 구분 된 토큰을 가져 오기 위해 설계되었습니다. 이 제한으로 인해 약 2 배 빠릅니다 String.split(). ( 비교를String.split()StringTokenizer 참조하십시오 .) 또한 정규 표현식 API보다 우선합니다 String.split().

필자 는 일반적인 머신에서 몇 밀리 초 안에 수천 개의 문자열을String.split() 토큰 화 할 수 있다는 타이밍을 알 수 있습니다 . 또한 출력을 문자열 배열로 제공하는 것 보다 장점 이 있습니다. 이는 일반적으로 원하는 것입니다. 에서 제공 한대로을 사용하는 것은 대부분 "구문 적으로 까다로워"입니다. 이 관점에서 요즘은 약간의 공간 낭비이며,을 사용할 수도 있습니다 .StringTokenizerEnumerationStringTokenizerStringTokenizerString.split()


8
String.Split 및 StringTokenizer에서 실행 한 것과 동일한 테스트에서 스캐너의 결과를 보는 것도 흥미로울 것입니다.
Dave

2
"Java API 노트에 명시된 바와 같이 StringTokenizer를 사용하지 않는 이유는 무엇입니까?"라는 또 다른 질문에 대한 답을주십시오. 이 텍스트에서 답은 "String.split ()이 충분히 빠르기"때문인 것 같습니다.
다리

1
그래서 StringTokenizer는 이제 더 이상 사용되지 않습니까?
Steve the Maker

대신에 무엇을 사용해야합니까? 스캐너?
Adrian

4
나는 그것이 오래된 질문에 대한 대답이라는 것을 알고 있지만 거대한 텍스트 스트림을 즉시 토큰으로 분할 해야하는 경우 메모리가 부족 StringTokenizer하기 때문에 여전히 최선의 방법 String.split()이 아닌가?
Sergei Tachenov

57

를 제거하여 시작하겠습니다 StringTokenizer. 나이가 들었고 정규 표현식조차 지원하지 않습니다. 설명서에는 다음과 같은 내용이 있습니다.

StringTokenizer새 코드에서는 사용을 권장하지 않지만 호환성을 위해 유지되는 레거시 클래스입니다. 이 기능을 원하는 사람은 split방법 String이나 java.util.regex패키지를 대신 사용하는 것이 좋습니다 .

이제 바로 버려 봅시다. 그 나뭇잎 split()Scanner. 그들 사이의 차이점은 무엇입니까?

우선, split()배열을 반환하면 foreach 루프를 쉽게 사용할 수 있습니다.

for (String token : input.split("\\s+") { ... }

Scanner 더 스트림처럼 만들어집니다.

while (myScanner.hasNext()) {
    String token = myScanner.next();
    ...
}

또는

while (myScanner.hasNextDouble()) {
    double token = myScanner.nextDouble();
    ...
}

(이것은 다소 큰 API 를 가지고 있으므로 항상 간단한 것으로 제한되지 않는다고 생각하십시오.)

이 스트림 스타일 인터페이스는 구문 분석을 시작하기 전에 모든 입력이 없거나 가져올 수없는 경우 간단한 텍스트 파일 또는 콘솔 입력을 구문 분석하는 데 유용 할 수 있습니다.

개인적으로, 내가 기억할 수있는 유일한 시간 Scanner은 명령 줄에서 사용자 입력을 얻어야 할 때 학교 프로젝트를 위해서입니다. 그것은 그런 종류의 작업을 쉽게 만듭니다. 그러나 내가 String나누고 싶은 것을 가지고 있다면 , 거의 갈 필요가 없습니다 split().


20
StringTokenizer는 String.split ()보다 2 배 빠릅니다. 정규식을 사용할 필요가 없으면하지 마십시오!
Alex Worden

방금 Scanner주어진 줄 바꿈 문자를 감지했습니다 String. 새 라인 문자 (봐 플랫폼에 따라 다를 수 있기 때문에 Pattern!의 자바 독을) 입력 문자열을 준수하도록 보장되지 않습니다 System.lineSeparator(), 나는 찾을 Scanner이미 새로운 라인 문자를 호출 할 때 무엇을 찾아야할지 알고로 더 적합합니다 nextLine(). 왜냐하면 String.split올바른 표준 표현식 패턴을 입력하여 줄 구분 기호를 감지해야합니다. 줄 구분 기호는 표준 위치에 저장되어 있지 않습니다 ( Scanner클래스 소스 에서 복사하는 것이 가장 좋습니다 ).
ADTC

9

StringTokenizer는 항상 존재했습니다. 가장 빠르지 만 열거 형 관용구가 다른 것만 큼 우아하지 않을 수 있습니다.

JDK 1.4에서 split이 존재하게되었습니다. 토크 나이저보다 느리지 만 String 클래스에서 호출 할 수 있으므로 사용하기가 더 쉽습니다.

스캐너는 JDK 1.5에있게되었습니다. 가장 유연하고 유명한 Cs scanf 함수 제품군과 동등한 기능을 지원하기 위해 Java API에서 오랜 간격을 메 웁니다.


6

토큰 화하려는 String 객체가있는 경우 StringTokenizer보다 String의 split 메소드를 사용하는 것이 좋습니다. 파일이나 사용자와 같이 프로그램 외부의 소스에서 텍스트 데이터를 구문 분석하는 경우 검사기가 편리합니다.


5
그렇게 칭의도없고 이유도 없습니까?
jan.supol 2018 년

6

분할 속도는 느리지 만 스캐너만큼 느리지는 않습니다. StringTokenizer가 분할보다 빠릅니다. 그러나 JFastParser https://github.com/hughperkins/jfastparser 에서 속도 부스트를 얻기 위해 유연성을 교환하여 속도를 두 배로 늘릴 수 있음을 알았습니다.

백만 배가 포함 된 문자열 테스트 :

Scanner: 10642 ms
Split: 715 ms
StringTokenizer: 544ms
JFastParser: 290ms

일부 Javadoc은 훌륭했을 것입니다. 숫자 데이터 이외의 것을 구문 분석하려면 어떻게해야합니까?
NickJ

글쎄, 그것은 아름다움이 아닌 속도를 위해 설계되었습니다. 아주 간단하고 몇 줄만 있으므로 원하는 경우 텍스트 구문 분석을위한 몇 가지 옵션을 추가 할 수 있습니다.
휴 퍼킨스

4

String.split은 StringTokenizer보다 훨씬 느린 것 같습니다. split의 유일한 장점은 토큰 배열을 얻는 것입니다. 또한 정규식을 분할하여 사용할 수 있습니다. org.apache.commons.lang.StringUtils에는 두 개의 viz보다 훨씬 빠르게 작동하는 split 메소드가 있습니다. StringTokenizer 또는 String.split. 그러나 세 가지 모두에 대한 CPU 사용률은 거의 동일합니다. 따라서 CPU를 덜 사용하는 방법이 필요하지만 여전히 찾을 수 없습니다.


3
이 대답은 약간 무의미합니다. 당신은 더 빠르지 만 "더 적은 CPU 집약적"인 것을 찾고 있다고 말합니다. 모든 프로그램은 CPU에 의해 실행됩니다. 프로그램이 CPU를 100 % 사용하지 않으면 I / O와 같은 다른 것을 대기해야합니다. 직접 디스크 액세스를 수행하지 않는 한 (특히 여기서 수행하지 않는 경우) 문자열 토큰 화를 논의 할 때 문제가되지 않습니다.
Jolta

4

나는 최근에 성능에 민감한 상황에서 String.split ()의 나쁜 성능에 대한 실험을했습니다. 이 기능이 유용 할 수 있습니다.

http://eblog.chrononsystems.com/hidden-evils-of-javas-stringsplit-and-stringr

요점은 String.split ()이 매번 정규 표현식 패턴을 컴파일하므로 미리 컴파일 된 Pattern 객체를 사용하고이를 직접 사용하여 String에서 작동하는 경우에 비해 프로그램 속도가 느려질 수 있다는 것입니다.


4
실제로 String.split ()은 항상 패턴을 컴파일하지는 않습니다. 1.7 java 인 경우 소스를 살펴보십시오. 패턴이 단일 문자이고 이스케이프 문자가 아닌지 확인하면 regexp없이 문자열을 분할하므로 매우 빠릅니다.
Krzysztof Krasoń

1

기본 시나리오의 경우 Pattern.split ()을 제안하지만 최대 성능이 필요한 경우 (특히 Android에서 테스트 한 모든 솔루션이 매우 느림) 단일 문자로만 분할하면 이제 내 자신의 방법을 사용합니다.

public static ArrayList<String> splitBySingleChar(final char[] s,
        final char splitChar) {
    final ArrayList<String> result = new ArrayList<String>();
    final int length = s.length;
    int offset = 0;
    int count = 0;
    for (int i = 0; i < length; i++) {
        if (s[i] == splitChar) {
            if (count > 0) {
                result.add(new String(s, offset, count));
            }
            offset = i + 1;
            count = 0;
        } else {
            count++;
        }
    }
    if (count > 0) {
        result.add(new String(s, offset, count));
    }
    return result;
}

"abc".toCharArray ()를 사용하여 문자열의 문자 배열을 가져옵니다. 예를 들면 다음과 같습니다.

String s = "     a bb   ccc  dddd eeeee  ffffff    ggggggg ";
ArrayList<String> result = splitBySingleChar(s.toCharArray(), ' ');

1

한 가지 중요한 차이점은 String.split ()과 Scanner가 모두 빈 문자열을 생성 할 수 있지만 StringTokenizer는이를 수행하지 않는다는 것입니다.

예를 들면 다음과 같습니다.

String str = "ab cd  ef";

StringTokenizer st = new StringTokenizer(str, " ");
for (int i = 0; st.hasMoreTokens(); i++) System.out.println("#" + i + ": " + st.nextToken());

String[] split = str.split(" ");
for (int i = 0; i < split.length; i++) System.out.println("#" + i + ": " + split[i]);

Scanner sc = new Scanner(str).useDelimiter(" ");
for (int i = 0; sc.hasNext(); i++) System.out.println("#" + i + ": " + sc.next());

산출:

//StringTokenizer
#0: ab
#1: cd
#2: ef
//String.split()
#0: ab
#1: cd
#2: 
#3: ef
//Scanner
#0: ab
#1: cd
#2: 
#3: ef

String.split () 및 Scanner.useDelimiter ()의 구분 기호는 단순한 문자열이 아니라 정규식이기 때문입니다. 위의 예에서 구분 기호 ""를 "+"로 바꾸면 StringTokenizer처럼 동작 할 수 있습니다.


-5

String.split ()은 매우 잘 작동하지만 단일 또는 이중 파이프 (|) 기호를 기반으로 아래에 표시된 것처럼 문자열을 분할하려는 경우 작동하지 않는 것처럼 자체 경계가 있습니다. 이 상황에서 StringTokenizer를 사용할 수 있습니다.

ABC | IJK


12
실제로 "ABC | IJK".split ( "\\ |");
Tomo

"ABC || DEF ||".. split ( "\\ |")는 뒤에 오는 두 개의 빈 값을 무시하므로 구문 분석이 이전보다 복잡해지기 때문에 실제로 작동하지 않습니다.
Armand
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.