2015-06-19 4 views
31

मैं हाल ही में एक स्ट्रिंग को विभाजित करने की एक लुक-आगे नियमित अभिव्यक्ति की शक्ति का इस्तेमालकैसे Guava Splitter.onPattern (..)। Split() String.split (..) से अलग है?</p> <pre><code>"abc8".split("(?=\d)|\W") </code></pre> <p>तो कंसोल इस अभिव्यक्ति देता है को मुद्रित:

[abc, 8] 

इस परिणाम के साथ बहुत खुश, मैं इसे आगे विकास के लिए गुवा में स्थानांतरित करना चाहता था, जो इस तरह दिखता था:

Splitter.onPattern("(?=\\d)|\\W").split("abc8") 

मेरे आश्चर्य के लिए आउटपुट में बदल गया:

[abc] 

क्यों?

+0

मेरे लिए यह अपने शून्य लंबाई सीमांकक के साथ संयोजन में एक वर्ण भागों के लिए एक बंद-एक करके बग की तरह दिखता है। मेरे लिए यह स्ट्रिंग की शुरुआत में काम नहीं करता है, लेकिन बीच में ठीक काम करता है। –

+0

प्रासंगिक, लेकिन कोई जवाब नहीं: https://github.com/google/guava/issues/1378। इससे मदद मिलेगी, आप बस जो भी चाहें उस पर मेल खा सकते हैं और विभाजक बनाए रख सकते हैं ... –

उत्तर

15

आपको एक बग मिला!

@Override 
protected String computeNext() { 
    /* 
    * The returned string will be from the end of the last match to the 
    * beginning of the next one. nextStart is the start position of the 
    * returned substring, while offset is the place to start looking for a 
    * separator. 
    */ 
    int nextStart = offset; 
    while (offset != -1) { 
    int start = nextStart; 
    int end; 

    int separatorPosition = separatorStart(offset); 

    if (separatorPosition == -1) { 
     end = toSplit.length(); 
     offset = -1; 
    } else { 
     end = separatorPosition; 
     offset = separatorEnd(separatorPosition); 
    } 

    if (offset == nextStart) { 
     /* 
     * This occurs when some pattern has an empty match, even if it 
     * doesn't match the empty string -- for example, if it requires 
     * lookahead or the like. The offset must be increased to look for 
     * separators beyond this point, without changing the start position 
     * of the next returned substring -- so nextStart stays the same. 
     */ 
     offset++; 
     if (offset >= toSplit.length()) { 
     offset = -1; 
     } 
     continue; 
    } 

    while (start < end && trimmer.matches(toSplit.charAt(start))) { 
     start++; 
    } 
    while (end > start && trimmer.matches(toSplit.charAt(end - 1))) { 
     end--; 
    } 

    if (omitEmptyStrings && start == end) { 
     // Don't include the (unused) separator in next split string. 
     nextStart = offset; 
     continue; 
    } 

    if (limit == 1) { 
     // The limit has been reached, return the rest of the string as the 
     // final item. This is tested after empty string removal so that 
     // empty strings do not count towards the limit. 
     end = toSplit.length(); 
     offset = -1; 
     // Since we may have changed the end, we need to trim it again. 
     while (end > start && trimmer.matches(toSplit.charAt(end - 1))) { 
     end--; 
     } 
    } else { 
     limit--; 
    } 

    return toSplit.subSequence(start, end).toString(); 
    } 
    return endOfData(); 
} 

रुचि के क्षेत्र है:

if (offset == nextStart) { 
    /* 
    * This occurs when some pattern has an empty match, even if it 
    * doesn't match the empty string -- for example, if it requires 
    * lookahead or the like. The offset must be increased to look for 
    * separators beyond this point, without changing the start position 
    * of the next returned substring -- so nextStart stays the same. 
    */ 
    offset++; 
    if (offset >= toSplit.length()) { 
    offset = -1; 
    } 
    continue; 
} 

यह तर्क अच्छा काम करता है, जब तक कि

System.out.println(s.split("abc82")); // [abc, 8] 
System.out.println(s.split("abc8")); // [abc] 

इस विधि Splitter का उपयोग करता है वास्तव में String रों (Splitter.SplittingIterator::computeNext) विभाजित करने के लिए है String के अंत में खाली मिलान होता है। यदि खाली मिलान String के अंत में होता है, तो वह उस चरित्र को छोड़ने को समाप्त कर देगा। क्या इस हिस्से की तरह दिखना चाहिए (नोटिस >= ->>) है:

if (offset == nextStart) { 
    /* 
    * This occurs when some pattern has an empty match, even if it 
    * doesn't match the empty string -- for example, if it requires 
    * lookahead or the like. The offset must be increased to look for 
    * separators beyond this point, without changing the start position 
    * of the next returned substring -- so nextStart stays the same. 
    */ 
    offset++; 
    if (offset > toSplit.length()) { 
    offset = -1; 
    } 
    continue; 
} 
+0

सोचा था कि इसे एक ऐसा पैटर्न रखने की अनुमति नहीं दी जानी चाहिए जो लुकहेड या लुकबींड का उपयोग करके खाली स्ट्रिंग से मेल खाती हो, लेकिन ऐसा लगता है कि आपको बग के लिए सही स्थान मिला है। – Bubletan

+0

@ बुबलेटन (? = \ D) खाली स्ट्रिंग से मेल नहीं खाएगा। यह एक खाली स्ट्रिंग से मेल खाता है जिसके बाद एक संख्या होती है, जो एक ही चीज़ नहीं है। – Jeffrey

+1

हां, मैंने यही कहा; _an_ खाली स्ट्रिंग। – Bubletan

5

अमरूद Splitter एक बग लगता है जब एक पैटर्न एक खाली स्ट्रिंग से मेल खाता है। यदि आप एक Matcher बनाने और प्रिंट यह क्या से मेल खाता है की कोशिश करते हैं:

Pattern pattern = Pattern.compile("(?=\\d)|\\W"); 
Matcher matcher = pattern.matcher("abc8"); 
while (matcher.find()) { 
    System.out.println(matcher.start() + "," + matcher.end()); 
} 

आप उत्पादन 3,3 जो है जैसे कि यह 8 से मेल खाएंगे यह देखने में आता है मिलता है। इसलिए यह केवल abc के परिणामस्वरूप विभाजित होता है।

आप उदाहरण का उपयोग कर सकते हैं Pattern#split(String) जो सही आउटपुट देने लगता है:

Pattern.compile("(?=\\d)|\\W").split("abc8") 
+0

'" abc8 ".split (" (? = \\ d) | \\ डब्ल्यू ")' ' Pattern.compile ("(= \\ घ) |? \\ डब्ल्यू")। विभाजन ("abc8") '। – SqueezyMo

+0

@ जेफरी हां, और यही कारण है कि चेक विफल रहता है। यह 'स्प्लिटर' में एक बग की तरह लगता है। – Bubletan

+0

@ स्क्वीजीमो 'स्ट्रिंग # स्प्लिट' में कुछ और कोड है लेकिन काफी हां। – Bubletan

संबंधित मुद्दे