Str_replace का उपयोग करना ताकि यह केवल पहले मैच पर कार्य करे?


325

मैं चाहता हूँ के एक संस्करण str_replace()है कि केवल की पहली आवृत्ति को बदल देता है $searchमें $subject। क्या इसका कोई आसान समाधान है, या क्या मुझे हैकी समाधान की आवश्यकता है?


जैसा कि इस स्वसंपूर्ण पुस्तकालय में पाया गया है, आप इसे उपयोगी s($subject)->replaceFirst($search)और s($subject)->replaceFirstIgnoreCase($search)उपयोगी मान सकते हैं
जौ

जवाबों:


346

Preg_replace के साथ किया जा सकता है :

function str_replace_first($from, $to, $content)
{
    $from = '/'.preg_quote($from, '/').'/';

    return preg_replace($from, $to, $content, 1);
}

echo str_replace_first('abc', '123', 'abcdef abcdef abcdef'); 
// outputs '123def abcdef abcdef'

मैजिक वैकल्पिक चौथे पैरामीटर [सीमा] में है। प्रलेखन से:

[सीमा] - प्रत्येक विषय स्ट्रिंग में प्रत्येक पैटर्न के लिए अधिकतम संभव प्रतिस्थापन। -1 की कमी (कोई सीमा नहीं)।


हालांकि, एक अधिक कुशल विधि (मोटे तौर पर 3-4x तेज) के लिए ज़ोम्बैट का जवाब देखें ।


39
इस पद्धति का नकारात्मक पहलू नियमित अभिव्यक्तियों का प्रदर्शन दंड है।
ज़ोम्बैट

27
एक और नकारात्मक पहलू यह है कि आपको "सुई" पर प्रीग_क्वोट () का उपयोग करना होगा और प्रतिस्थापन में मेटा-वर्ण $ और \ से बचना होगा।
जोश डेविस

32
यह भागने के मुद्दों के कारण एक सामान्य समाधान के रूप में विफल रहता है।
जेरेमी कॉफ़मैन

2
'प्रदर्शन' के कारण बहुत बार नियमित अभिव्यक्तियों को खारिज कर दिया जाता है, अगर प्रदर्शन प्राथमिक चिंता का विषय था, तो हम PHP नहीं लिखेंगे! पैटर्न को लपेटने के लिए '/' के अलावा कुछ का उपयोग किया जा सकता है, शायद '~', जो कुछ हद तक भागने की समस्या से बचने में मदद करेगा। यह निर्भर करता है कि डेटा क्या है, और यह कहां से आया है।
थॉमसरेडस्टोन

1
प्रदर्शन एक तरफ हट जाता है - क्या जो लोग भागने के मुद्दों के बारे में शिकायत करते हैं, उनके पास संभावित बगों के अलावा मन में कुछ भी विशिष्ट है preg_quote? उदाहरण के लिए, @ThomasRedstone चिंता करता है कि /यदि यह दिखाई देता है तो सीमांकक खतरनाक हो सकता है $from, लेकिन सौभाग्य से ऐसा नहीं है: यह ठीक से बच गया है क्योंकि preg_quoteदूसरा पैरामीटर (कोई भी आसानी से परीक्षण कर सकता है)। मैं विशिष्ट मुद्दों (जो मेरी किताब में गंभीर पीसीआरई सुरक्षा कीड़े होंगे) के बारे में सुनना चाहूंगा।
MvanGeest

610

इसका कोई संस्करण नहीं है, लेकिन समाधान बिल्कुल भी हैक नहीं है।

$pos = strpos($haystack, $needle);
if ($pos !== false) {
    $newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
}

बहुत आसान है, और नियमित अभिव्यक्ति के प्रदर्शन दंड बचाता है।


बोनस: यदि आप अंतिम घटना को बदलना चाहते हैं , तो इसके strrposस्थान पर उपयोग करें strpos


17
बहुत तेज हो सकता है और नियमित अभिव्यक्ति की तुलना में कम मेमोरी का उपयोग करेगा। पता नहीं क्यों कोई उसे वोट देगा ...
जोश डेविस

12
मुझे यह दृष्टिकोण पसंद है, लेकिन कोड में एक त्रुटि है, root_replace कॉल का अंतिम पैरामीटर strlen ($ सुई) की जगह strlen ($ प्रतिस्थापित) होना चाहिए .. कृपया इसके बारे में सावधान रहें !!
नेल्सन

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

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

1
शानदार दृष्टिकोण। चर मानों को बदलने के लिए पूरी तरह से काम करता है, जो उनमें regex वर्णों को आरक्षित करता है (इसलिए preg_replace भालू है)। यह सीधा और सुरुचिपूर्ण है।
प्रागसुस

96

संपादित करें: दोनों उत्तर अपडेट कर दिए गए हैं और अब सही हैं। मैं जवाब छोड़ दूंगा क्योंकि फंक्शन टाइमिंग अभी भी उपयोगी है।

'ज़ोम्बैट' और 'बहुत ज़्यादा php' के जवाब दुर्भाग्य से सही नहीं हैं। यह उत्तर ज़ोम्बैट के लिए एक संशोधन है (जैसा कि मेरे पास टिप्पणी पोस्ट करने के लिए पर्याप्त प्रतिष्ठा नहीं है):

$pos = strpos($haystack,$needle);
if ($pos !== false) {
    $newstring = substr_replace($haystack,$replace,$pos,strlen($needle));
}

स्ट्रलेन ($ बदलें) के बजाय स्ट्रलेन ($ सुई) पर ध्यान दें। ज़ोम्बैट का उदाहरण केवल सही ढंग से काम करेगा यदि सुई और प्रतिस्थापित समान लंबाई हैं।

यहाँ PHP के अपने str_replace के समान हस्ताक्षर वाले फ़ंक्शन में समान कार्यक्षमता है:

function str_replace_first($search, $replace, $subject) {
    $pos = strpos($subject, $search);
    if ($pos !== false) {
        return substr_replace($subject, $replace, $pos, strlen($search));
    }
    return $subject;
}

यह 'बहुत ज्यादा php' का संशोधित उत्तर है:

implode($replace, explode($search, $subject, 2));

1. के बजाय अंत में 2 नोट करें या फ़ंक्शन प्रारूप में:

function str_replace_first($search, $replace, $subject) {
    return implode($replace, explode($search, $subject, 2));
}

मैंने दो कार्यों को समय पर किया और पहला मैच दो बार तेज है जब कोई मैच नहीं मिला। एक मैच मिलने पर वे समान गति वाले होते हैं।


ऐसा क्यों नहीं किया जाता है: str_replace_flexible (मिश्रित $ s, मिश्रित $ r, int $ ऑफसेट, int $ limit) जहां फ़ंक्शन $ ऑफसेट (nth) मैच से शुरू होने वाली $ सीमा घटनाओं को प्रतिस्थापित करता है।
एडम फ्रीडमैन

बहुत बुरा यह केवल केस-संवेदी प्रतिस्थापन के लिए लागू होता है।
andreszs

4
@ stripos()बचाव के लिए भेजा :-)
ग्रास डबल

76

मुझे आश्चर्य हुआ कि कौन सा सबसे तेज था, इसलिए मैंने उन सभी का परीक्षण किया।

नीचे आप पाएंगे:

  • इस पृष्ठ पर योगदान किए गए सभी कार्यों की एक व्यापक सूची
  • प्रत्येक अंतर्विरोध के लिए बेंचमार्क परीक्षण (10,000 से अधिक औसत निष्पादन समय)
  • प्रत्येक उत्तर के लिंक (पूर्ण कोड के लिए)

सभी कार्यों को एक ही सेटिंग के साथ परीक्षण किया गया था:

$string = 'OOO.OOO.OOO.S';
$search = 'OOO'; 
$replace = 'B';

ऐसे कार्य जो स्ट्रिंग के भीतर एक स्ट्रिंग की पहली घटना को प्रतिस्थापित करते हैं :


एक स्ट्रिंग के भीतर केवल एक स्ट्रिंग की अंतिम घटना को प्रतिस्थापित करने वाले कार्य :


इसके लिए धन्यवाद, मैं आम तौर पर preg_replace का उपयोग करता हूं क्योंकि यह सबसे लचीला है यदि भविष्य के ट्वीक की आवश्यकता होती है ज्यादातर मामलों में 27% धीमी महत्वपूर्ण नहीं है
zzapper

@oLinkWebDevelopment मुझे आपकी बेंचमार्क स्क्रिप्ट देखने में दिलचस्पी होगी। मुझे लगता है कि यह उपयोगी साबित हो सकता है।
डेव मॉर्टन

substr_replace()परिणाम जीतने का कारण सरल है; क्योंकि यह एक आंतरिक कार्य है। आंतरिक और उपयोगकर्ता-परिभाषित कार्य करने वाले दो कार्य समान हैं, क्योंकि आंतरिक एक निचली परतों में चलता है। तो, क्यों नहीं preg_match()? नियमित अभिव्यक्ति हर आंतरिक स्ट्रिंग हेरफेर फ़ंक्शन की तुलना में लगभग धीमी होती है, क्योंकि कई बार स्ट्रिंग में खोज करने के उनके राष्ट्र के कारण।
मेकितगढ़ा

1
मुझे उम्मीद है कि आपके "विजेता" ( substr_replace($string, $replace, 0, strlen($search));) पर बेंचमार्क ने केवल उस स्थिर को नहीं लिखा 0। गैर-रेगेक्स समाधानों के दृढ़ विश्वास का हिस्सा यह है कि उन्हें यह जानने के लिए शुरुआती बिंदु को "खोजने" की आवश्यकता है कि कहां बदलना है।
मिकमैकुसा

55

दुर्भाग्य से, मुझे किसी भी PHP फ़ंक्शन का पता नहीं है जो ऐसा कर सकता है।
आप इस तरह से आसानी से अपना रोल कर सकते हैं:

function replace_first($find, $replace, $subject) {
    // stolen from the comments at PHP.net/str_replace
    // Splits $subject into an array of 2 items by $find,
    // and then joins the array with $replace
    return implode($replace, explode($find, $subject, 2));
}

मुझे लगता है कि यह उन सभी का सबसे गोल्फ संस्करण है - joinइसके बजाय का उपयोग करना implode
टाइटस

return implode($replace, explode($find, $subject, $limit+1));कस्टम रिप्लेस नंबरों के लिए
beppe9000

7

मैंने इस छोटे से फंक्शन को बनाया , जो रीगेक्सपी की आवश्यकता के बिना, स्ट्रिंग को (केस-संवेदी) सीमा के साथ बदल देता है। यह बढ़िया काम करता है।

function str_replace_limit($search, $replace, $string, $limit = 1) {
    $pos = strpos($string, $search);

    if ($pos === false) {
        return $string;
    }

    $searchLen = strlen($search);

    for ($i = 0; $i < $limit; $i++) {
        $string = substr_replace($string, $replace, $pos, $searchLen);

        $pos = strpos($string, $search);

        if ($pos === false) {
            break;
        }
    }

    return $string;
}

उदाहरण का उपयोग:

$search  = 'foo';
$replace = 'bar';
$string  = 'foo wizard makes foo brew for evil foo and jack';
$limit   = 2;

$replaced = str_replace_limit($search, $replace, $string, $limit);

echo $replaced;
// bar wizard makes bar brew for evil foo and jack

हालांकि मैं इसके बजाय अधिक स्पष्ट होने ===falseके is_bool(लिए करूँगा - मैं इस अंगूठे को सिर्फ इसलिए दे रहा हूं क्योंकि इसने RegExp पागलपन से बचा लिया है ! ... और एक ही समय में यह काम कर रहा है और स्वच्छ समाधान ...
jave.web

आसानी से अनुकूलन योग्य preg_समाधान का उल्लेख करना पागलपन नहीं बल्कि व्यक्तिगत प्राथमिकता है। return preg_replace('/'.preg_quote($search, '/').'/', $replace, $content, 1);उन लोगों के लिए पढ़ना बहुत आसान है जो रेगेक्स से नहीं डरते। केस-असंवेदनशील खोज की आवश्यकता है? iअंत पैटर्न सीमांकक के बाद जोड़ें । यूनिकोड / मल्टीबाइट समर्थन की आवश्यकता है? uअंत पैटर्न सीमांकक के बाद जोड़ें । शब्द सीमा समर्थन की आवश्यकता है? \bअपनी खोज स्ट्रिंग के दोनों किनारों पर जोड़ें । यदि आप रेगेक्स नहीं चाहते हैं, तो रेगेक्स का उपयोग न करें। पाठ्यक्रमों के लिए घोड़े, लेकिन निश्चित रूप से पागलपन नहीं।
मिकमैकुसा

3

सबसे आसान तरीका नियमित अभिव्यक्ति का उपयोग करना होगा।

दूसरा तरीका स्ट्रैप के साथ स्ट्रिंग की स्थिति का पता लगाना है () और फिर एक root_replace ()

लेकिन मैं वास्तव में RegExp के लिए जाना होगा।


यह "संकेत" इस पृष्ठ पर अन्य पदों की तुलना में अस्पष्ट / कम-मूल्य है।
मिकमैकुसा

3
function str_replace_once($search, $replace, $subject) {
    $pos = strpos($subject, $search);
    if ($pos === false) {
        return $subject;
    }

    return substr($subject, 0, $pos) . $replace . substr($subject, $pos + strlen($search));
}

कोड-ओनली उत्तर स्टैकऑवरफ्लो पर कम-मूल्य हैं क्योंकि वे हजारों भविष्य के शोधकर्ताओं को शिक्षित / सशक्त बनाने का एक खराब काम करते हैं।
मिकमैकुसा

3

=> कोड की समीक्षा की गई, इसलिए कुछ टिप्पणियों को बहुत पुराना मानें

और उस सुधार के लिए मेरी मदद करने पर सभी को धन्यवाद

कोई बग, कृपया मुझे सूचित करें; मैं इसे ठीक कर दूँगा

तो, के लिए जाने देता है:

उदाहरण के लिए पहले 'o' को 'ea' में बदलना :

$s='I love you';
$s=str_replace_first('o','ea',$s);
echo $s;

//output: I leave you

कार्यक्रम:

function str_replace_first($a,$b,$s)
         {
         $w=strpos($s,$a);
         if($w===false)return $s;
         return substr($s,0,$w).$b.substr($s,$w+strlen($a));
         }

विफल रहता है अगर $ यह बार-बार आगा बनाम आसा
क्रिस्टो

मुझे लगता है कि होना चाहिए substr($where,$b+strlen($this)), नहीं substr($where,$b+1)। और मुझे लगता है कि substr_replaceयह तेज है।
टाइटस

कोड संशोधित किया गया था, अब यह लंबे तार के लिए भी काम करता है
PYK

यह समाधान कोडित के रूप में काम नहीं करता है। प्रमाण: 3v4l.org/cMeZj और जब आप चर नामकरण समस्या को ठीक करते हैं, तो यह तब काम नहीं करता है जब खोज मूल्य नहीं मिलता है - यह इनपुट स्ट्रिंग को नुकसान पहुंचाता है। प्रमाण: 3v4l.org/XHtfc
mickmackusa

क्या यह उचित है कि कोई व्यक्ति FIX कोड पूछता है? @mickmackusa आप जाँच कर सकते हैं कि कृपया फिर से?
PYK

2
$string = 'this is my world, not my world';
$find = 'world';
$replace = 'farm';
$result = preg_replace("/$find/",$replace,$string,1);
echo $result;

यह पहले उत्तर के समान ही है। इसके अलावा, आपको इसे अभिव्यक्ति के रूप में उपयोग करने preg_quoteसे $findपहले करना चाहिए ।
एमिल विक्रोत्तम

यह वही है जो मैंने इस्तेमाल किया, इसलिए मैंने इसे वोट दिया। पहला उत्तर ड्रुपल के साथ संघर्ष का कारण बना, इसने एक ड्रुपल हेल्पर फ़ंक्शन को अधिलेखित कर दिया होगा। इसलिए मैंने सिर्फ उस कोड को लिया जो फ़ंक्शन के अंदर था और इसे बाकी कोड के साथ इन-लाइन इस्तेमाल किया ...
Dan Mantyla

यह कोड-केवल उत्तर पृष्ठ पर निरर्थक सलाह प्रदान करता है (यह उल्लेख नहीं है कि यह कमी है preg_quote()। इस देर से नकली उत्तर को पृष्ठ से सुरक्षित रूप से शुद्ध किया जा सकता है क्योंकि इसकी सलाह पहले से प्रदान की गई है, और उच्चतर स्वीकृत स्वीकार किए जाते हैं।
मिकमैक्स

2

@ रेनोकोर के उत्तर पर विस्तार करने के लिए , मैंने एक फ़ंक्शन लिखा है जो 100% पिछड़े-संगत है str_replace()। यही कारण है कि आप की जगह ले सकता है, सभी की घटनाओं str_replace()के साथ str_replace_limit()के लिए यहां तक कि उन सरणियों का उपयोग कर कुछ भी खिलवाड़ के बिना, $search, $replace, और / या $subject

यदि आप फ़ंक्शन कॉल को बदलना चाहते हैं, तो फ़ंक्शन पूरी तरह से स्व-निहित हो सकता है ($string===strval(intval(strval($string)))), लेकिन मैं इसके खिलाफ सिफारिश करूंगा valid_integer()क्योंकि स्ट्रिंग्स के रूप में प्रदान किए गए पूर्णांकों के साथ काम करते समय यह एक उपयोगी फ़ंक्शन है।

नोट: जब भी संभव हो, इसके बजाय str_replace_limit()का उपयोग करेगा str_replace(), इसलिए सभी कॉल को एक हिट प्रदर्शन के बारे में चिंता किए बिना str_replace()बदला जा सकता है str_replace_limit()

प्रयोग

<?php
$search = 'a';
$replace = 'b';
$subject = 'abcabc';
$limit = -1; // No limit
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit);
echo $count.' replacements -- '.$new_string;

2 प्रतिस्थापन - bbcbbc

$limit = 1; // Limit of 1
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit);
echo $count.' replacements -- '.$new_string;

1 प्रतिस्थापन - bbcabc

$limit = 10; // Limit of 10
$new_string = str_replace_limit($search, $replace, $subject, $count, $limit);
echo $count.' replacements -- '.$new_string;

2 प्रतिस्थापन - bbcbbc

समारोह

<?php

/**
 * Checks if $string is a valid integer. Integers provided as strings (e.g. '2' vs 2)
 * are also supported.
 * @param mixed $string
 * @return bool Returns boolean TRUE if string is a valid integer, or FALSE if it is not 
 */
function valid_integer($string){
    // 1. Cast as string (in case integer is provided)
    // 1. Convert the string to an integer and back to a string
    // 2. Check if identical (note: 'identical', NOT just 'equal')
    // Note: TRUE, FALSE, and NULL $string values all return FALSE
    $string = strval($string);
    return ($string===strval(intval($string)));
}

/**
 * Replace $limit occurences of the search string with the replacement string
 * @param mixed $search The value being searched for, otherwise known as the needle. An
 * array may be used to designate multiple needles.
 * @param mixed $replace The replacement value that replaces found search values. An
 * array may be used to designate multiple replacements.
 * @param mixed $subject The string or array being searched and replaced on, otherwise
 * known as the haystack. If subject is an array, then the search and replace is
 * performed with every entry of subject, and the return value is an array as well. 
 * @param string $count If passed, this will be set to the number of replacements
 * performed.
 * @param int $limit The maximum possible replacements for each pattern in each subject
 * string. Defaults to -1 (no limit).
 * @return string This function returns a string with the replaced values.
 */
function str_replace_limit(
        $search,
        $replace,
        $subject,
        &$count,
        $limit = -1
    ){

    // Set some defaults
    $count = 0;

    // Invalid $limit provided. Throw a warning.
    if(!valid_integer($limit)){
        $backtrace = debug_backtrace();
        trigger_error('Invalid $limit `'.$limit.'` provided to '.__function__.'() in '.
                '`'.$backtrace[0]['file'].'` on line '.$backtrace[0]['line'].'. Expecting an '.
                'integer', E_USER_WARNING);
        return $subject;
    }

    // Invalid $limit provided. Throw a warning.
    if($limit<-1){
        $backtrace = debug_backtrace();
        trigger_error('Invalid $limit `'.$limit.'` provided to '.__function__.'() in '.
                '`'.$backtrace[0]['file'].'` on line '.$backtrace[0]['line'].'. Expecting -1 or '.
                'a positive integer', E_USER_WARNING);
        return $subject;
    }

    // No replacements necessary. Throw a notice as this was most likely not the intended
    // use. And, if it was (e.g. part of a loop, setting $limit dynamically), it can be
    // worked around by simply checking to see if $limit===0, and if it does, skip the
    // function call (and set $count to 0, if applicable).
    if($limit===0){
        $backtrace = debug_backtrace();
        trigger_error('Invalid $limit `'.$limit.'` provided to '.__function__.'() in '.
                '`'.$backtrace[0]['file'].'` on line '.$backtrace[0]['line'].'. Expecting -1 or '.
                'a positive integer', E_USER_NOTICE);
        return $subject;
    }

    // Use str_replace() whenever possible (for performance reasons)
    if($limit===-1){
        return str_replace($search, $replace, $subject, $count);
    }

    if(is_array($subject)){

        // Loop through $subject values and call this function for each one.
        foreach($subject as $key => $this_subject){

            // Skip values that are arrays (to match str_replace()).
            if(!is_array($this_subject)){

                // Call this function again for
                $this_function = __FUNCTION__;
                $subject[$key] = $this_function(
                        $search,
                        $replace,
                        $this_subject,
                        $this_count,
                        $limit
                );

                // Adjust $count
                $count += $this_count;

                // Adjust $limit, if not -1
                if($limit!=-1){
                    $limit -= $this_count;
                }

                // Reached $limit, return $subject
                if($limit===0){
                    return $subject;
                }

            }

        }

        return $subject;

    } elseif(is_array($search)){
        // Only treat $replace as an array if $search is also an array (to match str_replace())

        // Clear keys of $search (to match str_replace()).
        $search = array_values($search);

        // Clear keys of $replace, if applicable (to match str_replace()).
        if(is_array($replace)){
            $replace = array_values($replace);
        }

        // Loop through $search array.
        foreach($search as $key => $this_search){

            // Don't support multi-dimensional arrays (to match str_replace()).
            $this_search = strval($this_search);

            // If $replace is an array, use the value of $replace[$key] as the replacement. If
            // $replace[$key] doesn't exist, just an empty string (to match str_replace()).
            if(is_array($replace)){
                if(array_key_exists($key, $replace)){
                    $this_replace = strval($replace[$key]);
                } else {
                    $this_replace = '';
                }
            } else {
                $this_replace = strval($replace);
            }

            // Call this function again for
            $this_function = __FUNCTION__;
            $subject = $this_function(
                    $this_search,
                    $this_replace,
                    $subject,
                    $this_count,
                    $limit
            );

            // Adjust $count
            $count += $this_count;

            // Adjust $limit, if not -1
            if($limit!=-1){
                $limit -= $this_count;
            }

            // Reached $limit, return $subject
            if($limit===0){
                return $subject;
            }

        }

        return $subject;

    } else {
        $search = strval($search);
        $replace = strval($replace);

        // Get position of first $search
        $pos = strpos($subject, $search);

        // Return $subject if $search cannot be found
        if($pos===false){
            return $subject;
        }

        // Get length of $search, to make proper replacement later on
        $search_len = strlen($search);

        // Loop until $search can no longer be found, or $limit is reached
        for($i=0;(($i<$limit)||($limit===-1));$i++){

            // Replace 
            $subject = substr_replace($subject, $replace, $pos, $search_len);

            // Increase $count
            $count++;

            // Get location of next $search
            $pos = strpos($subject, $search);

            // Break out of loop if $needle
            if($pos===false){
                break;
            }

        }

        // Return new $subject
        return $subject;

    }

}

4
अगर तुम मुझसे पूछते हो तो थोड़े फूला हुआ इस समाधान में मुझे सबसे ज्यादा 'नफ़रत' भी है, जो त्रुटि से निपटने की है। यदि आप गलत मान पास करते हैं तो यह स्क्रिप्ट को तोड़ देता है। आपको लगता है कि यह पेशेवर लग रहा है, लेकिन ऐसा नहीं है, एक त्रुटि के बजाय एक नोटिस या चेतावनी का उत्पादन करता है। बेहतर है कि बुलशिट को छोड़ें, इसके बजाय झूठा लौटें या शून्य करें और इस तरह के फ़ंक्शन में कभी भी बैकट्रेस का उपयोग न करें। सबसे अच्छा समाधान यह है कि प्रोग्रामर तय कर सकता है कि आउटपुट गलत / अप्रत्याशित होने पर क्या करना है।
कोडबीट

इस का उपयोग करता है @Erwinus E_USER_WARNINGभर है, जो एक है चेतावनी , नहीं एक त्रुटि । बैकट्रेस यह पता लगाने के लिए बेहद उपयोगी है कि पहली जगह में फ़ंक्शन के लिए अमान्य डेटा किस कोड से गुजर रहा है (जो उत्पादन में बग को ट्रैक करने के लिए बिल्कुल आवश्यक है)। के $subjectबजाय लौटने के बजाय false/ nullया एक त्रुटि को फेंकने के लिए, यह बस मेरे उपयोग के मामले के लिए एक व्यक्तिगत विकल्प था। मैच के लिए str_replace()की कार्यक्षमता, catchable घातक त्रुटियों का उपयोग कर सबसे अच्छा शर्त होगी (के रूप में str_replace()जब पहली दो तर्क के लिए एक बंद प्रदान करता है)।
0b10011

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

@Erwinus जब मैं टिप्पणियों में आया था तो मैं क्रियाशील था क्योंकि कुछ लोग भाषा के साथ-साथ दूसरों को भी नहीं समझते हैं, और टिप्पणियों को हमेशा उन लोगों द्वारा हटाया जा सकता है जो इसे समझते हैं। यदि आप सभी किनारे के मामलों के लिए एक ही अंतिम परिणाम प्राप्त करने का एक बेहतर तरीका जानते हैं, तो हर तरह से, उत्तर को संपादित करें। और यदि आपका उत्पादन वातावरण त्रुटि संदेशों को दबाता नहीं है, तो आपको इस फ़ंक्शन से एक बड़ा मुद्दा मिल गया है;)
0b10011

टीएल; डीआर यह स्निपेट इतना फूला हुआ है कि मैं इसे रेगेक्स फंक्शन (आई हेट स्क्रॉलिंग) पर चुनने की कल्पना नहीं कर सकता। यदि आप किए गए प्रतिस्थापन को गिनना चाहते हैं, तो इसके लिए एक पैरामीटर है preg_replace()। इसके अलावा, preg_replace()/ regex शब्द सीमा हैंडलिंग (यदि वांछनीय है) प्रदान करता है - ऐसा कुछ जो गैर-रेगेक्स फ़ंक्शन सुरुचिपूर्ण ढंग से प्रदान नहीं करेगा।
मिकमैकुसा

2

अपने परीक्षा परिणाम के अनुसार, मैं karim79 द्वारा उपलब्ध कराए गए regular_express को वोट देना चाहूंगा। (मेरे पास अब इसे वोट करने के लिए पर्याप्त प्रतिष्ठा नहीं है!)

ज़ोम्बैट से समाधान कई फ़ंक्शन कॉल का उपयोग करता है, मैं कोड को भी सरल करता हूं। मैं PHP 5.4 का उपयोग 100,000 बार दोनों समाधानों को चलाने के लिए कर रहा हूँ, और यहाँ परिणाम है:

$str = 'Hello abc, have a nice day abc! abc!';
$pos = strpos($str, 'abc');
$str = substr_replace($str, '123', $pos, 3);

==> 1.85 सेकंड

$str = 'Hello abc, have a nice day abc! abc!';
$str = preg_replace('/abc/', '123', $str, 1);

==> 1.35 सेकंड

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


आपका पहला स्निपेट एक अनुचित तुलना है क्योंकि यह एक सही कार्यान्वयन का उपयोग करने में विफल रहता है। आप के $posलिए जाँच नहीं कर रहे हैं false, इसलिए जब सुई अस्तित्व में नहीं है, यह उत्पादन को नुकसान होगा।
मिकमैकुसा

धन्यवाद @ मिकमैकुसा, आप सही कह रहे हैं। लेकिन वह बात नहीं है। मैंने कहा कि इस कोड को कार्यान्वयन की दक्षता की तुलना करने के लिए सरल बनाया गया है।
हंटर वू

बिलकुल मेरी बात। आपको कभी भी बेंचमार्क तुलना नहीं करनी चाहिए जो ठीक उसी प्रक्रिया को नहीं करती है। सेब की तुलना आधे-संतरे से करना उपयोगी नहीं है। पूरी तरह से पूर्ण गैर-रेगेक्स दृष्टिकोण को लागू करने से गति का अंतर अधिक गहरा हो जाएगा।
मिकमैकुसा

खैर, फिर से धन्यवाद। लेकिन जो मैं चाहता हूं वह बेहतर कार्यान्वयन ढूंढना है, न कि अधिक अंतर बनाने के लिए।
हंटर वू

2

ज़ोम्बैट के उत्तर पर विस्तार करने के लिए (जिसे मैं सबसे अच्छा उत्तर मानता हूं), मैंने उनके फ़ंक्शन का एक पुनरावर्ती संस्करण तैयार किया जो $limitयह निर्दिष्ट करने के लिए एक पैरामीटर में होता है कि आप कितनी जगह बदलना चाहते हैं।

function str_replace_limit($haystack, $needle, $replace, $limit, $start_pos = 0) {
    if ($limit <= 0) {
        return $haystack;
    } else {
        $pos = strpos($haystack,$needle,$start_pos);
        if ($pos !== false) {
            $newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
            return str_replace_limit($newstring, $needle, $replace, $limit-1, $pos+strlen($replace));
        } else {
            return $haystack;
        }
    }
}

ध्यान दें, कोई गुणवत्ता जांच नहीं है $start_pos, इसलिए यदि यह स्ट्रिंग की लंबाई से परे है, तो यह फ़ंक्शन उत्पन्न करेगा Warning: strpos(): Offset not contained in string...:। $start_posलंबाई से परे होने पर यह फ़ंक्शन प्रतिस्थापन करने में विफल रहता है । असफलता का प्रमाण: 3v4l.org/qGuVIR ... आपका फ़ंक्शन return $haystackशर्तों को संयोजित कर सकता है और इस तरह के एकल-उपयोग चर घोषित करने से बच सकता है: 3v4l.org/Kdmqp हालाँकि, जैसा कि मैंने इस पृष्ठ पर अन्य टिप्पणियों में कहा है, मैं चाहूँगा एक बहुत साफ, प्रत्यक्ष, गैर-पुनरावर्ती preg_replace()कॉल का उपयोग करें।
मिकमैकुसा

हाँ तो आप इस लाइन में जोड़ सकते हैं कि elseबयान$start_pos > strlen($haystack) ? $start_pos = strlen($haystack) : '';
Manojkiran.A

2

एक तार के लिए

$string = 'OOO.OOO.OOO.S';
$search = 'OOO';
$replace = 'B';

//replace ONLY FIRST occurance of "OOO" with "B"
    $string = substr_replace($string,$replace,0,strlen($search));
    //$string => B.OOO.OOO.S

//replace ONLY LAST occurance of "OOOO" with "B"
    $string = substr_replace($string,$replace,strrpos($string,$search),strlen($search)) 
    //$string => OOO.OOO.B.S

    //replace ONLY LAST occurance of "OOOO" with "B"
    $string = strrev(implode(strrev($replace),explode(strrev($search),strrev($string),2)))
    //$string => OOO.OOO.B.S

एकल चरित्र के लिए

$string[strpos($string,$search)] = $replace;


//EXAMPLE

$string = 'O.O.O.O.S';
$search = 'O';
$replace = 'B';

//replace ONLY FIRST occurance of "O" with "B" 
    $string[strpos($string,$search)] = $replace;  
    //$string => B.O.O.O.S

//replace ONLY LAST occurance of "O" with "B" 
    $string[strrpos($string,$search)] = $replace; 
    // $string => B.O.O.B.S

पहली स्ट्रिंग_ इनपुट () स्निपेट तब विफल हो जाती है जब खोज स्ट्रिंग इनपुट स्ट्रिंग के ऑफसेट 0 पर नहीं होती है। विफलता का प्रमाण: 3v4l.org/oIbRv और दोनों substr_replace()तकनीक इनपुट स्ट्रिंग को नुकसान पहुंचाती हैं जब खोज मूल्य मौजूद नहीं होता है। विफलता का प्रमाण: 3v4l.org/HmEml (और आख़िरी तकनीक के साथ आख़िरी तकनीक revको गंभीरता से आंखों पर
चढ़ा हुआ

2

लोगों ने जो कहा, उसे लागू करते हुए याद रखें कि संपूर्ण स्ट्रिंग एक सरणी है:

$string = "Lorem ipsum lá lá lá";

$string[0] = "B";

echo $string;

"बोरम इप्सम ला ला ला"


3
जब तक इसमें मल्टीबाइट कैरेक्टर नहीं होते ... और तब आपकी तकनीक विफल हो जाती है। कितना दुर्भाग्यपूर्ण है कि आपने एक नमूना इनपुट स्ट्रिंग की पेशकश कीáविफलता का प्रदर्शन
mickmackusa

आप सत्यापित कर सकते हैं यदि आपका string मल्टीबाइट स्ट्रिंग का उपयोगmb_strlen($subject) != strlen($subject)
रूसोलेक्सैंड्रे

यह पोस्ट पूछे जा रहे प्रश्न का उत्तर देने का प्रयास नहीं करता है।
मिकमैकुसा

2
$str = "/property/details&id=202&test=123#tab-6p";
$position = strpos($str,"&");
echo substr_replace($str,"?",$position,1);

Root_replace का उपयोग करके हम पहले वर्ण की घटना को केवल स्ट्रिंग में बदल सकते हैं। के रूप में और कई बार दोहराया जाता है, लेकिन केवल पहली स्थिति में हमें प्रतिस्थापित करना होगा?


1

यह समारोह @renocor के जवाब से काफी प्रेरित है। यह फ़ंक्शन मल्टी बाइट को सुरक्षित बनाता है।

function str_replace_limit($search, $replace, $string, $limit)
{
    $i = 0;
    $searchLength = mb_strlen($search);

    while(($pos = mb_strpos($string, $search)) !== false && $i < $limit)
    {
        $string = mb_substr_replace($string, $replace, $pos, $searchLength);
        $i += 1;
    }

    return $string;
}

function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = null)
{
    $string = (array)$string;
    $encoding = is_null($encoding) ? mb_internal_encoding() : $encoding;
    $length = is_null($length) ? mb_strlen($string) - $start : $length;

    $string = array_map(function($str) use ($replacement, $start, $length, $encoding){

        $begin = mb_substr($str, 0, $start, $encoding);
        $end = mb_substr($str, ($start + $length), mb_strlen($str), $encoding);

        return $begin . $replacement . $end;

    }, $string);

    return ( count($string) === 1 ) ? $string[0] : $string;
}

0

आप इसका उपयोग कर सकते हैं:

function str_replace_once($str_pattern, $str_replacement, $string){ 

        if (strpos($string, $str_pattern) !== false){ 
            $occurrence = strpos($string, $str_pattern); 
            return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern)); 
        } 

        return $string; 
    } 

इसका उदाहरण php.net से मिला

उपयोग:

$string = "Thiz iz an examplz";
var_dump(str_replace_once('z','Z', $string)); 

आउटपुट:

ThiZ iz an examplz

यह प्रदर्शन को थोड़ा कम कर सकता है, लेकिन सबसे आसान समाधान।


यदि वह आउटपुट है तो बिंदु क्या है? क्या यह केवल पहले लोअरकेस "z" को अपरकेस "Z" से बदलना नहीं चाहिए? इन सबकी जगह बदले? मुझे लगा कि हम यहाँ क्या बात कर रहे थे ...
कुंडा

मेरा बुरा, यह केवल पहली घटना की जगह लेगा। संपादित।
हैप्पीहार्डिक

इसी सलाह को बास ने लगभग 3 साल पहले (और बिना ज्यादा बुलाए strpos()) पेश किया था। डाउनवोट किया गया क्योंकि यह पृष्ठ पर कोई नया मान नहीं जोड़ता है।
मिकमैकुसा

0

यदि आप स्ट्रिंग में कोई मल्टीबाइट वर्ण नहीं है और यदि आप केवल एक चार को बदलना चाहते हैं तो आप बस उपयोग कर सकते हैं strpos

यहां एक फ़ंक्शन जो त्रुटियों को संभालता है

/**
 * Replace the first occurence of given string
 *
 * @param  string $search  a char to search in `$subject`
 * @param  string $replace a char to replace in `$subject`
 * @param  string $subject
 * @return string
 *
 * @throws InvalidArgumentException if `$search` or `$replace` are invalid or if `$subject` is a multibytes string
 */
function str_replace_first(string $search , string $replace , string $subject) : string {
    // check params
    if(strlen($replace) != 1 || strlen($search) != 1) {
        throw new InvalidArgumentException('$search & $replace must be char');
    }elseif(mb_strlen($subject) != strlen($subject)){
        throw new InvalidArgumentException('$subject is an multibytes string');
    }
    // search 
    $pos = strpos($subject, $search);
    if($pos === false) {
        // not found
        return $subject;
    }

    // replace
    $subject[$replace] = $subject;

    return $subject;
}

0

लूप सॉल्यूशन के लिए

<?php
echo replaceFirstMatchedChar("&", "?", "/property/details&id=202&test=123#tab-6");

function replaceFirstMatchedChar($searchChar, $replaceChar, $str)
{
    for ($i = 0; $i < strlen($str); $i++) {

        if ($str[$i] == $searchChar) {
            $str[$i] = $replaceChar;
            break;
        }
    }
    return $str;
}

-1

यहाँ एक साधारण वर्ग है जो मैंने हमारे थोड़े संशोधित str_replace () को लपेटने के लिए बनाया है फ़ंक्शन ।

हमारा php :: str_rreplace () फ़ंक्शन भी आपको एक रिवर्स, सीमित str_replace () को बाहर ले जाने की अनुमति देता है जो स्ट्रिंग के केवल अंतिम X उदाहरण (s) को बदलने की कोशिश करते समय बहुत आसान हो सकता है।

ये उदाहरण दोनों preg_replace () का उपयोग करते हैं ।

<?php
class php {

    /**
    * str_replace() from the end of a string that can also be limited e.g. replace only the last instance of '</div>' with ''
    *
    * @param string   $find
    * @param string   $replace
    * @param string   $subject
    * @param int      $replacement_limit | -1 to replace all references
    *
    * @return string
    */
    public static function str_replace($find, $replace, $subject, $replacement_limit = -1) {
        $find_pattern = str_replace('/', '\/', $find);
        return preg_replace('/' . $find_pattern . '/', $replace, $subject, $replacement_limit);
    }

    /**
    * str_replace() from the end of a string that can also be limited e.g. replace only the last instance of '</div>' with ''
    *
    * @param string   $find
    * @param string   $replace
    * @param string   $subject
    * @param int      $replacement_limit | -1 to replace all references
    *
    * @return string
    */
    public static function str_rreplace($find, $replace, $subject, $replacement_limit = -1) {
        return strrev( self::str_replace(strrev($find), strrev($replace), strrev($subject), $replacement_limit) );
    }
}

आपकी पोस्ट पहले से संतृप्त पृष्ठ पर इस मूल्य को नहीं जोड़ती है। आपका रेगेक्स समाधान कई फ्रिंज मामलों पर विफल रहता है क्योंकि आपने सुई स्ट्रिंग में पात्रों से बचने के लिए गलत उपकरण का उपयोग किया था। विफलता का प्रमाण: 3v4l.org/dTdYK 2009 से भारी उत्थान और स्वीकृत उत्तर इस तकनीक के उचित निष्पादन को दर्शाता है। आपकी दूसरी विधि पूछे गए प्रश्न का उत्तर नहीं देती है और पहले से ही oLinkWebDevelopment द्वारा प्रदान की गई थी।
मिकमैकुसा

-1
$str = "Hello there folks!"
$str_ex = explode("there, $str, 2);   //explodes $string just twice
                                      //outputs: array ("Hello ", " folks")
$str_final = implode("", $str_ex);    // glues above array together
                                      // outputs: str("Hello  folks")

एक और अतिरिक्त जगह है, लेकिन मेरे मामले में बैकगाउंड स्क्रिप्ट के लिए यह महत्वपूर्ण नहीं था।


यह तकनीक 2009 में वापस toomuchphp द्वारा प्रदान की गई थी ! मैंने पदत्याग कर दिया है क्योंकि आपका पोस्ट शोधकर्ताओं के लिए कोई नया मूल्य नहीं जोड़ता है। कृपया उत्तर पोस्ट करने से पहले सुनिश्चित करें कि आपका समाधान पृष्ठ के लिए अद्वितीय है और पृष्ठ पर मूल्य जोड़ता है।
मिकमैकुसा

-3

यह मेरा पहला उत्तर है, मैं इसे सही ढंग से करने की उम्मीद करता हूं। इस समस्या के लिए str_replace फ़ंक्शन के चौथे तर्क का उपयोग क्यों नहीं किया जाता है?

mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )

गणना: यदि पारित किया जाता है, तो यह प्रदर्शन किए गए प्रतिस्थापनों की संख्या पर सेट किया जाएगा।


संपादित करें: यह उत्तर गलत है, क्योंकि str_replace का 4th पैरामीटर एक चर है जिसे किए गए प्रतिस्थापनों की संख्या असाइन की गई है। यह preg_replace के साथ असंगत है , जिसका 4 $limitवाँ पैरामीटर और 5 वाँ पैरामीटर है &$count


चौथे तर्क str_replace () द्वारा किए गए प्रतिस्थापनों की संख्या पर सेट किए जाएंगे। यही कारण है कि जब आप पूर्णांक पास करते हैं तो आपको एक त्रुटि मिलती है, न कि एक चर।
अर्मिनरोसु '

-6

केवल पहले या पहले कुछ उदाहरणों को बदलने के लिए एक समाधान खोजना आसान है (गणना मूल्य देकर)। उदाहरण के अंतिम या अंतिम जोड़े को बदलने के लिए कई समाधान नहीं हैं।

शायद str_replace ($ खोज, $ प्रतिस्थापित, $ विषय, -3) जैसी कुछ चीज़ों को अंतिम तीन उदाहरणों को बदलना चाहिए।

वैसे भी, सिर्फ एक सुझाव।


4
जब एक उत्तर दो साल पहले स्वीकार कर लिया गया हो तो किसी प्रश्न का उत्तर क्यों दें?
mbinette

-3 भी पैरामीटर के रूप में काम नहीं करेगा, क्योंकि 4 वाँ आउटपुट आउटपुट है न कि इनपुट पैरामीटर। यह बेहतर होगा कि आप जो कोड प्रस्तावित करते हैं, उसकी बजाय कोड को पोस्ट करें जो क्रैश करता है।
घोस्ट राइटर78

हाँ, यह गलत है, फिर भी, जब मैं इसे आज़माता हूं तो मुझे एक रिक्त स्क्रीन क्रैश क्यों होता है? मैंने सामान्य error_reporting (E_ALL) किया; ini_set ("display_errors", 1); अभी भी रिक्त स्क्रीन त्रुटि।
डौग कैसिडी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.