Preg_replace () e modifier को preg_replace_callback से बदलें


83

मैं नियमित अभिव्यक्तियों से भयानक हूं। मैं इसे बदलने की कोशिश कर रहा हूँ:

public static function camelize($word) {
   return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word);
}

अनाम फ़ंक्शन के साथ preg_replace_callback। मुझे समझ नहीं आ रहा है कि \\ 2 क्या कर रहा है। या इस बात के लिए कि वास्तव में preg_replace_callback कैसे काम करता है।

इसे प्राप्त करने के लिए सही कोड क्या होगा?


1
संशोधक है पदावनत पीएचपी 5.5.0 के रूप में
हमजा

8
@ HamZaDzCyberDeV मुझे पता है। यही कारण है कि मैं इसे preg_replace_callback के साथ बदलना चाहता हूं
Casey

2
के लिए एक मैनुअल पेज है preg_replace_callback। और उक्त कॉलबैक में \\2बन जाएगा $matches[2]। या आप किस हिस्से के बारे में विशेष रूप से भ्रमित हैं?
मारियो

@ उमरियो आह $ द मैच [2] मैं सभी की जरूरत थी। मुझे अभी भी समझ नहीं आया कि यह कैसे काम करता है, लेकिन यह करता है। यदि आप एक जवाब में कहते हैं कि मैं इसे चिह्नित करूंगा तो यह समस्या का समाधान होगा।
केसी

3
कृपया उपयोग न करें create_function, यह अभी तक एक और आवरण है eval। आपको उचित अनाम फ़ंक्शन का उपयोग करना चाहिए, जब तक कि आप किसी कारण से PHP 5.2 में फंस न जाएं।
IMSoP

जवाबों:


75

एक नियमित अभिव्यक्ति में, आप मिलान किए गए स्ट्रिंग के कुछ हिस्सों को "कैप्चर" कर सकते हैं (brackets); इस मामले में, आप पर कब्जा कर रहे हैं (^|_)और([a-z]) मैच के कुछ हिस्सों। इन्हें 1 पर शुरू किया गया है, इसलिए आपके पास 1-संदर्भ 1 और 2 है। मैच 0 पूरी मिलान स्ट्रिंग है।

/eसंशोधक एक प्रतिस्थापन स्ट्रिंग लेता है, और विकल्प एक नंबर (जैसे के बाद बैकस्लैश \1) उचित पीठ के संदर्भ के साथ - लेकिन क्योंकि आप एक स्ट्रिंग के अंदर हैं, तो आप बैकस्लैश से बचने के लिए, ताकि आप की आवश्यकता '\\1'। यह तब (प्रभावी रूप से) evalपरिणामी स्ट्रिंग को चलाने के लिए चलाता है जैसे कि यह PHP कोड था (यही कारण है कि इसे हटा दिया जा रहा है, क्योंकि इसका उपयोग करना आसान हैeval असुरक्षित तरीके )।

इसके preg_replace_callbackबजाय फ़ंक्शन एक कॉलबैक फ़ंक्शन लेता है और इसे एक सरणी पास करता है जिसमें मिलान किए गए बैक-संदर्भ होते हैं। इसलिए जहां आपने लिखा होगा '\\1', आप उस पैरामीटर के तत्व 1 का उपयोग कर सकते हैं - जैसे यदि आपके पास फॉर्म का एक अनाम फ़ंक्शन है function($matches) { ... }, तो पहला बैक-रेफरेंस $matches[1]उस फ़ंक्शन के अंदर है।

तो का एक /eतर्क

'do_stuff(\\1) . "and" . do_stuff(\\2)'

का कॉलबैक बन सकता है

function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }

या आपके मामले में

'strtoupper("\\2")'

हो सकता हे

function($m) { return strtoupper($m[2]); }

ध्यान दें कि $mऔर $matchesजादू के नाम नहीं हैं, वे केवल मेरे कॉलबैक फ़ंक्शन की घोषणा करते समय दिए गए पैरामीटर नाम हैं। इसके अलावा, आपको एक अनाम फ़ंक्शन पास करने की ज़रूरत नहीं है, यह एक स्ट्रिंग के रूप में एक फ़ंक्शन नाम हो सकता है, या कुछ के रूप में array($object, $method), जैसा कि PHP में किसी भी कॉलबैक के साथ हो सकता है , जैसे।

function stuffy_callback($things) {
    return do_stuff($things[1]) . "and" . do_stuff($things[2]);
}
$foo = preg_replace_callback('/([a-z]+) and ([a-z]+)/', 'stuffy_callback', 'fish and chips');

किसी भी फ़ंक्शन के साथ, आप डिफ़ॉल्ट रूप से अपने कॉलबैक (आसपास के दायरे से) के बाहर चर का उपयोग नहीं कर सकते। एक अनाम फ़ंक्शन का उपयोग करते समय, आप useकीवर्ड का उपयोग उन चर आयात करने के लिए कर सकते हैं, जिनकी आपको उपयोग करने की आवश्यकता है, जैसा कि PHP मैनुअल में चर्चा की गई है । जैसे अगर पुराना तर्क था

'do_stuff(\\1, $foo)'

तब नया कॉलबैक दिख सकता है

function($m) use ($foo) { return do_stuff($m[1], $foo); }

gotchas

  • उपयोग की preg_replace_callbackहै के बजाय/e तो आप अपने "पैटर्न" तर्क से कि झंडा हटाने की जरूरत, regex पर संशोधक। तो जैसे एक पैटर्न /blah(.*)blah/meiबन जाएगा /blah(.*)blah/mi
  • /eसंशोधक का एक संस्करण का इस्तेमाल किया addslashes()तर्क पर आंतरिक रूप से है, इसलिए कुछ प्रतिस्थापन इस्तेमाल किया stripslashes()इसे हटाने के लिए; ज्यादातर मामलों में, आप शायद stripslashesअपने नए कॉलबैक से कॉल को निकालना चाहते हैं ।

1

preg_replace eval सपोर्ट के साथ शिम

यह बहुत ही असावधान है। लेकिन अगर आप एक प्रोग्रामर नहीं हैं, या वास्तव में भयानक कोड पसंद करते हैं, तो आप एक विकल्प का उपयोग कर सकते हैंpreg_replace अपने /eध्वज को अस्थायी रूप से काम करने के फ़ंक्शन का ।

/**
 * Can be used as a stopgap shim for preg_replace() calls with /e flag.
 * Is likely to fail for more complex string munging expressions. And
 * very obviously won't help with local-scope variable expressions.
 *
 * @license: CC-BY-*.*-comment-must-be-retained
 * @security: Provides `eval` support for replacement patterns. Which
 *   poses troubles for user-supplied input when paired with overly
 *   generic placeholders. This variant is only slightly stricter than
 *   the C implementation, but still susceptible to varexpression, quote
 *   breakouts and mundane exploits from unquoted capture placeholders.
 * @url: https://stackoverflow.com/q/15454220
 */
function preg_replace_eval($pattern, $replacement, $subject, $limit=-1) {
    # strip /e flag
    $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern);
    # warn about most blatant misuses at least
    if (preg_match('/\(\.[+*]/', $pattern)) {
        trigger_error("preg_replace_eval(): regex contains (.*) or (.+) placeholders, which easily causes security issues for unconstrained/user input in the replacement expression. Transform your code to use preg_replace_callback() with a sane replacement callback!");
    }
    # run preg_replace with eval-callback
    return preg_replace_callback(
        $pattern,
        function ($matches) use ($replacement) {
            # substitute $1/$2/… with literals from $matches[]
            $repl = preg_replace_callback(
                '/(?<!\\\\)(?:[$]|\\\\)(\d+)/',
                function ($m) use ($matches) {
                    if (!isset($matches[$m[1]])) { trigger_error("No capture group for '$m[0]' eval placeholder"); }
                    return addcslashes($matches[$m[1]], '\"\'\`\$\\\0'); # additionally escapes '$' and backticks
                },
                $replacement
            );
            # run the replacement expression
            return eval("return $repl;");
        },
        $subject,
        $limit
    );
}

संक्षेप में, आप उस फ़ंक्शन को अपने कोडबेस में शामिल करते हैं, और जहाँ भी ध्वज का उपयोग किया गया था , उसे संपादित preg_replace करते हैं ।preg_replace_eval/e

पेशेवरों और विपक्ष :

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

रिप्लेसमेंट कोड जनरेटर

अब यह कुछ हद तक बेमानी है। लेकिन उन उपयोगकर्ताओं की मदद कर सकते हैं जो अभी भी अपने कोड को मैन्युअल रूप से पुनर्गठन करने से अभिभूत हैं preg_replace_callback। जबकि यह प्रभावी रूप से अधिक समय लेने वाला है, एक कोड जनरेटर को /eएक अभिव्यक्ति में प्रतिस्थापन स्ट्रिंग का विस्तार करने के लिए कम परेशानी होती है । यह एक बहुत ही अचूक रूपांतरण है, लेकिन सबसे अधिक प्रचलित उदाहरणों की संभावना है।

इस फ़ंक्शन का उपयोग करने के लिए, किसी भी टूटी हुई preg_replaceकॉल को संपादित करें preg_replace_eval_replacementऔर इसे एक बार चलाएं । यह उसके स्थान पर उपयोग किए जाने वाले अनुसार preg_replace_callbackब्लॉक का प्रिंट आउट लेगा ।

/**
 * Use once to generate a crude preg_replace_callback() substitution. Might often
 * require additional changes in the `return …;` expression. You'll also have to
 * refit the variable names for input/output obviously.
 *
 * >>>  preg_replace_eval_replacement("/\w+/", 'strtopupper("$1")', $ignored);
 */
function preg_replace_eval_replacement($pattern, $replacement, $subjectvar="IGNORED") {
    $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern);
    $replacement = preg_replace_callback('/[\'\"]?(?<!\\\\)(?:[$]|\\\\)(\d+)[\'\"]?/', function ($m) { return "\$m[{$m[1]}]"; }, $replacement);
    $ve = "var_export";
    $bt = debug_backtrace(0, 1)[0];
    print "<pre><code>
    #----------------------------------------------------
    # replace preg_*() call in '$bt[file]' line $bt[line] with:
    #----------------------------------------------------
    \$OUTPUT_VAR = preg_replace_callback(
        {$ve($pattern, TRUE)},
        function (\$m) {
            return {$replacement};
        },
        \$YOUR_INPUT_VARIABLE_GOES_HERE
    )
    #----------------------------------------------------
    </code></pre>\n";
}

ध्यान रखें कि केवल कॉपी और पेस्ट करना ही प्रोग्रामिंग नहीं है। आपको अपने वास्तविक इनपुट / आउटपुट चर नामों या उपयोग के संदर्भ में उत्पन्न कोड को वापस अनुकूलित करना होगा।

  • $OUTPUT =यदि पिछले preg_replaceकॉल का उपयोग किया गया था तो विशिष्ट रूप से असाइनमेंट को जाना होगा if
  • हालाँकि अस्थायी चर या बहु-कोड ब्लॉक संरचना को रखना सबसे अच्छा है।

और प्रतिस्थापन अभिव्यक्ति अधिक पठनीयता सुधार या पुन: काम की मांग कर सकती है।

  • उदाहरण के लिए stripslashes()अक्सर शाब्दिक अभिव्यक्तियों में निरर्थक हो जाता है।
  • वैरिएबल-स्कोप लुकअप की आवश्यकता होती है useयाglobal कॉलबैक के भीतर / के लिए संदर्भ।
  • असमान रूप से उद्धृत-संलग्न "-$1-$2"कैप्चर संदर्भ, सादे परिवर्तन द्वारा वाक्य-रचना को तोड़ देगा "-$m[1]-$m[2]

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


0

आपको ध्वज e(या evalसामान्य रूप से) का उपयोग नहीं करना चाहिए ।

आप टी-रेक्स लाइब्रेरी का भी उपयोग कर सकते हैं

pattern('(^|_)([a-z])')->replace($word)->by()->group(2)->callback('strtoupper');
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.