2013-06-07 10 views
5

हालांकि मेरे पास छद्म कोड में रेगेक्स का पर्याप्त ज्ञान है, लेकिन मुझे php regex perl में जो करना है, उसका अनुवाद करने में समस्या हो रही है।
मैं अपनी अभिव्यक्ति के हिस्से को निकालने के लिए preg_match का उपयोग करने की कोशिश कर रहा हूं।
मैं निम्न स्ट्रिंग ${classA.methodA.methodB(classB.methodC(classB.methodD)))} है और मैं 2 काम करने होंगे:
PHP Regex preg_match निष्कर्षण

एक। वाक्य रचना

  • ${classA.methodA.methodB(classB.methodC(classB.methodD)))}वैध मान्य
  • ${classA.methodA.methodB}वैध
  • ${classA.methodA.methodB()}मान्य नहीं
  • ${methodB(methodC(classB.methodD)))}मान्य नहीं

बी। मैं उन जानकारी ${classA.methodA.methodB(classB.methodC(classB.methodD)))} निकालने के लिए की जरूरत लौटना चाहिए

  1. ClassA
  2. MethodA
  3. methodB (classB.methodC (classB.methodD)))

मेरे द्वारा बनाए गए इस कोड को

$expression = '${myvalue.fdsfs.fsdf.blo(fsdf.fsfds(fsfs.fs))}'; 
$pattern = '/\$\{(?:([a-zA-Z0-9]+)\.)(?:([a-zA-Z\d]+)\.)*([a-zA-Z\d.()]+)\}/'; 
if(preg_match($pattern, $expression, $matches)) 
{ 
    echo 'found'.'<br/>'; 
    for($i = 0; $i < count($matches); $i++) 
     echo $i." ".$matches[$i].'<br/>'; 
} 

परिणाम है:
पाया
0 $ {myvalue.fdsfs.fsdf.blo (fsdf.fsfds (fsfs.fs))}
1 myvalue
2 fsdf
3 blo (fsdf.fsfds (fsfs.fs))

जाहिर है मुझे दोहराव के तरीकों को निकालने में मुश्किल हो रही है और यह ठीक से इसे मान्य नहीं कर रहा है (ईमानदारी से मैंने दूसरी समस्या को हल करने के बाद इसे आखिरी बार छोड़ दिया) इसलिए खाली कोष्ठक की अनुमति है और यह जांच नहीं कर रहा है कि एक बार ब्रांड्स को खोला जाए या नहीं बंद होना चाहिए।

धन्यवाद सभी

अद्यतन

एक्स m.buettner

आपकी मदद के लिए धन्यवाद। मैंने आपके कोड की तेज़ कोशिश की लेकिन यह एक बहुत ही छोटा मुद्दा देता है, हालांकि मैं इसे पास कर सकता हूं। अपने पैटर्न परिभाषा के साथ

$expression = '${myvalue.fdsfs}'; 

यह पता चलता है: मुद्दा मेरे पहले कोड में से एक का एक ही है कि मैं यहाँ पोस्ट नहीं जो है जब मैं इस स्ट्रिंग की कोशिश है

found 
0 ${myvalue.fdsfs} 
1 myvalue.fdsfs 
2 myvalue 
3 
4 fdsfs 

आप कर सकते हैं के रूप में देखें कि तीसरी रेखा को एक सफेद जगह के रूप में पकड़ा गया है जो मौजूद नहीं है। मुझे समझ में नहीं आया कि यह ऐसा क्यों कर रहा था, तो क्या आप मुझे सुझाव दे सकते हैं कि php regex सीमाओं के कारण मुझे इसके साथ कैसे रहना है या नहीं?

मैंने कहा कि मैं आपको धन्यवाद दे सकता हूं। न केवल आपने मेरी समस्या का उत्तर दिया बल्कि पैटर्न विकसित करते समय पालन करने के लिए उचित मार्ग पर कई सुझावों के साथ जितना संभव हो उतना जानकारी इनपुट करने की कोशिश की।

एक आखिरी बात मैं (बेवकूफ) एक छोटे से महत्वपूर्ण मामला है जिसमें एक अल्पविराम से विभाजित तो

$expression = '${classA.methodAA(classB.methodBA(classC.methodCA),classC.methodCB)}'; 
$expression = '${classA.methodAA(classB.methodBA(classC.methodCA),classC.methodCB,classD.mehtodDA)}'; 

मान्य होना चाहिए से अधिक पैरामीटर है जोड़ने के लिए भूल गया था।

मैं इस

$expressionPattern =    
     '/ 
     ^     # beginning of the string 
     [$][{]    # literal ${ 
     (     # group 1, used for recursion 
      (    # group 2 (class name) 
      [a-z\d]+  # one or more alphanumeric characters 
     )     # end of group 2 (class name) 
      [.]    # literal . 
      (    # group 3 (all intermediate method names) 
      (?:    # non-capturing group that matches a single method name 
       [a-z\d]+  # one or more alphanumeric characters 
       [.]   # literal . 
      )*    # end of method name, repeat 0 or more times 
     )     # end of group 3 (intermediate method names); 
      (    # group 4 (final method name and arguments) 
      [a-z\d]+  # one or or more alphanumeric characters 
      (?:    # non-capturing group for arguments 
       [(]   # literal (
       (?1)   # recursively apply the pattern inside group 1 
       (?:  # non-capturing group for multiple arguments   
        [,]  # literal , 
        (?1)  # recursively apply the pattern inside group 1 on parameters 
       )*   # end of multiple arguments group; repeat 0 or more times 
       [)]   # literal) 
      )?    # end of argument-group; make optional 
     )     # end of group 4 (method name and arguments) 
     )     # end of group 1 (recursion group) 
     [}]     # literal } 
     $     # end of the string 
     /ix'; 

एक्स कासिमिर एट Hippolyte

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

एक्स Denomales

अपने समर्थन के लिए धन्यवाद, लेकिन अपने कोड गिर जाता है जब मैं इस प्रयास करें:

$sourcestring='${classA1.methodA0.methodA1.methodB1(classB.methodC(classB.methodD))}'; 

परिणाम है:

Array 

( [0] => ऐरे ( [0] => $ {classA1.methodA0.methodA1.methodB1 (classB.methodC (cl assB.methodD))} )

[1] => Array 
    (
     [0] => classA1 
    ) 

[2] => Array 
    (
     [0] => methodA0 
    ) 

[3] => Array 
    (
     [0] => methodA1.methodB1(classB.methodC(classB.methodD)) 
    ) 

) 

यह

[2] => Array 
    (
     [0] => methodA0.methodA1 
    ) 

[3] => Array 
    (
     [0] => methodB1(classB.methodC(classB.methodD)) 
    ) 

) 

या

[2] => Array 
    (
     [0] => methodA0 
    ) 

[3] => Array 
    (
     [0] => methodA1 
    ) 

[4] => Array 
    (
     [0] => methodB1(classB.methodC(classB.methodD)) 
    ) 

) 

उत्तर

6

यह एक कठिन है। पुनरावर्ती पैटर्न अक्सर नियमित अभिव्यक्तियों के साथ क्या संभव है और यहां तक ​​कि यदि यह संभव हो, तो यह अभिव्यक्तियों के लिए बहुत कठिन हो सकता है जो समझने और बनाए रखने के लिए बहुत कठिन हैं।

आप PHP का उपयोग कर रहे हैं और इसलिए पीसीआरई, जो वास्तव में रिकर्सिव रेगेक्स संरचनाओं का समर्थन करता है (?n)। चूंकि आपका रिकर्सिव पैटर्न काफी नियमित है, रेगेक्स का उपयोग करके कुछ हद तक व्यावहारिक समाधान ढूंढना संभव है।

एक चेतावनी मुझे तुरंत उल्लेख करनी चाहिए: चूंकि आप "इंटरमीडिएट" विधि प्रति स्तर कॉल करने की अनुमति देते हैं और मनमानी संख्या (आपके स्निपेट fdsfs और fsdf में), आप इन सभी को अलग-अलग कैप्चर में नहीं प्राप्त कर सकते हैं। पीसीआरई के साथ यह असंभव है। प्रत्येक मैच हमेशा आपके पैटर्न में शुरुआती कोष्ठक की मात्रा द्वारा निर्धारित कैप्चर की एक ही सीमित संख्या उत्पन्न करेगा। यदि एक कैप्चरिंग समूह बार-बार उपयोग किया जाता है (उदाहरण के लिए ([a-z]+\.)+ जैसे कुछ का उपयोग करना) तो हर बार जब समूह का उपयोग किया जाता है तो पिछला कैप्चर ओवरराइट किया जाएगा और आपको केवल अंतिम उदाहरण मिल जाएगा। इसलिए, मैं अनुशंसा करता हूं कि आप सभी "इंटरमीडिएट" विधि कॉल को एकसाथ कैप्चर करें, और फिर परिणामस्वरूप explode पर क्लिक करें।

इसी प्रकार आप एक साथ कई घोंसले के स्तरों को कैप्चर नहीं कर सकते (यदि आप चाहते थे)। इसलिए, आपके वांछित कैप्चर (जहां आखिरी में सभी घोंसले के स्तर शामिल हैं) एकमात्र विकल्प हैं - फिर आप उस स्तर पर फिर से पैटर्न को फिर से नीचे ले जाने के लिए लागू कर सकते हैं।

अब वास्तविक अभिव्यक्ति के लिए:

$pattern = '/ 
    ^     # beginning of the string 
    [$][{]    # literal ${ 
    (     # group 1, used for recursion 
     (     # group 2 (class name) 
     [a-z\d]+   # one or more alphanumeric characters 
    )     # end of group 2 (class name) 
     [.]     # literal . 
     (     # group 3 (all intermediate method names) 
     (?:    # non-capturing group that matches a single method name 
      [a-z\d]+  # one or more alphanumeric characters 
      [.]    # literal . 
     )*    # end of method name, repeat 0 or more times 
    )     # end of group 3 (intermediate method names); 
     (     # group 4 (final method name and arguments) 
     [a-z\d]+   # one or or more alphanumeric characters 
     (?:    # non-capturing group for arguments 
      [(]    # literal (
      (?1)   # recursively apply the pattern inside group 1 
      [)]    # literal) 
     )?    # end of argument-group; make optional 
    )     # end of group 4 (method name and arguments) 
    )      # end of group 1 (recursion group) 
    [}]     # literal } 
    $      # end of the string 
    /ix'; 

कुछ सामान्य नोट: जटिल भाव के लिए (और regex जायके इसका समर्थन में), हमेशा मुक्त रिक्ति x संशोधक जो आप सफेद स्थान को शुरू करने की अनुमति देता है का उपयोग करें और अपनी इच्छाओं को अभिव्यक्ति स्वरूपित करने के लिए टिप्पणियां।उनके बिना, पैटर्न इस तरह दिखता है:

'/^[$][{](([a-z\d]+)[.]((?:[a-z\d]+[.])*)([a-z\d]+(?:[(](?1)[)])?))[}]$/ix' 

यहां तक ​​कि अगर आप रेगुलर एक्सप्रेशन से अपने आप को लिखा है और आप केवल एक है जो कभी परियोजना पर काम करता है कर रहे हैं - अब से एक महीने समझने का प्रयास करें।

दूसरा, मैंने मामले-insenstive i संशोधक का उपयोग कर पैटर्न को थोड़ा सा सरल बना दिया है। यह बस कुछ अव्यवस्था को हटा देता है, क्योंकि आप अपने अक्षरों के ऊपरी-केस प्रकारों को छोड़ सकते हैं।

तीसरा, ध्यान दें कि मैं वर्णों से बचने के लिए [$] और [.] जैसे सिंगल-कैरेक्टर क्लासेस का उपयोग करता हूं, जहां यह संभव है। यह केवल स्वाद का विषय है, और आप बैकस्लैश वेरिएंट का उपयोग करने के लिए स्वतंत्र हैं। मैं व्यक्तिगत रूप से चरित्र वर्गों की पठनीयता को प्राथमिकता देता हूं (और मैं दूसरों को यहां असहमत हूं), इसलिए मैं आपको यह विकल्प भी पेश करना चाहता था।

चौथा, मैंने आपके पैटर्न के चारों ओर एंकर जोड़े हैं, ताकि ${...} के बाहर कोई अमान्य वाक्यविन्यास न हो।

अंत में, रिकर्सन कैसे काम करता है? (?n) बैकरेफर \n के समान है, जिसमें यह समूह n पर कब्जा करने के लिए संदर्भित है (बाएं से दाएं कोष्ठक खोलकर गिना जाता है)। अंतर यह है कि एक बैकरेफर समूह n द्वारा मिलान किए गए मिलान से फिर से मिलान करने का प्रयास करता है, जबकि (?n) पैटर्न को फिर से लागू करता है। यह (.)\1 किसी भी वर्ण को पंक्ति में दो बार मेल खाता है, जबकि (.)(?1) किसी भी चरित्र से मेल खाता है और फिर पैटर्न को फिर से लागू करता है, इसलिए एक और मनमाना चरित्र से मेल खाता है। यदि आप उन (?n) में से किसी एक का उपयोग n वें समूह के भीतर करते हैं, तो आपको रिकर्सन मिलता है। (?0) या (?R) पूरे पैटर्न को संदर्भित करता है। वह सब जादू है।

0 है:

ऊपर पैटर्न इनपुट

'${abc.def.ghi.jkl(mno.pqr(stu.vwx))}' 

कैप्चर में परिणाम होगा

0 ${abc.def.ghi.jkl(mno.pqr(stu.vwx))} 
1 abc.def.ghi.jkl(mno.pqr(stu.vwx)) 
2 abc 
3 def.ghi. 
4 jkl(mno.pqr(stu.vwx)) 

नोट वहाँ आउटपुट देने लायक कुछ अंतर आप वास्तव में उम्मीद कर रहे हैं कि करने के लिए लागू पूरा मिलान (और इस मामले में बस इनपुट स्ट्रिंग फिर से)। PHP हमेशा इस रिपोर्ट की रिपोर्ट करेगा, इसलिए आप इससे छुटकारा नहीं पा सकते हैं।

1 पहला कैप्चरिंग समूह है जो रिकर्सिव भाग को संलग्न करता है। आपको आउटपुट में इसकी आवश्यकता नहीं है, लेकिन (?n) दुर्भाग्यवश गैर-कैप्चरिंग समूहों का संदर्भ नहीं दे सकता है, इसलिए आपको इसकी भी आवश्यकता है।

2 वांछित श्रेणी का नाम है।

3 इंटरमीडिएट विधि नामों की सूची है, साथ ही पिछली अवधि। explode का उपयोग करना इस से सभी विधि नाम निकालना आसान है।

4 वैकल्पिक (रिकर्सिव) तर्क सूची के साथ अंतिम विधि नाम है। अब आप इसे ले सकते हैं, और यदि आवश्यक हो तो पैटर्न फिर से लागू करें। ध्यान दें कि एक पूरी तरह से रिकर्सिव दृष्टिकोण के लिए आप पैटर्न को थोड़ा संशोधित करना चाहेंगे।यही है: ${ और } को एक अलग पहले चरण में बंद करें, ताकि पूरे पैटर्न में अंतिम कैप्चर के समान सटीक (रिकर्सिव) पैटर्न हो, और आप (?1) के बजाय (?0) का उपयोग कर सकते हैं। फिर मिलान करें, विधि नाम, और कोष्ठक हटाएं, और दोहराएं, जब तक कि आपको अंतिम कैप्चर में कोई और ब्रांड्स प्राप्त न हो जाए।

रिकर्सन पर अधिक जानकारी के लिए, PHP's PCRE documentation पर एक नज़र डालें।


मेरा आखिरी बिंदु को वर्णन करने के लिए, यहाँ एक टुकड़ा है कि सभी तत्वों रिकर्सिवली निकालता है:

if(!preg_match('/^[$][{](.*)[}]$/', $expression, $matches)) 
    echo 'Invalid syntax.'; 
else 
    traverseExpression($matches[1]); 

function traverseExpression($expression, $level = 0) { 
    $pattern = '/^(([a-z\d]+)[.]((?:[a-z\d]+[.])*)([a-z\d]+(?:[(](?1)[)])?))$/i'; 
    if(preg_match($pattern, $expression, $matches)) { 
     $indent = str_repeat(" ", 4*$level); 
     echo $indent, "Class name: ", $matches[2], "<br />"; 
     foreach(explode(".", $matches[3], -1) as $method) 
      echo $indent, "Method name: ", $method, "<br />"; 
     $parts = preg_split('/[()]/', $matches[4]); 
     echo $indent, "Method name: ", $parts[0], "<br />"; 
     if(count($parts) > 1) { 
      echo $indent, "With arguments:<br />"; 
      traverseExpression($parts[1], $level+1); 
     } 
    } 
    else 
    { 
     echo 'Invalid syntax.'; 
    } 
} 

फिर से नोट, कि मैं एक एक लाइनर के रूप में पैटर्न इस्तेमाल करने की सलाह नहीं है, लेकिन क्या यह उत्तर पहले से ही काफी लंबा है।

+0

जब मैं इस $ अभिव्यक्ति = '$ {myvalue.fdsfs}' को आजमाता हूं; – user2463968

+0

@ user2463968 फिर क्या? आपको तर्क के बिना कक्षा का नाम, कोई मध्यवर्ती विधियां और अंतिम विधि नहीं मिलती है। क्या यह आपका इरादा नहीं है? –

4

आप एक ही पैटर्न के साथ सत्यापन और निष्कर्षण कर सकते हैं होना चाहिए, उदाहरण के लिए:

$subjects = array(
'${classA.methodA.methodB(classB.methodC(classB.methodD))}', 
'${classA.methodA.methodB}', 
'${classA.methodA.methodB()}', 
'${methodB(methodC(classB.methodD))}', 
'${classA.methodA.methodB(classB.methodC(classB.methodD(classC.methodE)))}', 
'${classA.methodA.methodB(classB.methodC(classB.methodD(classC.methodE())))}' 
); 

$pattern = <<<'LOD' 
~ 
# definitions 
(?(DEFINE)(?<vn>[a-z]\w*+)) 

# pattern 
^\$\{ 
    (?<classA>\g<vn>)\. 
    (?<methodA>\g<vn>)\. 
    (?<methodB> 
     \g<vn> ( 
      \(\g<vn> \. \g<vn> (?-1)?+ \) 
     )?+ 
    ) 
}$ 

~x 
LOD; 

foreach($subjects as $subject) { 
    echo "\n\nsubject: $subject"; 
    if (preg_match($pattern, $subject, $m)) 
     printf("\nclassA: %s\nmethodA: %s\nmethodB: %s", 
      $m['classA'], $m['methodA'], $m['methodB']); 
    else 
     echo "\ninvalid string";  
} 

रेगेक्स एक्सपी लैनेशन:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯

पैटर्न के अंत में आप संशोधक एक्स देख सकते हैं जो पैटर्न के अंदर रिक्त स्थान, न्यूलाइन और कमेंटरी को अनुमति देता है।

पहला पैटर्न नामित समूह vn (परिवर्तनीय नाम) की परिभाषा से शुरू होता है, यहां आप परिभाषित कर सकते हैं कि क्लास ए या विधिबी सभी पैटर्न के लिए कैसा दिखता है। फिर आप \g<vn>

के साथ सभी पैटर्न में इस परिभाषा को संदर्भित कर सकते हैं ध्यान दें कि यदि आप कक्षाओं और अन्य परिभाषाओं को जोड़ने के तरीके के लिए अलग-अलग प्रकार के नाम चाहते हैं तो आप परिभाषित कर सकते हैं।उदाहरण:

(?(DEFINE)(?<cn>....)) # for class name 
(?(DEFINE)(?<mn>....)) # for method name 

पैटर्न ही: नाम वाले समूह में

(?<classA>\g<vn>) कब्जा के लिए ClassA पैटर्न vn

एक ही बात में परिभाषित साथ MethodA

methodB अलग कारण है क्योंकि इसमें नेस्टेड पैरेंट शामिल हो सकता है एसआईएस, यही कारण है कि मैं इस भाग के लिए एक पुनरावर्ती पैटर्न का उपयोग करता हूं।

विवरण:

\g<vn>   # the method name (methodB) 
(    # open a capture group 
    \(  # literal opening parenthesis 
    \g<vn> \. \g<vn> # for classB.methodC⑴ 
    (?-1)?+ # refer the last capture group (the actual capture group) 
       # one or zero time (possessive) to allow the recursion stop 
       # when there is no more level of parenthesis 
    \)   # literal closing parenthesis 
)?+   # close the capture group 
       # one or zero time (possessive) 
       # to allow method without parameters 

आप \g<vn>(?>\.\g<vn>)+ से यह जगह ले सकता है अगर आप एक से अधिक विधि अनुमति देना चाहते हैं।

अधिकार परिमाणकों के बारे में:

आप एक परिमाणक (*+?) यह अधिकार बनाने के लिए के बाद + जोड़ सकते हैं, लाभ regex इंजन पता है कि यह अन्य तरीकों का परीक्षण करने के पीछे करने की जरूरत नहीं है कि है एक subpattern के साथ मैच करने के लिए। रेगेक्स फिर अधिक कुशल है।

+0

27 सेकंड से यह करने के लिए मुझे मारो की अनुमति नहीं दी जाएगी। मुझे उस आदत को भी –

+0

@ m.buettner बनाना चाहिए: मुझे लगता है कि हमने एक ऐतिहासिक विषय बना दिया है! –

+0

आपका सुझाव भी अच्छा है लेकिन इस कोड का उपयोग करते समय यह एक जटिल जटिल स्थिति का तात्पर्य है। मेरा मतलब है कि कोड स्वयं समझना आसान है लेकिन यह कम लचीला हो जाता है। उस ने कहा कि उसने मुझे बहुत सारी जानकारी भी दी है जो भविष्य में निश्चित रूप से सहायक हो सकती है। – user2463968

2

विवरण

इस अभिव्यक्ति से मेल खाते हैं और केवल ${classA.methodA.methodB(classB.methodC(classB.methodD)))} या ${classA.methodA.methodB} प्रारूपों पर कब्जा होगा।

(?:^|\n|\r)[$][{]([^.(}]*)[.]([^.(}]*)[.]([^(}]*(?:[(][^}]+[)])?)[}](?=\n|\r|$)

enter image description here

समूह

समूह 0 पास टेढ़ा-मेढ़ा ब्रैकेट

  1. शुरू डॉलर चिह्न से पूरे मैच हो जाता है कक्षा
  2. पहले हो जाता हो जाता है विधि
  3. को दूसरी विधि के बाद सभी पाठ मिलते हैं लेकिन बंद स्क्विगली ब्रैकेट सहित नहीं। इस समूह खुला दौर कोष्ठक जो खाली हैं है () तो इस मैच असफल हो जायेगी

पीएचपी कोड उदाहरण:

<?php 
$sourcestring="${classA1.methodA1.methodB1(classB.methodC(classB.methodD)))} 
${classA2.methodA2.methodB2} 
${classA3.methodA3.methodB3()} 
${methodB4(methodC4(classB4.methodD)))} 
${classA5.methodA5.methodB5(classB.methodC(classB.methodD)))}"; 
preg_match_all('/(?:^|\n|\r)[$][{]([^.(}]*)[.]([^.(}]*)[.]([^(}]*(?:[(][^}]+[)])?)[}](?=\n|\r|$)/im',$sourcestring,$matches); 
echo "<pre>".print_r($matches,true); 
?> 

$matches Array: 
(
    [0] => Array 
     (
      [0] => ${classA1.methodA1.methodB1(classB.methodC(classB.methodD)))} 
      [1] => 
${classA2.methodA2.methodB2} 
      [2] => 
${classA5.methodA5.methodB5(classB.methodC(classB.methodD)))} 
     ) 

    [1] => Array 
     (
      [0] => classA1 
      [1] => classA2 
      [2] => classA5 
     ) 

    [2] => Array 
     (
      [0] => methodA1 
      [1] => methodA2 
      [2] => methodA5 
     ) 

    [3] => Array 
     (
      [0] => methodB1(classB.methodC(classB.methodD))) 
      [1] => methodB2 
      [2] => methodB5(classB.methodC(classB.methodD))) 
     ) 

) 

अस्वीकरण

  • मैं कक्षा के अंत में एक नंबर जोड़ा गया और समूहों में क्या हो रहा है, यह जानने में मदद करने के लिए विधि नाम
  • ओपी में प्रदान किए गए नमूना पाठ में खुले और करीबी राउंड ब्रैकेट संतुलित नहीं हैं। नामित कब्जा समूहों के लिए डी +1:
  • हालांकि ()(()) की अनुमति दी जाएगी