दिलचस्प पोस्ट
मैं git commit संदेश में डिफ़ॉल्ट टिप्पणियों को कैसे बदल सकता हूँ? यूडब्ल्यूपी में तत्व कैसे स्क्रॉल करें यूनिकोडडेकोड एर्रर: 'मोरैप' कोडेक स्थिति में बाइट एक्स को डीकोड नहीं कर सकता Y: वर्ण मैप को <undefined> Android में डिफ़ॉल्ट चेतावनी संवाद की चौड़ाई और ऊंचाई कैसे नियंत्रित करें? एक स्थैतिक पुस्तकालय में वीसी ++ संसाधन क्या यह नामस्थान ब्लॉक में # शामिल करने के लिए एक अच्छा विचार है? <? Php और <के बीच का अंतर? एंड्रॉइड रिस्ट्रॉफ़्ट – प्रगति नोटिफिकेशन दिखाने के लिए प्रगति अद्यतन Google ग्लास जीडीके: एंड्रॉइड डिवाइस के साथ कैसे संचार करें IEnumerable पर कोई अतिरिक्त विस्तार पद्धति क्यों नहीं है? शरीर में तेजी के साथ एक POST अनुरोध कैसे भेजें उसी विंडो में एक ही विंडो में खोलें और एक ही टैब में सबसे आम एसक्यूएल विरोधी पैटर्न क्या हैं? बूटस्ट्रैप 3 नई स्लाइड के लिए स्लाइड करने के बजाय नई स्लाइड में लुप्त होती हिंडोझल पायथन में Socket.IO क्लाइंट लाइब्रेरी

क्या यह संभव है कि रेगेक्स मेटाचैक्टर्स से एसएएल के साथ मज़बूती से बचें

मैं सोच रहा हूं कि इनपुट स्ट्रिंग में किसी भी regex metacharacters से बचने के लिए एक 100% विश्वसनीय sed कमांड लिखना संभव है, ताकि इसे बाद में कमांड कमांड में इस्तेमाल किया जा सके। इस कदर:

 #!/bin/bash # Trying to replace one regex by another in an input file with sed search="/abc\n\t[az]\+\([^ ]\)\{2,3\}\3" replace="/xyz\n\t[0-9]\+\([^ ]\)\{2,3\}\3" # Sanitize input search=$(sed 'script to escape' <<< "$search") replace=$(sed 'script to escape' <<< "$replace") # Use it in a sed command sed "s/$search/$replace/" input 

मुझे पता है कि पैटर्न के बजाय निश्चित स्ट्रिंग के साथ काम करने के लिए बेहतर उपकरण हैं, उदाहरण के लिए, awk , perl या python मैं बस यह साबित करना चाहूंगा कि क्या यह संभव है या नहीं इसके साथ। मैं कहूंगा कि हम और भी मज़ेदार होने के लिए मूल पोसिक्स रीगेक्सेस पर ध्यान केंद्रित करें! 🙂

मैंने बहुत सी चीजों की कोशिश की है, लेकिन कभी भी मुझे एक ऐसा इनपुट मिल सकता है जिसने मेरा प्रयास तोड़ दिया। मैंने सोचा कि सार को script to escape रूप में script to escape किसी को भी गलत दिशा में नहीं ले जाया जाएगा।

बीटीडब्ल्यू, चर्चा यहां आई थी। मैंने सोचा था कि यह समाधान इकट्ठा करने के लिए एक अच्छा स्थान हो सकता है और संभवतः उन्हें ब्रेक और / या विस्तृत कर सकता है।

Solutions Collecting From Web of "क्या यह संभव है कि रेगेक्स मेटाचैक्टर्स से एसएएल के साथ मज़बूती से बचें"

ध्यान दें:

  • यदि आप इस उत्तर में चर्चा की गई तकनीकों के आधार पर प्रीपेक्जड कार्यक्षमता की तलाश कर रहे हैं:
    • bash फ़ंक्शंस जो मल्टी-लाइन प्रतिस्थापनों में भी बच निकलने में सक्षम बनाता है , इस पोस्ट के निचले भाग में मिल सकते हैं (साथ ही एक perl समाधान जो इस तरह के बचने के लिए perl के अंतर्निहित समर्थन का उपयोग करता है)
    • @ एड मॉर्टन के उत्तर में एक उपकरण ( bash स्क्रिप्ट) होता है जो एकल-पंक्ति प्रतिस्थापन को मजबूत करता है
  • सभी स्निपेट्स को bash रूप में खोल (POSIX- आज्ञाकारी reformulations संभव है) मानते हैं:

सिंगल लाइन सॉल्यूशंस


sed में रेगेक्स के रूप में उपयोग करने के लिए एक स्ट्रिंग से sed :

श्रेय देने के लिए जहां श्रेय दिया गया है: मुझे इस उत्तर में नीचे दिए गए रेगेक्स मिले।

मान लें कि खोज स्ट्रिंग एक -लाइन स्ट्रिंग है:

 search='abc\n\t[az]\+\([^ ]\)\{2,3\}\3' # sample input containing metachars. searchEscaped=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<<"$search") # escape it. sed -n "s/$searchEscaped/foo/p" <<<"$search" # if ok, echoes 'foo' 
  • ^ को छोड़कर प्रत्येक चरित्र को अपने स्वयं के चरित्र सेट में रखा गया है [...] अभिव्यक्ति को इसे एक शाब्दिक रूप में माना जाता है
    • ध्यान दें कि ^ एक चार है आप [^] रूप में प्रतिनिधित्व नहीं कर सकते , क्योंकि उस स्थान (निषेध) में इसका विशेष अर्थ है
  • फिर, ^ वर्ण \^ रूप में बच गए हैं

दृष्टिकोण मजबूत है, लेकिन कुशल नहीं है

सशक्तता से सभी विशेष रेगेक्स वर्णों की अपेक्षा करने की कोशिश नहीं की जाती है – जो सभी regex बोलियों में भिन्न होगी – लेकिन केवल सभी फीजीक्स बोलियों द्वारा साझा की जाने वाली सुविधाओं पर ध्यान केंद्रित करने के लिए:

  • एक चरित्र सेट के अंदर शाब्दिक पात्रों को निर्दिष्ट करने की क्षमता।
  • एक शाब्दिक ^ as \^ से बचने की क्षमता

sed की s/// कमांड में प्रतिस्थापन स्ट्रिंग के रूप में उपयोग करने के लिए एक स्ट्रिंग से बचें:

sed s/// कमांड में प्रतिस्थापन स्ट्रिंग एक रेगेक्स नहीं है, लेकिन यह प्लेसहोल्डर्स को पहचानता है जो या तो पूरे स्ट्रिंग को रैगेक्स ( & ) या विशिष्ट कैप्चर-ग्रुप के परिणाम से इंडेक्स ( \1 , \2 , ..), तो ये (प्रथागत) रेगेक्स सीमांकक के साथ बच निकलना चाहिए, /

मान लें कि प्रतिस्थापन स्ट्रिंग एक -लाइन स्ट्रिंग है:

 replace='Laurel & Hardy; PS\2' # sample input containing metachars. replaceEscaped=$(sed 's/[&/\]/\\&/g' <<<"$replace") # escape it sed -n "s/\(.*\) \(.*\)/$replaceEscaped/p" <<<"foo bar" # if ok, outputs $replace as is 


बहु-लाइन समाधान


sed में रेगेक्स के रूप में उपयोग करने के लिए एक बहु-लाइन स्ट्रिंग से sed :

नोट : यह केवल तभी समझ में आता है जब मिलान करने के लिए कई इनपुट लाइन (संभवतः सभी) पढ़े गए हैं।
चूंकि sed और awk जैसे उपकरण डिफ़ॉल्ट रूप से एक समय में एक लाइन पर काम करते हैं, इसलिए एक समय में एक से अधिक पंक्ति को पढ़ने के लिए अतिरिक्त कदमों की आवश्यकता होती है।

 # Define sample multi-line literal. search='/abc\n\t[az]\+\([^ ]\)\{2,3\}\3 /def\n\t[AZ]\+\([^ ]\)\{3,4\}\4' # Escape it. searchEscaped=$(sed -e 's/[^^]/[&]/g; s/\^/\\^/g; $!a\'$'\n''\\n' <<<"$search" | tr -d '\n') #' # Use in a Sed command that reads ALL input lines up front. # If ok, echoes 'foo' sed -n -e ':a' -e '$!{N;ba' -e '}' -e "s/$searchEscaped/foo/p" <<<"$search" 
  • बहु-पंक्ति इनपुट स्ट्रिंग में नई लाइनें '\n' स्ट्रिंग्स में अनुवादित की जानी चाहिए, जो कि एक रीजेक्स में न्यूलाइन कैसे एन्कोडेड हैं।
  • $!a\'$'\n''\\n' प्रत्येक स्ट्रिंग को जोड़ता है '\n' प्रत्येक आउटपुट लाइन पर, लेकिन आखिरी (आखिरी न्यूलाइन पर ध्यान नहीं दिया जाता है, क्योंकि यह <<< द्वारा जोड़ा गया था)
  • tr -d '\n तब स्ट्रिंग से सभी वास्तविक नई लाइनें निकाल दी जाती हैं (और जब भी इसकी पैटर्न को छापती है तो एक को जोड़ता है), '\n' तारों के साथ इनपुट में सभी नई लाइनों को प्रभावी ढंग से बदल देता है
  • -e ':a' -e '$!{N;ba' -e '}' का पॉसिक्स-अनुपालन वाला स्वरूप है जो सभी इनपुट लाइनों को एक लूप पढ़ता है, इसलिए बाद के आदेशों को सभी इनपुट लाइनों पर संचालित करने के लिए छोड़कर एक बार।

sed की s/// कमांड में प्रतिस्थापन स्ट्रिंग के रूप में उपयोग करने के लिए एक बहु-लाइन स्ट्रिंग से बचें:

 # Define sample multi-line literal. replace='Laurel & Hardy; PS\2 Masters\1 & Johnson\2' # Escape it for use as a Sed replacement string. IFS= read -d '' -r < <(sed -e ':a' -e '$!{N;ba' -e '}' -e 's/[&/\]/\\&/g; s/\n/\\&/g' <<<"$replace") replaceEscaped=${REPLY%$'\n'} # If ok, outputs $replace as is. sed -n "s/\(.*\) \(.*\)/$replaceEscaped/p" <<<"foo bar" 
  • इनपुट स्ट्रिंग में नई लाइनें वास्तविक नई पंक्तियों के रूप में बनाए रखी जानी चाहिए, लेकिन \ -छेक्षित
  • -e ':a' -e '$!{N;ba' -e '}' sed मुहावरे के पॉसिक्स-अनुरूप फॉर्म है जो सभी इनपुट लाइनों को एक लूप पढ़ता है।
  • 's/[&/\]/\\&/g सभी- & , \ और / उदाहरणों से बचते हैं, जैसे एकल-पंक्ति समाधान में।
  • s/\n/\\&/g' फिर \ -सभी वास्तविक नई लाइनों को प्रीफिक्स करता है
  • IFS= read -d '' -r को sed कमांड की आउटपुट को पढ़ने के लिए प्रयोग किया जाता है (जो कि न्यूलाइंस के स्वत: हटाने से बचने के लिए है, जो कि कमांड प्रतिस्थापन ( $(...) ) प्रदर्शन करेंगे।
  • ${REPLY%$'\n'} फिर एक एकल अनुगामी नई लाइन को निकालता है, जो <<< ने निविष्ट रूप से इनपुट में जोड़ा है


उपरोक्त ( sed ) के आधार पर bash फ़ंक्शंस :

  • quoteRe() एक regex में उपयोग के लिए उद्धरण (पलायन)
  • quoteSubst() एक s/// कॉल के प्रतिस्थापन स्ट्रिंग में उपयोग के लिए उद्धरण।
  • दोनों मल्टी-लाइन इनपुट सही ढंग से संभालते हैं
    • ध्यान दें कि क्योंकि sed समय पर एक ही पंक्ति को डिफ़ॉल्ट रूप से पढ़ता है, बहु-लाइन स्ट्रिंग के साथ quoteRe() का उपयोग केवल कमांड में ही समझ में आता है, जो एक बार में कई (या सभी) लाइनों को स्पष्ट रूप से पढ़ता है
    • इसके अलावा, कमांड प्रतिस्थापन ( $(...) ) का उपयोग करने के लिए फ़ंक्शन कॉल करने के लिए स्ट्रिंग के लिए काम नहीं करेगा जो कि नई लाइनों का अनुपालन करते हैं; उस घटना में, IFS= read -d '' -r escapedValue <(quoteSubst "$value") तरह कुछ का उपयोग करें
 # SYNOPSIS # quoteRe <text> quoteRe() { sed -e 's/[^^]/[&]/g; s/\^/\\^/g; $!a\'$'\n''\\n' <<<"$1" | tr -d '\n'; } 
 # SYNOPSIS # quoteSubst <text> quoteSubst() { IFS= read -d '' -r < <(sed -e ':a' -e '$!{N;ba' -e '}' -e 's/[&/\]/\\&/g; s/\n/\\&/g' <<<"$1") printf %s "${REPLY%$'\n'}" } 

उदाहरण:

 from=$'Cost\(*):\n$3.' # sample input containing metachars. to='You & I'$'\n''eating A\1 sauce.' # sample replacement string with metachars. # Should print the unmodified value of $to sed -e ':a' -e '$!{N;ba' -e '}' -e "s/$(quoteRe "$from")/$(quoteSubst "$to")/" <<<"$from" 

-e ':a' -e '$!{N;ba' -e '}' के उपयोग पर ध्यान दें कि सभी इनपुट एक ही बार में पढ़ने के लिए, ताकि बहु-लाइन प्रतिस्थापन काम करे।



perl समाधान:

पर्ल ने quotemeta() में शाब्दिक उपयोग के लिए मनमाने ढंग से स्ट्रिंग से बचने के लिए अंतर्निहित समर्थन दिया है : quotemeta() फ़ंक्शन या इसके बराबर \Q...\E उद्धरण
दृष्टिकोण एकल और बहु-लाइन स्ट्रिंग दोनों के लिए समान है; उदाहरण के लिए:

 from=$'Cost\(*):\n$3.' # sample input containing metachars. to='You owe me $1/$& for'$'\n''eating A\1 sauce.' # sample replacement string w/ metachars. # Should print the unmodified value of $to. # Note that the replacement value needs NO escaping. perl -s -0777 -pe 's/\Q$from\E/$to/' -- -from="$from" -to="$to" <<<"$from" 
  • सभी इनपुट को एक बार में पढ़ने के लिए -0777 के उपयोग पर ध्यान दें, ताकि बहु-लाइन प्रतिस्थापन काम कर सके।

  • -s विकल्प को अनुमति देने की अनुमति देता है -<var>=<val> -स्टाइल पर्ल चर परिभाषाएं -- स्क्रिप्ट के बाद, किसी भी फाइलनाम ऑपरेंड से पहले।

इस सूत्र में @ एमकेलेमेंट0 के उत्तर पर बिल्डिंग, निम्न उपकरण किसी भी एकल-पंक्ति स्ट्रिंग को (जैसा regexp के विरोध में) किसी और एकल पंक्ति के साथ sed और bash का उपयोग कर बदल देगा:

 $ cat sedstr #!/bin/bash old="$1" new="$2" file="${3:--}" escOld=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< "$old") escNew=$(sed 's/[&/\]/\\&/g' <<< "$new") sed "s/$escOld/$escNew/g" "$file" 

इस उपकरण की ज़रूरत को वर्णन करने के लिए, a.*/b{2,}\nc को d&e\1f साथ बदलने की कोशिश करने पर विचार करें a.*/b{2,}\nc

 $ cat file a.*/b{2,}\nc axx/bb\nc $ sed 's/a.*/b{2,}\nc/d&e\1f/' file sed: -e expression #1, char 16: unknown option to `s' $ sed 's/a.*\/b{2,}\nc/d&e\1f/' file sed: -e expression #1, char 23: invalid reference \1 on `s' command's RHS $ sed 's/a.*\/b{2,}\nc/d&e\\1f/' file a.*/b{2,}\nc axx/bb\nc # .... and so on, peeling the onion ad nauseum until: $ sed 's/a\.\*\/b{2,}\\nc/d\&e\\1f/' file d&e\1f axx/bb\nc 

या उपरोक्त उपकरण का उपयोग करें:

 $ sedstr 'a.*/b{2,}\nc' 'd&e\1f' file d&e\1f axx/bb\nc 

यह उपयोगी साबित हो सकता है कि यदि आवश्यक हो तो शब्दों को बदलने के लिए शब्द-सीमांकक का उपयोग करने के लिए आसानी से संवर्धित किया जा सकता है, उदाहरण के लिए जीएनयू sed वाक्यविन्यास:

 sed "s/\<$escOld\>/$escNew/g" "$file" 

जबकि उपकरण जो वास्तव में तारों पर काम करते हैं (जैसे कि awk index() ) शब्द-सीमांकक का उपयोग नहीं कर सकते हैं