2012-06-12 11 views
29

यहाँ अपने आवेदन में वर्तमान कोड है।जावा विभाजन स्ट्रिंग प्रदर्शन

मैंने यह भी सीखा कि split वास्तव में एक नियमित अभिव्यक्ति लेता है, जो मेरे लिए यहां बेकार है।

तो मेरा सवाल है, स्ट्रिंग विभाजन को अनुकूलित करने के लिए मैं किस विकल्प का उपयोग कर सकता हूं? मैंने StringUtils.split देखा है लेकिन क्या यह तेज़ है?

(मैंने कोशिश की होगी है और परीक्षण किया अपने आप को लेकिन अपने आवेदन की रूपरेखा बहुत समय लगता है, इसलिए अगर किसी को पहले से ही जवाब जानता है कुछ समय बचाया है कि)

उत्तर

32

String.split(String) यदि आपका पैटर्न केवल एक वर्ण लंबा है तो regexp नहीं बनाएगा। एकल चरित्र द्वारा विभाजित होने पर, यह विशेष कोड का उपयोग करेगा जो कि बहुत ही कुशल है। इस विशेष मामले में StringTokenizer बहुत तेज नहीं है।

यह ओपनजेडीके 7/ओरेकलजेडीके 7 में पेश किया गया था। Here's a bug report और a commit।मैंने simple benchmark here बनाया है।


$ java -version 
java version "1.8.0_20" 
Java(TM) SE Runtime Environment (build 1.8.0_20-b26) 
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode) 

$ java Split 
split_banthar: 1231 
split_tskuzzy: 1464 
split_tskuzzy2: 1742 
string.split: 1291 
StringTokenizer: 1517 
+1

इस बेंचमार्क के लिए धन्यवाद। आपका कोड "अनुचित" है हालांकि स्ट्रिंगटोकनाइज़र भाग एक सूची बनाने से बचाता है और इसे एक सरणी में परिवर्तित करता है .... हालांकि महान प्रारंभिक बिंदु! –

7

StringTokenizer (इस तरह सरल पार्स मैं के लिए बहुत तेजी से है कुछ समय पहले कुछ बेंचमार्किंग किया था और आपको भारी गति मिलती है)।

StringTokenizer st = new StringTokenizer("1/2/3","/"); 
String[] arr = st.countTokens(); 
arr[0] = st.nextToken(); 

आप एक छोटे से अधिक प्रदर्शन बाहर eek चाहते हैं, आप इसे मैन्युअल रूप में अच्छी तरह कर सकते हैं:

String s = "1/2/3" 
char[] c = s.toCharArray(); 
LinkedList<String> ll = new LinkedList<String>(); 
int index = 0; 

for(int i=0;i<c.length;i++) { 
    if(c[i] == '/') { 
     ll.add(s.substring(index,i)); 
     index = i+1; 
    } 
} 

String[] arr = ll.size(); 
Iterator<String> iter = ll.iterator(); 
index = 0; 

for(index = 0; iter.hasNext(); index++) 
    arr[index++] = iter.next(); 
+4

StringTokenizer एक विरासत वर्ग है (लेकिन रिटर्न Iterable/इटरेटर और उन्हें स्ट्रिंग सरणी में कनवर्ट करने 54ms की कुल लेता है) संगतता कारणों के लिए बनाए रखा गया है हालांकि इसका उपयोग नए कोड में निराश है। यह अनुशंसा की जाती है कि इस कार्यक्षमता की तलाश करने वाले किसी भी व्यक्ति को स्ट्रिंग या java.util.regex पैकेज की विभाजन विधि का उपयोग करें। –

+3

सिर्फ इसलिए कि विरासत का यह मतलब नहीं है कि यह उपयोगी नहीं है।और वास्तव में, यह विशेष वर्ग वास्तव में उस अतिरिक्त प्रदर्शन को बढ़ावा देने के लिए बहुत उपयोगी है, इसलिए मैं वास्तव में इस "विरासत" लेबल के खिलाफ हूं। – tskuzzy

+3

'स्ट्रिंग' और' java.util.regex' पैकेज की विभाजित विधि regexes का उपयोग करने के महत्वपूर्ण ओवरहेड लेती है। 'स्ट्रिंगटोकनाइज़र 'नहीं है। –

3

java.util.StringTokenizer(String str, String delim)this post के अनुसार के बारे में दो बार के रूप में तेजी से है।

हालांकि, जब तक आपका आवेदन एक विशाल पैमाने पर नहीं है, split आपके लिए ठीक होना चाहिए (सी.एफ. एक ही पोस्ट, यह कुछ मिलीसेकंड में हजारों तारों को उद्धृत करता है)।

+0

यह एक विशाल पैमाने पर आवेदन नहीं लेता है, एक तंग पाश में एक विभाजन जैसे कि दस्तावेज़ पार्सर पर्याप्त है - और लगातार- twitterlinks, ईमेल, हैशटैग पार्सिंग की सामान्य दिनचर्या के बारे में सोचें .... उन्हें एमबी के साथ खिलाया जाता है पार्स करने के लिए पाठ। नियमित रूप से कुछ दर्जन लाइनें हो सकती हैं लेकिन उन्हें प्रति सेकेंड सैकड़ों बार बुलाया जाएगा। – rupps

15

यदि आप तृतीय-पक्ष पुस्तकालयों का उपयोग कर सकते हैं, Guava'sSplitter नियमित अभिव्यक्तियों के ऊपरी हिस्से को नहीं लेते हैं, जब आप इसके लिए नहीं पूछते हैं, और सामान्य नियम के रूप में बहुत तेज़ होते हैं। (प्रकटीकरण: मैं अमरूद के लिए योगदान करते हैं।)

Iterable<String> split = Splitter.on('/').split(string); 

(इसके अलावा, Splitter एक नियम much more predictableString.split की तुलना में है।)

+1

यह एक बड़ी फ़ाइल से लाइनों पर इसका उपयोग करते समय मेरे लिए एक बहुत ही महत्वपूर्ण अंतर बना दिया। –

+2

यह पोस्ट इटरटेबल के गैर-उपयोग की सिफारिश करता है, यहां तक ​​कि गुवा की टीम लीड कहती है ... http: //alexruiz.developerblogs.com/? P = 2519 – sirvon

1

अमरूद एक Splitter जो अधिक लचीला है कि String.split() विधि है, और नहीं है (जरूरी) एक regex का उपयोग करें। OTOH, String.split() को रेगेक्स मशीनरी से बचने के लिए जावा 7 में अनुकूलित किया गया है यदि विभाजक एक एकल है। तो प्रदर्शन जावा 7 में समान होना चाहिए।

+0

ओह ठीक है मैं जावा 5 का उपयोग कर रहा हूं (दुर्भाग्य से हाँ, बदल नहीं सकता कि) –

0

स्ट्रिंग की विभाजन विधि शायद एक सुरक्षित विकल्प है। As of at least java 6 (हालांकि एपीआई संदर्भ 7 के लिए है) वे मूल रूप से कहते हैं कि स्ट्रिंगटोकनाइज़र का उपयोग निराश है। उनके शब्दों को नीचे उद्धृत किया गया है।

"स्ट्रिंगटोकनाइज़र एक विरासत वर्ग है जो संगतता कारणों के लिए बनाए रखा गया है हालांकि इसका उपयोग नए कोड में निराश है। यह अनुशंसा की जाती है कि इस कार्यक्षमता की तलाश करने वाले किसी भी व्यक्ति को स्ट्रिंग या java.util.regex पैकेज की विभाजन विधि का उपयोग करें। "

2

StringTokenizer किसी अन्य बंटवारे विधि की तुलना में तेजी है, लेकिन tokenized स्ट्रिंग के साथ सीमांकक वापस जाने के लिए tokenizer हो रही 50% की तरह कुछ से प्रदर्शन में सुधार। यह निर्माता java.util.StringTokenizer.StringTokenizer(String str, String delim, boolean returnDelims) का उपयोग कर हासिल किया जाता है। यहां उस मामले पर कुछ अन्य अंतर्दृष्टि: Performance of StringTokenizer class vs. split method in Java

0

आप स्प्लिट फ़ंक्शन स्वयं लिख सकते हैं, जो सबसे तेज़ होने वाला है। यहाँ, लिंक है कि यह साबित होता है कि यह मेरे लिए बहुत काम किया, 6X के आधार पर अपने कोड अनुकूलित

StringTokenizer - reading lines with integers

अलग करना: 366ms indexOf: 50ms StringTokenizer: 89ms GuavaSplit: 109ms IndexOf2 (कुछ सुपर अनुकूलित ऊपर प्रश्न में दिए गए) समाधान: 14ms CsvMapperSplit (पंक्ति द्वारा मानचित्रण पंक्ति): 326ms CsvMapperSplit_DOC (एक दस्तावेज़ निर्माण और एक ही बार में सभी पंक्तियों) मानचित्रण: 177ms

2

देखकर के रूप में मैं बड़े पैमाने पर काम कर रहा हूँ, मैं टी सोचा कि यह कुछ और बेंचमार्किंग प्रदान करने में मदद करेगा, जिसमें मेरे कुछ कार्यान्वयन शामिल हैं (मैं रिक्त स्थान पर विभाजित हूं, लेकिन यह स्पष्ट करना चाहिए कि यह सामान्य रूप से कितना समय लेता है):

मैं 426 एमबी फ़ाइल के साथ काम कर रहा हूं 2622761 लाइनें। एकमात्र व्हाइटस्पेस सामान्य रिक्त स्थान ("") और रेखाएं ("\ n") हैं।

सबसे पहले मैं रिक्त स्थान के साथ सभी लाइनों को बदलने, और बेंचमार्क एक विशाल लाइन को पार्स:

.split(" ") 
Cumulative time: 31.431366952 seconds 

.split("\s") 
Cumulative time: 52.948729489 seconds 

splitStringChArray() 
Cumulative time: 38.721338004 seconds 

splitStringChList() 
Cumulative time: 12.716065893 seconds 

splitStringCodes() 
Cumulative time: 1 minutes, 21.349029036000005 seconds 

splitStringCharCodes() 
Cumulative time: 23.459840685 seconds 

StringTokenizer 
Cumulative time: 1 minutes, 11.501686094999997 seconds 

तो मैं लाइन (जिसका अर्थ है कि कार्य करता है और छोरों ही बार में सभी के बजाय कई बार किया जाता है, के आधार पर मानदंड बंटवारे लाइन):

// Use a char array, and count the number of instances first. 
public static String[] splitStringChArray(String str, StringBuilder sb) { 
    char[] strArray = str.toCharArray(); 
    int count = 0; 
    for (char c : strArray) { 
     if (c == ' ') { 
      count++; 
     } 
    } 
    String[] splitArray = new String[count+1]; 
    int i=0; 
    for (char c : strArray) { 
     if (c == ' ') { 
      splitArray[i] = sb.toString(); 
      sb.delete(0, sb.length()); 
     } else { 
      sb.append(c); 
     } 
    } 
    return splitArray; 
} 

// Use a char array but create an ArrayList, and don't count beforehand. 
public static ArrayList<String> splitStringChList(String str, StringBuilder sb) { 
    ArrayList<String> words = new ArrayList<String>(); 
    words.ensureCapacity(str.length()/5); 
    char[] strArray = str.toCharArray(); 
    int i=0; 
    for (char c : strArray) { 
     if (c == ' ') { 
      words.add(sb.toString()); 
      sb.delete(0, sb.length()); 
     } else { 
      sb.append(c); 
     } 
    } 
    return words; 
} 

// Using an iterator through code points and returning an ArrayList. 
public static ArrayList<String> splitStringCodes(String str) { 
    ArrayList<String> words = new ArrayList<String>(); 
    words.ensureCapacity(str.length()/5); 
    IntStream is = str.codePoints(); 
    OfInt it = is.iterator(); 
    int cp; 
    StringBuilder sb = new StringBuilder(); 
    while (it.hasNext()) { 
     cp = it.next(); 
     if (cp == 32) { 
      words.add(sb.toString()); 
      sb.delete(0, sb.length()); 
     } else { 
      sb.append(cp); 
     } 
    } 

    return words; 
} 

// This one is for compatibility with supplementary or surrogate characters (by using Character.codePointAt()) 
public static ArrayList<String> splitStringCharCodes(String str, StringBuilder sb) { 
    char[] strArray = str.toCharArray(); 
    ArrayList<String> words = new ArrayList<String>(); 
    words.ensureCapacity(str.length()/5); 
    int cp; 
    int len = strArray.length; 
    for (int i=0; i<len; i++) { 
     cp = Character.codePointAt(strArray, i); 
     if (cp == ' ') { 
      words.add(sb.toString()); 
      sb.delete(0, sb.length()); 
     } else { 
      sb.append(cp); 
     } 
    } 

    return words; 
} 

इस तरह है:

.split(" ") 
Cumulative time: 3.809014174 seconds 

.split("\s") 
Cumulative time: 7.906730124 seconds 

splitStringChArray() 
Cumulative time: 4.06576739 seconds 

splitStringChList() 
Cumulative time: 2.857809996 seconds 

Bonus: splitStringChList(), but creating a new StringBuilder every time (the average difference is actually more like .42 seconds): 
Cumulative time: 3.82026621 seconds 

splitStringCodes() 
Cumulative time: 11.730249921 seconds 

splitStringCharCodes() 
Cumulative time: 6.995555826 seconds 

StringTokenizer 
Cumulative time: 4.500008172 seconds 

यहाँ कोड है

StringTokenizer tokenizer = new StringTokenizer(file.getCurrentString()); 
    words = new String[tokenizer.countTokens()]; 
    int i = 0; 
    while (tokenizer.hasMoreTokens()) { 
     words[i] = tokenizer.nextToken(); 
     i++; 
    } 
0

उपयोग अपाचे कॉमन्स लैंग »3.0 के

StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 

आप गैर regex विभाजन की जरूरत है और स्ट्रिंग सरणी में परिणाम चाहता है, तो StringUtils उपयोग करते हैं, मैं StringUtils.splitByWholeSeparator के साथ तुलना में: मैं StringTokenizer इस्तेमाल किया गुवा का स्प्लिटर और जावा का स्ट्रिंग स्प्लिट, और पाया गया स्ट्रिंगयूटिल तेज है।

  1. StringUtils - 8ms
  2. स्ट्रिंग - 11ms
  3. स्प्लिटर - 1ms
संबंधित मुद्दे