2012-07-03 13 views
5

से मेल खाने वाले सभी ओवरलैपिंग सबस्ट्रिंग्स क्या कोई एपीआई विधि है जो नियमित अभिव्यक्ति से मेल खाने वाले सभी (संभावित रूप से ओवरलैपिंग) सबस्ट्रिंग्स लौटाती है?जावा रेगेक्स

उदाहरण के लिए, मेरे पास एक टेक्स्ट स्ट्रिंग है: String t = 04/31 412-555-1235;, और मेरे पास एक पैटर्न है: Pattern p = new Pattern("\\d\\d+"); जो दो या दो से अधिक वर्णों के तारों से मेल खाता है।

मैचों मैं कर रहे हैं: 04, 31, 412, 555, 1235

मैं कैसे अतिव्यापी मैचों मिलता है?

मैं कोड लौटना चाहते: 04, 31, 41, 412, 12, 55, 555, 55, 12, 123, 1235, 23, 235, 35.

सैद्धांतिक रूप से यह संभव हो जाना चाहिए - एक स्पष्ट O(n^2) एल्गोरिदम है जो पैटर्न के खिलाफ सभी सबस्ट्रिंग को दर्शाता है और जांचता है।

संपादित

बल्कि सभी सबस्ट्रिंग की गणना की तुलना में, यह Matcher में region(int start, int end) विधि का उपयोग करने सुरक्षित है। एक अलग, निकाले गए सबस्ट्रिंग के खिलाफ पैटर्न की जांच करना मैच के परिणाम को बदल सकता है (उदाहरण के लिए यदि पैटर्न के प्रारंभ/अंत में गैर-कैप्चरिंग समूह या शब्द सीमा जांच है)।

संपादित 2

वास्तव में, यह है कि क्या region() आप शून्य चौड़ाई मैचों के लिए क्या उम्मीद करता है स्पष्ट नहीं है। विनिर्देश अस्पष्ट है, और प्रयोग निराशाजनक परिणाम पैदा करते हैं।

उदाहरण के लिए:

String line = "xx90xx"; 
String pat = "\\b90\\b"; 
System.out.println(Pattern.compile(pat).matcher(line).find()); // prints false 
for (int i = 0; i < line.length(); ++i) { 
    for (int j = i + 1; j <= line.length(); ++j) { 
    Matcher m = Pattern.compile(pat).matcher(line).region(i, j); 
    if (m.find() && m.group().size == (j - i)) { 
     System.out.println(m.group() + " (" + i + ", " + j + ")"); // prints 90 (2, 4) 
    } 
    } 
} 

मुझे यकीन है कि जो सबसे सुरुचिपूर्ण समाधान है नहीं कर रहा हूँ। pat मैचों की जांच करने से पहले एक दृष्टिकोण line और पैड को उचित सीमा वर्णों के साथ एक सबस्ट्रिंग लेना होगा।

संपादित 3

यहाँ पूर्ण समाधान है कि मैं के साथ आया है। यह मूल नियमित अभिव्यक्ति में शून्य-चौड़ाई पैटर्न, सीमाएं इत्यादि को संभाल सकता है। यह टेक्स्ट स्ट्रिंग के सभी सबस्ट्रिंग्स को देखता है और यह जांचता है कि नियमित अभिव्यक्ति केवल शुरुआत और अंत में उचित संख्या में वाइल्डकार्ड के साथ पैटर्न को पैड करके विशिष्ट स्थिति पर मेल खाती है या नहीं। ऐसा लगता है कि मैंने कोशिश किए मामलों के लिए काम किया - हालांकि मैंने व्यापक परीक्षण नहीं किया है। यह निश्चित रूप से यह संभवतः कम कुशल है।

public static void allMatches(String text, String regex) 
    { 
    for (int i = 0; i < text.length(); ++i) { 
     for (int j = i + 1; j <= text.length(); ++j) { 
     String positionSpecificPattern = "((?<=^.{"+i+"})("+regex+")(?=.{"+(text.length() - j)+"}$))"; 
     Matcher m = Pattern.compile(positionSpecificPattern).matcher(text); 

     if (m.find()) 
     { 
      System.out.println("Match found: \"" + (m.group()) + "\" at position [" + i + ", " + j + ")"); 
     } 
     } 
    } 
    } 

संपादित 4

यहाँ ऐसा करने का एक बेहतर तरीका है: https://stackoverflow.com/a/11372670/244526

संपादित 5

JRegex पुस्तकालय एक जावा regex मिलान सभी ओवरलैपिंग सबस्ट्रिंग खोजने (हालांकि समर्थन करता है ऐसा लगता है कि थोड़ी देर में अपडेट नहीं किया गया है)।विशेष रूप से, documentation on non-breaking search निर्दिष्ट करता है:

आप एक पैटर्न के सभी संभव occureneces खोजने सकते हैं उन है कि अन्तर्विभाजक या नेस्टेड रहते हैं सहित, नॉन-ब्रेकिंग खोज का उपयोग करना। यह है Matcher की विधि का उपयोग करके प्राप्त आगे बढ़ना (खोज() के बजाय)

+0

सभी 3 या अधिक वर्णों के परिणामस्वरूप पोस्ट-रेगेक्स लूपिंग करें –

+0

http://regexlib.com/ कुछ खुदाई करने के लिए एक अच्छी जगह हो सकती है। –

+0

@ Ωmega मेरी पूरी कोशिश कर रहा है, लेकिन फीडबैक के लिए खुला है जो उपयोगी नहीं है। चीयर्स। –

उत्तर

0

निकटतम आप प्राप्त कर सकते हैं कुछ इस तरह है।

"(?=((\\d*)\\d))(?=(\\d)\\d*)" 

परिणाम समूह 1, 2 और 3 पर कब्जा करने में किया जाएगा

जहाँ तक मेरी कल्पना जा सकते हैं, मैं केवल एक व्यवहार्य तरीका पुनर्ग्रहण की के रूप में शून्य लंबाई दावे में कब्जा करने के बारे में सोच सकते हैं एक स्ट्रिंग की एक ही स्थिति। शून्य-लंबाई के दावे के बाहर पाठ को कैप्चर करना एक बार और सभी के लिए पाठ का उपभोग करेगा (पीछे-पीछे जावा में निश्चित लंबाई को कैप्चर कर सकता है, इसलिए इसे पहुंच योग्य माना जा सकता है)।

यह समाधान सही नहीं है: पुनरावृत्ति (एक ही स्थिति में पाठ के!) और खाली स्ट्रिंग मैचों से अलग, यह सभी संभावित सबस्ट्रिंग को कैप्चर नहीं करेगा।

"(?=(\\d{" + n + "}))" 

और n के मूल्य बढ़ाने तक वहां कोई मुकाबला नहीं है के लिए इस के खिलाफ स्ट्रिंग से मेल:

एक तरह से हर संभव सबस्ट्रिंग कब्जा करने के लिए 1 से शुरू n के मूल्य के साथ निम्नलिखित regex का निर्माण है।

यह विधि निश्चित रूप से "\ d +" के साथ सभी संख्याओं को मिलान करने की विधि की तुलना में अक्षम है और सभी सबस्ट्रिंग निकालने के लिए अक्षम है।

0

यह हे (एन) के रूप में संभव हैकेवल यदि आप की अनुमति दी संख्या लंबाई श्रेणी निर्दिष्ट। (?=(\\d{2}))(?=(\\1\\d)?)(?=(\\2\\d)?)

यह सकारात्मक अग्रदर्शी के माध्यम से एक शून्य लंबाई दावा है, समूहों में इस तरह के अग्रदर्शी पर कब्जा:

मान लीजिए कि 2-4 अंक (संख्या 00-9999) से करते हैं। परिणाम सभी 2-4 अंकों के तारों की एक सरणी है जो रेगेक्स इनपुट के भीतर मिल सकती है, साथ ही साथ डुप्लीकेट और खाली तार (गैर-मिलान कैप्चर के लिए)।

मैं जावा डेवलपर नहीं हूं, लेकिन मेरा मानना ​​है कि एक पर्ल स्क्रिप्ट को एक उदाहरण के रूप में भी पढ़ा जा सकता है।

#!/usr/bin/perl          # perl script 
use List::MoreUtils qw/ uniq /;      # uniq subroutine library 
$_ = '04/31 412-555-1235';       # input 
my @n = uniq (/(?=(\d{2}))(?=(\1\d)?)(?=(\2\d)?)/g); # regex (single slash in Perl) 
print "$_\n" for grep(/\S/, @n);      # print non-empty lines 

चाल बैक्रेरेंस का उपयोग कर रही है। यदि आप 2-5 अंकों की स्ट्रिंग को कैप्चर करना चाहते हैं, तो आपको रेगेक्स में एक और सकारात्मक लुकहेड का उपयोग करना होगा: (?=(\\d{2}))(?=(\\1\\d)?)(?=(\\2\\d)?)(?=(\\3\\d)?)

मुझे विश्वास है कि यह एक निकटतम दृष्टिकोण है जिसे आप कर सकते हैं। यदि यह आपके लिए काम करता है, तो एक टिप्पणी छोड़ें और उम्मीद है कि कुछ जावा डेवलपर उपरोक्त स्क्रिप्ट के लिए जावा कोड के साथ अपना जवाब संपादित करेंगे।

+0

रेगेक्स है जावा में वही (सिवाय इसके कि बैकस्लैश से बचने की जरूरत है)। 'Uniq' के लिए, इसे जावा में' सेट' '('ट्रीसेट' या 'हैशसेट') के साथ अनुकरण किया जा सकता है। – nhahtdh

+0

@nhahtdh - धन्यवाद। पोस्ट को संपादित करके मेरे उत्तर में अपडेट जोड़ने के लिए स्वतंत्र महसूस करें। –

1

मुझे एक समान स्थिति का सामना करना पड़ा और मैंने उपर्युक्त उत्तरों की कोशिश की लेकिन मेरे मामले में मैचर की शुरुआत और अंत सूचकांक सेट करके बहुत अधिक समय लगा लेकिन मुझे लगता है कि मुझे एक बेहतर समाधान मिला है, मैं हूं इसे दूसरों के लिए यहां पोस्ट करना। तो मेरा कोड स्निपलेट नीचे है।

if (textToParse != null) { 
Matcher matcher = PLACEHOLDER_PATTERN.matcher(textToParse); 
    while(matcher.hitEnd()!=true){ 
     Boolean result = matcher.find(); 
     int count = matcher.groupCount(); 
     System.out.println("Result " +result+" count "+count); 
     if(result==true && count==1){ 
      mergeFieldName = matcher.group(1); 
      mergeFieldNames.add(mergeFieldName); 
      } 
     } 
    } 

मैंने matcher.hitEnd() विधि का उपयोग यह जांचने के लिए किया है कि मैं पाठ के अंत तक पहुंच गया हूं या नहीं।

उम्मीद है कि इससे मदद मिलती है। धन्यवाद!

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