2010-01-04 18 views
8

मैं JMD (Java MarkDown) (MarkDownSharp का जावा पोर्ट) पर काम कर रहा हूं लेकिन मुझे विशेष रूप से एक रेगेक्स के साथ कोई समस्या है। फ़ाइल के लिए Markdown_Documentation_Syntax.text इस नियमित अभिव्यक्ति मर जाता है:जावा रेगेक्स स्टैक ओवरफ़्लो पर मर जाता है: बेहतर संस्करण

private static final String BLOCK_TAGS_1 = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"; 
private static final String BLOCKS_NESTED_PATTERN = String.format("" + 
     "(" +      // save in $1 
     "^" +      // start of line (with MULTILINE) 
     "<(%s)" +     // start tag = $2 
     "\\b" +     // word break 
     "(.*\\n)*?" +    // any number of lines, minimally matching 
     "</\\2>" +     // the matching end tag 
     "[ \\t]*" +    // trailing spaces/tags 
     "(?=\\n+|\\Z)" +   // followed by a newline or end of 
     ")", BLOCK_TAGS_1); 

जो करने के लिए अनुवाद:

(^<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b(.*\n)*?</\2>[ \t]*(?=\n+|\Z)) 

यह पैटर्न को स्वीकार कर लिया ब्लॉक टैग है कि एक लाइन के शुरू होने से सहारा लेने लगते हैं की तलाश में है, के किसी भी संख्या के द्वारा पीछा किया रेखाएं और उसके बाद मिलान करने वाले टैग द्वारा एक नई लाइन या स्ट्रिंग टर्मिनेटर के बाद समाप्त कर दिया जाता है। यह उत्पन्न करता है:

java.lang.StackOverflowError 
    at java.util.regex.Pattern$Curly.match(Pattern.java:3744) 
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168) 
    at java.util.regex.Pattern$LazyLoop.match(Pattern.java:4357) 
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4227) 
    at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3366) 
    at java.util.regex.Pattern$Curly.match0(Pattern.java:3782) 
    at java.util.regex.Pattern$Curly.match(Pattern.java:3744) 
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168) 
    at java.util.regex.Pattern$LazyLoop.match(Pattern.java:4357) 
     ... 

यह (ओएसएस/एस एस IIRC के लिए चूक 128k/400K करने के लिए) के लिए जावा ढेर अंतरिक्ष में वृद्धि से निपटा जा सकता है लेकिन इसके बाद के संस्करण अभिव्यक्ति वैसे भी धीमी है।

तो मैं एक regex गुरु जो बेहतर कर सकते हैं के लिए देख रहा हूँ (या कम से कम इस पैटर्न के साथ प्रदर्शन समस्या की व्याख्या)। सी # संस्करण थोड़ा धीमा है लेकिन ठीक काम करता है। ऐसा लगता है कि PHP के साथ कोई समस्या नहीं है।

संपादित करें: यह विंडोज 7 64 अल्टीमेट पर चल रहे जेडीके 6u17 पर है।

+0

जो जेडीके संस्करण? – bmargulies

+5

यह नियमित अभिव्यक्तियों का एक भयानक उपयोग है। क्या आपको रेगेक्स का उपयोग करना है या क्या आप इसे वास्तविक रिकर्सिव पार्सर (या तो एलआर या रिकर्सिव वंश) के रूप में पुन: उपयोग कर सकते हैं? –

+0

क्या आपने '। * \ N' से'। *? \ N' के साथ प्रयास किया है? – YOU

उत्तर

16

इस भाग:

(.*\n)*? 

नेस्टेड * की वजह से और के बाद से वहाँ अधिक अक्षर हो कि बाद में मैच के लिए कर रहे हैं अनावश्यक बैक ट्रैकिंग की बहुत शामिल होगी।

मैं केवल किसी स्वैच्छिक तारों पर पर्ल में एक त्वरित बेंचमार्क चलाया, लेकिन

(?>.*\n)*? 

जो गैर कैप्चरिंग, स्वतंत्र subgrouping करता है कि टुकड़ा स्विचन द्वारा एक 13-15% सुधार मिला है। इससे आपको दो लाभ मिलते हैं, यह अब मिलान करने वाली स्ट्रिंग को कैप्चर करने में समय बर्बाद नहीं करता है, और सबसे महत्वपूर्ण बात यह है कि यह अब भी .* पर बैकट्रैक नहीं है जो वैसे भी समय बर्बाद है। इसका कोई तरीका नहीं है कि इसका केवल एक हिस्सा। * का परिणाम कभी भी एक वैध मैच में होगा जिससे स्पष्ट रूप से इसे सब कुछ बनाया जा सके या कुछ भी मदद नहीं करनी चाहिए।

है कि अगर इस मामले में एक पर्याप्त सुधार है पता है, लेकिन न करें।

+5

+1 आप, महोदय, एक चैंपियन हैं। उसने नौकरी की। – cletus

+0

एक और अधिक जटिल regex था लेकिन कब्जा अनदेखा करने के लिए '?> 'मुद्दे हल! धन्यवाद। –

2

पैटर्न में सुधार करने में मदद और सलाह दी जाती है करता है, जावा के पैटर्न मिलान पुनरावर्ती है और यह आमतौर पर सबसे अच्छा एक सतत समाधान पर स्विच किया जा सके।

जब मैं इसी तरह की समस्या नहीं थी, मैं jregex में स्विच (http://jregex.sourceforge.net/) और यह मेरे लिए काम किया।

पैटर्न मैच बेहतर समाधान के साथ अब सफल रहा है, लेकिन यह विफल हो सकता है अगर के रूप में बड़ा एक पाठ 10 बार दिया गया था।

पुनश्च

: एक पुराने विषय necromancing के लिए क्षमा करें, लेकिन इस सूत्र गूगल पर उच्च स्थान है और अगर मैं इसे यहाँ डाल यह लोगों को लाभ होगा

0

उप अभिव्यक्ति: "(.*\\n)*?" (और बेहतर स्वीकार किए जाते हैं जवाब संस्करण: "(?>.*\n)*?") , दोनों को एक समस्या है: वे एक पंक्ति पर लिखे गए ब्लॉक तत्व से मेल नहीं खाते हैं।

<div>one-liner</div> 

यदि यह वांछित व्यवहार, एक सही (और भी बहुत कुछ कुशल) समाधान केवल उपयोग करने के लिए है नहीं है:: दूसरे शब्दों में, वे इस मैच के लिए असफल

.*?

और बारी एकल लाइन मोड पर।

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