ฉันต้องการรุ่นstr_replace()
ว่ามีเพียงแทนที่เกิดขึ้นครั้งแรกของใน$search
$subject
มีวิธีแก้ไขปัญหานี้อย่างง่ายหรือฉันต้องการโซลูชันแฮ็กหรือไม่?
ฉันต้องการรุ่นstr_replace()
ว่ามีเพียงแทนที่เกิดขึ้นครั้งแรกของใน$search
$subject
มีวิธีแก้ไขปัญหานี้อย่างง่ายหรือฉันต้องการโซลูชันแฮ็กหรือไม่?
คำตอบ:
สามารถทำได้ด้วย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 (ไม่ จำกัด )
แม้ว่าเห็นคำตอบของ zombatสำหรับวิธีที่มีประสิทธิภาพมากขึ้น (ประมาณ 3-4 เท่าเร็วขึ้น)
preg_quote
หรือไม่? ตัวอย่างเช่น @ThomasRedstone กังวลว่าตัวคั่น/
อาจเป็นอันตรายหากปรากฏขึ้น$from
แต่โชคดีที่ไม่ใช่: มันจะหลบหนีได้อย่างถูกต้องเนื่องจากpreg_quote
พารามิเตอร์ตัวที่สอง (หนึ่งสามารถทดสอบได้อย่างง่ายดาย) ฉันสนใจที่จะรับฟังปัญหาที่เฉพาะเจาะจง (ซึ่งเป็นข้อบกพร่องด้านความปลอดภัย PCRE ร้ายแรงในหนังสือของฉัน)
ไม่มีรุ่น แต่โซลูชันไม่ได้แฮ็กเลย
$pos = strpos($haystack, $needle);
if ($pos !== false) {
$newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
}
ค่อนข้างง่ายและประหยัดค่าปรับของนิพจน์ทั่วไป
โบนัส: ถ้าคุณต้องการที่จะเปลี่ยนที่ผ่านมาเกิดขึ้นเพียงแค่ใช้ในสถานที่ของstrrpos
strpos
substr_replace
เป็นฟังก์ชั่นที่ค่อนข้างใช้งานไม่ได้เนื่องจากพารามิเตอร์ทั้งหมดปัญหาที่แท้จริงคือการจัดการสตริงด้วยตัวเลขนั้นค่อนข้างยุ่งยากบางครั้งคุณต้องระวังให้ผ่านตัวแปร / ออฟเซ็ตที่ถูกต้อง ที่จริงฉันจะไปไกลถึงจะบอกว่ารหัสข้างต้นเป็นตรงไปตรงมามากที่สุดและสำหรับฉันตรรกะวิธีการ
แก้ไข: ทั้งสองคำตอบได้รับการปรับปรุงและตอนนี้ถูกต้อง ฉันจะออกคำตอบเนื่องจากการกำหนดเวลาฟังก์ชั่นยังคงมีประโยชน์
คำตอบของ 'zombat' และ 'php มากเกินไป' นั้นไม่ถูกต้อง นี่คือการแก้ไขคำตอบที่ zombat โพสต์ (เนื่องจากฉันไม่มีชื่อเสียงพอที่จะโพสต์ความคิดเห็น):
$pos = strpos($haystack,$needle);
if ($pos !== false) {
$newstring = substr_replace($haystack,$replace,$pos,strlen($needle));
}
สังเกต strlen ($ เข็ม) แทน strlen ($ replace) ตัวอย่างของ Zombat จะทำงานได้อย่างถูกต้องหากเข็มและการเปลี่ยนมีความยาวเท่ากัน
นี่คือฟังก์ชั่นเดียวกันในฟังก์ชั่นที่มีลายเซ็นเดียวกับ str_replace ของ PHP:
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));
สังเกต 2 ตอนท้ายแทน 1 หรือในรูปแบบของฟังก์ชั่น:
function str_replace_first($search, $replace, $subject) {
return implode($replace, explode($search, $subject, 2));
}
ฉันตั้งเวลาทั้งสองฟังก์ชั่นและฟังก์ชั่นแรกจะเร็วเป็นสองเท่าเมื่อไม่พบที่ตรงกัน พวกเขามีความเร็วเท่ากันเมื่อพบการแข่งขัน
stripos()
to the rescue :-)
ฉันสงสัยว่าอันไหนเร็วที่สุดดังนั้นฉันจึงทดสอบพวกเขาทั้งหมด
ด้านล่างคุณจะพบกับ:
ฟังก์ชั่นทั้งหมดได้รับการทดสอบด้วยการตั้งค่าเดียวกัน:
$string = 'OOO.OOO.OOO.S';
$search = 'OOO';
$replace = 'B';
ฟังก์ชั่นที่จะแทนที่การเกิดขึ้นครั้งแรกของสตริงภายในสตริงเท่านั้น:
substr_replace($string, $replace, 0, strlen($search));
[CONTRIBUTED BY] => zombat
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000062883
[SLOWER BY] => FASTEST
replace_first($search, $replace, $string);
[CONTRIBUTED BY] => too much php
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000073902
[SLOWER BY] => 17.52%
preg_replace($search, $replace, $string, 1);
[CONTRIBUTED BY] => karim79
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000077519
[SLOWER BY] => 23.27%
str_replace_once($search, $replace, $string);
[CONTRIBUTED BY] => happyhardik
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000082286
[SLOWER BY] => 30.86%
str_replace_limit($search, $replace, $string, $count, 1);
[CONTRIBUTED BY] => bfrohs - expanded renocor
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000083342
[SLOWER BY] => 32.54%
str_replace_limit($search, $replace, $string, 1);
[CONTRIBUTED BY] => renocor
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000093116
[SLOWER BY] => 48.08%
str_replace_limit($string, $search, $replace, 1, 0);
[CONTRIBUTED BY] => jayoaK
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000093862
[SLOWER BY] => 49.26%
ฟังก์ชั่นที่จะแทนที่การเกิดขึ้นครั้งสุดท้ายของสตริงภายในสตริงเท่านั้น:
substr_replace($string, $replace, strrpos($string, $search), strlen($search));
[CONTRIBUTED BY] => oLinkSoftware - modified zombat
[OOO.OOO.OOO.S] => OOO.OOO.B.S
[AVERAGE TIME] => 0.0000068083
[SLOWER BY] => FASTEST
strrev(implode(strrev($replace), explode(strrev($search), strrev($string), 2)));
[CONTRIBUTED BY] => oLinkSoftware
[OOO.OOO.OOO.S] => OOO.OOO.B.S
[AVERAGE TIME] => 0.0000084460
[SLOWER BY] => 24.05%
substr_replace()
ชนะผลลัพธ์นั้นง่าย เพราะมันเป็นฟังก์ชั่นภายใน ฟังก์ชันภายในและสิ่งที่ผู้ใช้กำหนดเองทำสองอย่างนั้นแตกต่างกันในด้านประสิทธิภาพเนื่องจากฟังก์ชันภายในนั้นทำงานในเลเยอร์ที่ต่ำกว่า ดังนั้นทำไมไม่preg_match()
? นิพจน์ทั่วไปเกือบจะช้ากว่าฟังก์ชั่นการจัดการสตริงภายในเนื่องจากการค้นหาในสตริงหลายครั้ง
substr_replace($string, $replace, 0, strlen($search));
) 0
ไม่ได้เป็นเพียงการเขียนแบบคงที่ ส่วนหนึ่งของการแก้ปัญหาที่ไม่ใช่ของ regex ก็คือพวกเขาจำเป็นต้อง "ค้นหา" จุดเริ่มต้นก่อนที่จะรู้ว่าจะแทนที่ที่ใด
น่าเสียดายที่ฉันไม่รู้ฟังก์ชัน 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));
}
return implode($replace, explode($find, $subject, $limit+1));
สำหรับหมายเลขแทนที่แบบกำหนดเอง
ฉันสร้างฟังก์ชั่นเล็ก ๆนี้ที่แทนที่สตริงบนสตริง (คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) ด้วยขีด จำกัด โดยไม่จำเป็นต้องใช้ Regexp มันใช้งานได้ดี
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 ! ... และในขณะเดียวกันก็ใช้งานได้ดีและสะอาดหมดจด ...
preg_
โซลูชันที่ปรับแต่งได้ง่ายไม่ใช่เรื่องบ้าแต่เป็นความชอบส่วนตัว return preg_replace('/'.preg_quote($search, '/').'/', $replace, $content, 1);
เป็นเรื่องง่ายที่จะอ่านสำหรับคนที่ไม่กลัว regex ต้องการค้นหาตัวพิมพ์เล็กหรือตัวพิมพ์ใหญ่หรือไม่ เพิ่มi
หลังจากตัวคั่นรูปแบบสิ้นสุด ต้องการการสนับสนุน unicode / multibyte หรือไม่ เพิ่มu
หลังจากตัวคั่นรูปแบบสิ้นสุด ต้องการการสนับสนุนขอบเขตของคำหรือไม่ เพิ่ม\b
ทั้งสองด้านของสตริงการค้นหาของคุณ หากคุณไม่ต้องการ regex อย่าใช้ regex ม้าสำหรับหลักสูตร แต่ไม่บ้าแน่นอน
วิธีที่ง่ายที่สุดคือการใช้การแสดงออกปกติ
วิธีอื่นคือค้นหาตำแหน่งของสตริงด้วย strpos () จากนั้น substr_replace ()
แต่ฉันจะไปที่ RegExp จริงๆ
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));
}
=> รหัสถูกแก้ไขแล้วดังนั้นให้พิจารณาบางความคิดเห็นที่เก่าเกินไป
และขอบคุณทุกคนที่ช่วยฉันปรับปรุงมัน
ข้อผิดพลาดใด ๆ โปรดสื่อสารฉัน ฉันจะแก้ไขมันทันที
ดังนั้นไปสำหรับ:
การแทนที่'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
มันเร็วกว่า
$string = 'this is my world, not my world';
$find = 'world';
$replace = 'farm';
$result = preg_replace("/$find/",$replace,$string,1);
echo $result;
preg_quote
ของ$find
ก่อนที่จะใช้มันเป็นการแสดงออก
preg_quote()
คำตอบที่ซ้ำกันปลายนี้สามารถกำจัดได้อย่างปลอดภัยจากหน้าเพราะคำแนะนำที่ให้ไว้โดยก่อนหน้านี้และคำตอบที่ยอมรับ upvoted สูงขึ้น
เพื่อขยายคำตอบ @ renocor ของผมได้เขียนฟังก์ชั่นที่เป็น 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;
}
}
E_USER_WARNING
ตลอดซึ่งเป็นคำเตือน , ไม่ข้อผิดพลาด backtrace มีประโยชน์อย่างยิ่งในการค้นหาว่ารหัสใดที่ส่งข้อมูลที่ไม่ถูกต้องไปยังฟังก์ชันในตอนแรก (ซึ่งจำเป็นอย่างยิ่งในการติดตามข้อบกพร่องในการผลิต) สำหรับการกลับมา$subject
แทนที่จะfalse
/ null
หรือโยนข้อผิดพลาดนั่นเป็นเพียงตัวเลือกส่วนบุคคลสำหรับกรณีการใช้งานของฉัน เพื่อให้ตรงกับstr_replace()
การใช้งานของการใช้ข้อผิดพลาดร้ายแรงที่จับได้จะเป็นทางออกที่ดีที่สุด (เช่นstr_replace()
เมื่อมีการปิดสำหรับสองอาร์กิวเมนต์แรก)
preg_replace()
หากคุณต้องการที่จะนับทดแทนที่ทำมีพารามิเตอร์สำหรับการที่ใน นอกจากนี้preg_replace()
/ regex มีการจัดการขอบเขตคำ (ถ้าเป็นที่ต้องการ) - สิ่งที่ฟังก์ชั่นที่ไม่ใช่ regex จะไม่ให้อย่างหรูหรา
จากผลการทดสอบของฉันฉันต้องการลงคะแนน regular_express ที่จัดทำโดย karim79 (ฉันมีชื่อเสียงไม่พอที่จะลงคะแนนตอนนี้!)
โซลูชันจาก zombat ใช้การเรียกใช้ฟังก์ชันมากเกินไปฉันจะทำให้รหัสง่ายขึ้น ฉันใช้ 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
ดังนั้นเมื่อเข็มไม่ได้อยู่ในกองหญ้าก็จะเกิดความเสียหายเอาท์พุท
เพื่อขยายคำตอบของ zombat (ซึ่งฉันเชื่อว่าเป็นคำตอบที่ดีที่สุด) ฉันได้สร้างฟังก์ชันแบบเรียกซ้ำที่ใช้$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 อย่างไรก็ตามอย่างที่ฉันพูดในความคิดเห็นที่อื่นในหน้านี้ฉันต้องการ ใช้สะอาดมากตรงที่ไม่ใช่ recursive preg_replace()
โทร
else
statment บรรทัดนี้$start_pos > strlen($haystack) ? $start_pos = strlen($haystack) : '';
สำหรับสตริง
$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
substr_replace()
เทคนิคสร้างความเสียหายให้กับสตริงอินพุตเมื่อไม่มีค่าการค้นหา หลักฐานการล้มเหลว: 3v4l.org/HmEml (และเทคนิคสุดท้ายที่มีการrev
เรียกทั้งหมดนั้นซับซ้อนมาก / ยากต่อสายตา)
การเติมเต็มสิ่งที่ผู้คนพูดไว้โปรดจำไว้ว่าสตริงทั้งหมดเป็นอาร์เรย์:
$string = "Lorem ipsum lá lá lá";
$string[0] = "B";
echo $string;
"Borem ipsum lálálá"
á
วิธีโชคร้ายที่คุณนำเสนอสายป้อนตัวอย่างที่มี การสาธิตความล้มเหลว
string
เป็นสตริงหลายไบต์โดยใช้mb_strlen($subject) != strlen($subject)
$str = "/property/details&id=202&test=123#tab-6p";
$position = strpos($str,"&");
echo substr_replace($str,"?",$position,1);
การใช้ substr_replace เราสามารถแทนที่การเกิดขึ้นของอักขระตัวแรกในสตริงเท่านั้น ในฐานะ & ซ้ำหลายครั้ง แต่ในตำแหน่งแรกเราต้องแทนที่ & ด้วย?
ฟังก์ชั่นนี้ได้แรงบันดาลใจอย่างมากจากคำตอบของ @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;
}
คุณสามารถใช้สิ่งนี้:
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
นี่อาจลดประสิทธิภาพลงเล็กน้อย แต่เป็นวิธีที่ง่ายที่สุด
strpos()
) ลดลงเพราะไม่ได้เพิ่มคุณค่าใหม่ให้กับหน้าเว็บ
หากสตริงของคุณไม่มีอักขระหลายไบต์และหากคุณต้องการแทนที่อักขระตัวเดียวคุณสามารถใช้ 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;
}
สำหรับโซลูชั่นวน
<?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;
}
นี่คือคลาสธรรมดาที่ฉันสร้างขึ้นเพื่อรวมฟังก์ชันstr_replace () ที่ปรับเปลี่ยนเล็กน้อยของเรา
php :: str_rreplace () ฟังก์ชั่นของเรายังช่วยให้คุณดำเนินการย้อนกลับ str_replace จำกัด () ซึ่งจะมีประโยชน์มากเมื่อพยายามที่จะแทนที่เพียงอินสแตนซ์ X สุดท้ายของสตริง
ตัวอย่างเหล่านี้ใช้งานทั้ง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) );
}
}
$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")
มีที่ว่างเพิ่มอีกหนึ่งช่อง แต่มันก็ไม่สำคัญเหมือนกันกับสคริปต์แบคกราวน์ในกรณีของฉัน
นี่เป็นคำตอบแรกของฉันที่นี่ฉันหวังว่าจะทำอย่างถูกต้อง ทำไมไม่ใช้อาร์กิวเมนต์ที่สี่ของฟังก์ชัน str_replace สำหรับปัญหานี้
mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
นับ: ถ้าผ่านจะถูกกำหนดเป็นจำนวนการเปลี่ยนที่ทำ
แก้ไข: คำตอบนี้ไม่ถูกต้องเพราะพารามิเตอร์ที่ 4 ของstr_replaceเป็นตัวแปรที่ได้รับมอบหมายจำนวนของการแทนที่ทำ นี้ไม่สอดคล้องกับpreg_replaceซึ่งมีพารามิเตอร์ที่ 4 และพารามิเตอร์ที่$limit
5&$count
ง่ายต่อการค้นหาโซลูชันเพื่อแทนที่อินสแตนซ์คู่แรกหรือคู่แรกของอินสแตนซ์ (โดยให้ค่าการนับ) มีวิธีแก้ไขไม่มากที่จะแทนที่อินสแตนซ์สุดท้ายหรือคู่สุดท้ายของอินสแตนซ์
บางทีสิ่งที่ต้องการ str_replace ($ find, $ replace, $ subject, -3) ควรแทนที่สามอินสแตนซ์ล่าสุด
อย่างไรก็ตามเพียงแค่ข้อเสนอแนะ
s($subject)->replaceFirst($search)
และs($subject)->replaceFirstIgnoreCase($search)
เป็นประโยชน์ตามที่พบในห้องสมุดแบบสแตนด์อโลนนี้