2015-02-13 4 views
11

मेरे पास निम्न डेटा है जहां {n} प्लेसहोल्डर का प्रतिनिधित्व करता है।प्रत्येक उदाहरण को दो वर्णों के बीच बदलें

{n}{n}A{n}{n}A{n} 
{n}A{n}{n}{n}{n}A 
{n}{n}A{n}A{n}{n} 
{n}{n}{n}A{n}A{n}B 
{n}A{n}{n}B{n}{n} 
A{n}B{n}{n}{n}{n} 

मैं उदाहरण पत्र C के लिए के साथ दो एक वर्णों के बीच प्लेसहोल्डर के प्रत्येक उदाहरण को बदलने के लिए चाहते हैं। मैंने इसके लिए निम्नलिखित रेगेक्स लिखा है और मैं preg_replace फ़ंक्शन का उपयोग कर रहा हूं।

$str = preg_replace('~(?<=A)(\{n\})*(?=A)~', 'C', $str); 

समस्या यह है कि यह एक C के साथ दो एक के बीच सभी उदाहरणों की जगह है। C के साथ प्लेसहोल्डर के प्रत्येक व्यक्तिगत उदाहरण को प्रतिस्थापित करने के लिए मैं अपने regex या preg_replace कॉल को कैसे ठीक कर सकता हूं?

यह मेरा आउटपुट होना चाहिए।

{n}{n}ACCA{n} 
{n}ACCCCA 
{n}{n}ACA{n}{n} 
{n}{n}{n}ACA{n}B 
{n}A{n}{n}B{n}{n} 
A{n}B{n}{n}{n}{n} 

लेकिन वर्तमान में यह इसे आउटपुट करता है।

{n}{n}ACA{n} 
{n}ACA 
{n}{n}ACA{n}{n} 
{n}{n}{n}ACA{n}B 
{n}A{n}{n}B{n}{n} 
A{n}B{n}{n}{n}{n} 
+0

इस स्थिति में क्या होता है: 'ए {एन} ए {एन} ए'? 'एसीए {एन} ए' या 'एसीएसीए'? –

उत्तर

8

आप \G के साथ एंकरिंग द्वारा समस्या को हल कर सकते हैं।

$str = preg_replace('~(?:\G(?!\A)|({n})*A(?=(?1)++A))\K{n}~', 'C', $str); 

\G सुविधा एक लंगर है कि दो स्थानों में से एक में से मिलान कर सकते है; अंतिम मैच के अंत में स्ट्रिंग स्थिति या स्थिति की शुरुआत। \K भागने अनुक्रम रिपोर्ट किए गए मैच के शुरुआती बिंदु को रीसेट करता है और पहले से उपभोग वाले वर्णों को अब शामिल नहीं किया जाता है।

बैक ट्रैकिंग की मात्रा को कम करने के लिए, आप एक अधिक जटिल अभिव्यक्ति इस्तेमाल कर सकते हैं:

$str = preg_replace('~\G(?!\A)(?:{n} 
         |A(?:[^A]*A)+?((?=(?:{n})++A)\K{n} 
         |(*COMMIT)(*F))) 
         |[^A]*A(?:[^A]*A)*?(?1)~x', 'C', $str); 
+3

[+] (http://en.wikipedia.org/wiki/Plus_and_minus_signs) 1 '\ K' के भयानक उपयोग के लिए। – Unihedron

4
(?<=A){n}(?=(?:{n})*A)|\G(?!^){n} 

आप इस कोशिश कर सकते हैं। C द्वारा बदलें। पिछले मैच के अंत में स्थिति या पहले मैच के लिए स्ट्रिंग की शुरुआत करने के लिए आपको \G का उपयोग करना होगा।

ताकि आप अपने पहले मैच के बाद मैच कर सकें। डेमो देखें।

https://regex101.com/r/wU4xK1/7

यहाँ पहले आप {n} जो इसे बाद इसके पीछे A और A है से मेल खाते हैं जो बीच में {n} हो सकता है। कैप्चर करने के बाद, आप पिछले मैच के अंत में रीसेट करने के लिए \G का उपयोग करते हैं और बाद में {n} को स्थानांतरित करते रहते हैं।

$re = "/(?<=A){n}(?=(?:{n})*A)|\\G(?!^){n}/"; 
$str = "{n}{n}A{n}{n}A{n}\n{n}A{n}{n}{n}{n}A\n{n}{n}A{n}A{n}{n}\n{n}{n}{n}A{n}A{n}B\n{n}A{n}{n}B{n}{n}\nA{n}B{n}{n}{n}{n}"; 
$subst = "C"; 

$result = preg_replace($re, $subst, $str); 
7

कुछ और अधिक वर्बोज़ लेकिन आसान का पालन करने के समाधान समूहों में पाठ को तोड़ने के लिए प्रारंभिक अभिव्यक्ति का उपयोग करने के लिए है, फिर प्रत्येक समूह के अंदर अलग-अलग परिवर्तन लागू करें:

$text = preg_replace_callback('~(?<=A)(?:\{n\})*(?=A)~', function($match) { 
    // simple replacement inside 
    return str_replace('{n}', 'C', $match[0]); 
}, $text); 

मैं, स्मृति पर कब्जा है, जो अनावश्यक है से छुटकारा पाने के अभिव्यक्ति के लिए एक छोटी सी ट्वीक कर दिया है (?:...) का उपयोग करके।

+2

ईमानदारी से, यदि प्रदर्शन एक मुद्दा है तो शायद एक तेज़ समाधान। (+1) – hwnd

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