প্রিগ_রেপ্লেস () এবং মডিফায়ার প্রিগ_রেপ্লেস_ক্যালব্যাক দিয়ে প্রতিস্থাপন করুন


83

আমি নিয়মিত প্রকাশ সঙ্গে ভয়ানক। আমি এটি প্রতিস্থাপন করার চেষ্টা করছি:

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

একটি বেনামী ফাংশন সহ preg_replace_callback সহ। আমি বুঝতে পারি না যে 2 ডলার কী করছে। বা এই বিষয়টির জন্য ঠিক কীভাবে প্রাক-পূর্ববর্তী_ক্যালব্যাক কাজ করে works

এটি অর্জনের জন্য সঠিক কোডটি কী হবে?


4
পরিবর্তক হয় অবচিত পিএইচপি 5.5.0 হিসাবে
হামজা

8
আমি জানি আমি এটিকে preg_replace_callback- এর সাথে প্রতিস্থাপন করতে চাওয়ার একটি কারণ
কেসি

4
এর জন্য একটি ম্যানুয়াল পৃষ্ঠা রয়েছে preg_replace_callback। এবং \\2হয়ে উঠবে $matches[2]কলব্যাক। অথবা আপনি কোন অংশটি সম্পর্কে বিশেষভাবে বিভ্রান্ত?
মারিও

@ আমারিও আহ $ ম্যাচগুলি [2] আমার যা দরকার তা ছিল। এটি কীভাবে কাজ করে তা আমি এখনও বুঝতে পারি না তবে এটি করে। আপনি যদি একটি উত্তরে রাখেন তবে আমি চিহ্নিত করব এটি সমস্যার সমাধান হিসাবে।
ক্যাসি

4
দয়া করে ব্যবহার করবেন না create_function, এটি প্রায় আরও একটি মোড়ক eval। আপনার কোনও সঠিক বেনামি ফাংশন ব্যবহার করা উচিত, যদি না আপনি কোনও কারণে পিএইচপি 5.2 এ আটকে থাকেন।
আইএমএসওপি

উত্তর:


76

একটি নিয়মিত প্রকাশে, আপনি এর সাথে মিলে যাওয়া স্ট্রিংয়ের অংশগুলি "ক্যাপচার" করতে পারেন (brackets) ; এই ক্ষেত্রে, আপনি ম্যাচের অংশ (^|_)এবং ([a-z])অংশগুলি ক্যাপচার করছেন । এগুলি 1 থেকে শুরু করে সংখ্যাযুক্ত, সুতরাং আপনার 1 এবং 2 এর পিছনে রেফারেন্স রয়েছে 0 ম্যাচ 0 সম্পূর্ণ ম্যাচিং স্ট্রিং।

/eপরিবর্তক একটি প্রতিস্থাপন স্ট্রিং নেয় এবং পরিপূরক একটি সংখ্যা (যেমন দ্বারা অনুসরণ ব্যাকস্ল্যাশ \1) উপযুক্ত ব্যাক রেফারেন্স সহ - কিন্তু কারণ আপনি একটি স্ট্রিং ভিতরে, আপনি ব্যাকস্ল্যাশ অব্যাহতি, তাই আপনি পেতে প্রয়োজন '\\1'। এটি তখন (কার্যকরভাবে) চালায়eval ফলাফলটি স্ট্রিংটি চালানোর জন্য দৌড়ে যায় যদিও এটি পিএইচপি কোড ছিল (যার কারণে এটি অবচয় করা হচ্ছে, কারণ এটি 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), পিএইচপি কোনো কলব্যাক মত , যেমন

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, পিএইচপি ম্যানুয়ালটিতে আলোচিত হিসাবে আপনি কীওয়ার্ডটি আপনার অ্যাক্সেসের প্রয়োজন ভেরিয়েবলগুলি আমদানি করতে ব্যবহার করতে পারেন । যেমন পুরানো যুক্তি যদি ছিল

'do_stuff(\\1, $foo)'

তারপরে নতুন কলব্যাকটি দেখতে ভাল লাগবে

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

গটছস

  • ব্যবহারের preg_replace_callbackহয় পরিবর্তে/e যার ফলে আপনি আপনার "প্যাটার্ন" যুক্তি থেকে পতাকা সরানোর প্রয়োজন, Regex উপর পরিবর্তক। সুতরাং একটি প্যাটার্ন /blah(.*)blah/meiহয়ে যাবে /blah(.*)blah/mi
  • /eপরিবর্তক একটি বৈকল্পিক ব্যবহৃত addslashes()আর্গুমেন্ট উপর অভ্যন্তরীণভাবে, তাই ততক্ষণ প্রতিস্থাপন ব্যবহৃত stripslashes()এটা মুছে ফেলার জন্য; বেশিরভাগ ক্ষেত্রে, আপনি সম্ভবত stripslashesআপনার নতুন কলব্যাক থেকে কলটি সরাতে চান ।

1

প্রাক সমর্থন সঙ্গে shim

এটি খুব অবাঞ্ছিত। তবে আপনি যদি প্রোগ্রামার না হয়ে থাকেন বা সত্যই ভয়ঙ্কর কোডটি পছন্দ করেন তবে আপনি 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
  • এবং লাইসেন্স মন্তব্যটি কেবলমাত্র এটিকে অতিরিক্ত ব্যবহার করা বা ছড়িয়ে দেওয়া থেকে বিরত রাখতে to

প্রতিস্থাপন কোড জেনারেটর

এখন এটি কিছুটা অপ্রয়োজনীয়। তবে সেই ব্যবহারকারীদের যারা তাদের কোডটিতে ম্যানুয়ালি পুনর্গঠন করে এখনও অভিভূত হয়েছেন তাদের সহায়তা করতে পারে preg_replace_callback। যদিও এটি কার্যকরভাবে বেশি সময় সাশ্রয়ী, একটি কোড জেনারেটরের /eপ্রতিস্থাপনের স্ট্রিংটিকে একটি এক্সপ্রেশন হিসাবে প্রসারিত করতে কম সমস্যা হয় । এটি একটি অত্যন্ত অবিস্মরণীয় রূপান্তর, তবে সম্ভবত সবচেয়ে প্রচলিত উদাহরণগুলির পক্ষে যথেষ্ট suff

এই ফাংশনটি ব্যবহার করতে, কোনও ভাঙা 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
  • যদিও অস্থায়ী ভেরিয়েবলগুলি বা মাল্টলাইন কোড ব্লক কাঠামো রাখা ভাল।

এবং প্রতিস্থাপনের অভিব্যক্তি আরও পাঠযোগ্যতার উন্নতি বা পুনরায় কাজের দাবি করতে পারে demand

  • উদাহরণস্বরূপ stripslashes()আক্ষরিক ভাবের মধ্যে প্রায়ই নিরর্থক হয়ে ওঠে।
  • পরিবর্তনশীল-স্কোপ লুকের জন্য কলব্যাকের মধ্যে / এর জন্য একটি useবা globalরেফারেন্স প্রয়োজন ।
  • অসমতে উদ্ধৃত-আবদ্ধ "-$1-$2"ক্যাপচার রেফারেন্সগুলি প্লেইন ট্রান্সফর্মেশনের মাধ্যমে সিন্টেক্সিকভাবে ভেঙে যাবে "-$m[1]-$m[2]

কোড আউটপুটটি কেবল একটি সূচনা পয়েন্ট is এবং হ্যাঁ, এটি অনলাইন সরঞ্জাম হিসাবে আরও কার্যকর হত। এই কোড রাইটারিং এপ্রোচ (সম্পাদনা, রান, সম্পাদনা, সম্পাদনা) কিছুটা অবৈধ। তবুও যারা টাস্ককেন্দ্রিক কোডিং (আরও পদক্ষেপ, আরও উদ্ঘাটন) এর অভ্যস্ত তাদের কাছে আরও সহজলভ্য হতে পারে। সুতরাং এই বিকল্পটি আরও কয়েকটি সদৃশ প্রশ্ন রোধ করতে পারে।


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.