Is there any way to replace the same needle in string with differnet values out of a array?
Like that:
$string = ">>>?<<<>>>?<<<>>>?<<<"; // replacing the three occourances of "?"
// values of array
echo str_multiple_replace($string, array("Hello", "World", "!"));
Output:
">>>Hallo<<<>>>World<<<>>>!<<<"
How can the function str_multiple_replace look like to replace the three question marks with the content of the array.
EDIT: Let content NOT affect the replacing, so for example, if there is a "?" in the array, it shouldn't be replaced.
Use preg_replace_callback():
$string = ">>>?<<<>>>?<<<>>>?<<<";
$subs = array('Hello','World','!');
echo preg_replace_callback('#\?#',function ($matches) use (&$subs) {
return array_shift($subs);
},$string);
Or:
$string = ">>>?<<<>>>?<<<>>>?<<<";
$subs = array('Hello','World','!');
function str_multiple_replace($string, $needle, $subs) {
return preg_replace_callback('#'.preg_quote($needle,'#').'#',function ($matches) use (&$subs) {
return array_shift($subs);
},$string);
}
echo str_multiple_replace($string,'?',$subs);
You can actually utilize vprintf function to make this code extremely simple:
$string = ">>>?<<<%s>>>?<<<>>>?<<<";
$arr = array('Hello', 'World', '!');
vprintf(str_replace(array('%', '?'), array('%%', '%s'), $string), $subs);
UPDATE: Code using vsprintf function: (Thanks to #ComFreek)
function str_multiple_replace($str, $needle, $subs) {
return vsprintf(str_replace(array('%', $needle), array('%%', '%s'), $str), $subs);
}
$string = ">>>?<<<%s>>>?<<<>>>?<<<";
echo str_multiple_replace($string, '?', array('Hello', 'World', '!'));
OUTPUT:
>>>Hello<<<%s>>>World<<<>>>!<<<
This is not exactly the same format as your example, but the concept is the same:
PHP's printf() produces output according to a format:
$string=">>>%s<<<>>>%s<<<>>>%s<<<";
$length=printf($string,"Hello", "World", "!");
Outputs: >>>Hello<<<>>>World<<<>>>!<<<
http://php.net/manual/en/function.printf.php
A brute force solution would be something like....
function str_multiple_replace($haystack, $needle, $replacements)
{
$out = '';
while ($haystack && count($needle)) {
$out .= substr($haystack, 0,1);
$haystack = substr($haystack, 1);
if (substr($out, -1*strlen($needle)) === $needle) {
$out = substr($out, 0, -1*strlen($needle)) . array_shift($replacements);
}
}
$out .= $haystack;
return $out;
}
Related
I am looking for a function or class that substitutes given string and returns array of all possible replacements.
In other words I am seeking for a magic_function:
function magic_function( $str, $find, $replace )
{
$arr = array();
// some magic stuff
return $arr;
}
var_dump( magic_function( 'aaa', 'a', 'b' ) );
/*
should return:
Array(
'aab',
'aba',
'baa',
'bba',
'bab',
'abb',
'bbb'
);
*/
I am thinking of using explode and then somehow looping through that array, but maybe there is a simpler way? Maybe with regex? Any ideas? :)
Thank you in advance!
explode and loop seems fairly simple.
<?php
function magic_function ($str, $find, $replace) {
$parts = explode($find, $str);
$n = count($parts)-1;
$p = 1<<$n;
for ($i=1; $i<$p; $i++) {
for ($perm="", $seps=$i, $j=0; $j<$n; $seps>>=1, $j++) {
$perm .= $parts[$j] . ($seps&1 ? $replace : $find);
}
$res[] = $perm . $parts[$n];
}
return $res;
}
Start from $i=0 to include the no-replacement case.
In few words, I am trying to replace all the "?" with the value inside a variable and it doesn't work. Please help.
$string = "? are red ? are blue";
$count = 1;
update_query($string, array($v = 'violets', $r = 'roses'));
function update_query($string, $values){
foreach ( $values as $val ){
str_replace('?', $val, $string, $count);
}
echo $string;
}
The output I am getting is: ? are red ? are blue
Frustrated by people not paying attention, I am compelled to answer the question properly.
str_replace will replace ALL instances of the search string. So after violets, there will be nothing left for roses to replace.
Sadly str_replace does not come with a limit parameter, but preg_replace does. But you can actually do better still with preg_replace_callback, like so:
function update_query($string, $values){
$result = preg_replace_callback('/\?/', function($_) use (&$values) {
return array_shift($values);
}, $string);
echo $string;
}
You forgot to set it equal to your variable.
$string = str_replace('?', $val, $string, $count);
You probably want to capture the return from str_replace in a new string and echo it for each replacement, and pass $count by reference.
foreach ( $values as $val ){
$newString = str_replace('?', $val, $string, &$count);
echo $newString;
}
This is the best and cleanest way to do it
<?php
$string = "? are red ? are blue";
$string = str_replace('?','%s', $string);
$data = array('violets','roses');
$string = vsprintf($string, $data);
echo $string;
Your code edited
$string = "? are red ? are blue";
update_query($string, array('violets','roses'));
function update_query($string, $values){
$string = str_replace('?','%s', $string);
$string = vsprintf($string, $values);
echo $string;
}
Ok guys here is the solution from a combination of some good posts.
$string = "? are red ? are blue";
update_query($string, array($v = 'violets', $r = 'roses'));
function update_query($string, $values){
foreach ( $values as $val ){
$string = preg_replace('/\?/', $val, $string, 1);
}
echo $string;
}
As mentioned, preg_replace will allow limiting the amount of matches to update. Thank you all.
You can solve this in two ways:
1) Substitute the question marks with their respective values. There are a hundred ways one could tackle it, but for something like this I prefer just doing it the old-fashioned way: Find the question marks and replace them with the new values one by one. If the values in $arr contain question marks themselves then they will be ignored.
function update_query($str, array $arr) {
$offset = 0;
foreach ($arr as $newVal) {
$mark = strpos($str, '?', $offset);
if ($mark !== false) {
$str = substr($str, 0, $mark).$newVal.substr($str, $mark+1);
$offset = $mark + (strlen($newVal) - 1);
}
}
return $str;
}
$string = "? are red ? are blue";
$vars = array('violets', 'roses');
echo update_query($string, $vars);
2) Or you can make it easy on yourself and use unique identifiers. This makes your code easier to understand, and more predictable and robust.
function update_query($str, array $arr) {
return strtr($str, $arr);
}
echo update_query(':flower1 are red :flower2 are blue', array(
':flower1' => 'violets',
':flower2' => 'roses',
));
You could even just use strtr(), but wrapping it in a function that you can more easily remember (and which makes sense in your code) will also work.
Oh, and if you are planning on using this for creating an SQL query then you should reconsider. Use your database driver's prepared statements instead.
I have an string such as
$string = "This is my test string {ABC}. This is test {XYZ}. I am new for PHP {PHP}".
Now I need to replace occurrence of string within {}, in such a way that output will be:
This is my test string {ABC 1}. This is test {XYZ 2}. I am new for PHP {PHP 3}".
I am looking to resolve this with recursive function but not getting expected result.
$i = 1;
echo preg_replace_callback('/\{(.+?)\}/', function (array $match) use (&$i) {
return sprintf('{%s %d}', $match[1], $i++);
}, $string);
The "trick" is to simply keep an external counter running, here $i, which is used in the anonymous callback via use (&$i).
There is no recursion here. Simply counting.
$result = preg_replace_callback("/\{([^}]*+)\}/",function($m) {
static $count = 0;
$count++;
return "{".$m[1]." ".$count."}";
},$string);
If you really need recursive :^ )
$string = "This is my test string {ABC}. This is test {XYZ}. I am new for PHP {PHP}";
function my_replace($string, $count = 1)
{
if ($string)
{
return preg_replace_callback('/\{(.+?)\}(.*)$/', function (array $match) use ($count)
{
return sprintf('{%s %d} %s', $match[1], $count, my_replace($match[2], $count + 1));
}, $string, 1);
}
}
echo my_replace($string);
I'm looking for a way to replace all but first occurrences of a group or some character.
For example a following random string:
+Z1A124B555ND124AB+A555
1,5,2,4,A,B and + are repeating through out the string.
124, 555 are groups of characters that are also reoccurring.
Now, let's say I want to remove every but first occurrence of 555, A and B.
What regex would be appropriate? I could think of an example replacing all:
preg_replace('/555|A|B/','',$string);
Something like ^ that, but I want to keep the first occurrence... Any ideas?
Are your strings always delimited by plus signs? Do 555, A, and B always occur in the first "group" (delimited by +)?
If so, you can split, replace and then join:
$input = '+Z1A124B555+A124AB+A555';
$array = explode('+', $input, 3); // max 3 elements
$array[2] = str_replace(array('555', 'A', 'B'), '', $array[2]);
$output = implode('+', $array);
ps. No need to use regexes, when we can use a simple str_replace
Use the preg_replace_callback function:
$replaced = array('555' => 0, 'A' => 0, 'B' => 0);
$input = '+Z1A124B555+A124AB+A555';
$output = preg_replace_callback('/555|[AB]/', function($matches) {
static $replaced = 0;
if($replaced++ == 0) return $matches[0];
return '';
}, $input);
This solution could be modified to do what you want: PHP: preg_replace (x) occurrence?
Here is a modified solution for you:
<?php
class Parser {
private $i;
public function parse($source) {
$this->i=array();
return preg_replace_callback('/555|A|B/', array($this, 'on_match'), $source);
}
private function on_match($m) {
$first=$m[0];
if(!isset($this->i[$first]))
{
echo "I'm HERE";
$this->i[$first]=1;
}
else
{
$this->i[$first]++;
}
// Return what you want the replacement to be.
if($this->i[$first]>1)
{
$result="";
}
else
{
$result=$m[0];
}
return $result;
}
}
$sample = '+Z1A124B555ND124AB+A555';
$parse = new Parser();
$result = $parse->parse($sample);
echo "Result is: [$result]\n";
?>
A more generic function that works with every pattern.
function replaceAllButFirst($pattern, $replacement, $subject) {
return preg_replace_callback($pattern,
function($matches) use ($replacement, $subject) {
static $s;
$s++;
return ($s <= 1) ? $matches[0] : $replacement;
},
$subject
);
}
I was looking for some standard PHP function to replace some value of an array with other, but surprisingly I haven't found any, so I have to write my own:
function array_replace_value(&$ar, $value, $replacement)
{
if (($key = array_search($ar, $value)) !== FALSE) {
$ar[$key] = $replacement;
}
}
But I still wonder - for such an easy thing there must already be some function for it! Or maybe much easier solution than this one invented by me?
Note that this function will only do one replacement. I'm looking for existing solutions that similarly replace a single occurrence, as well as those that replace all occurrences.
Instead of a function that only replaces occurrences of one value in an array, there's the more general array_map:
array_map(function ($v) use ($value, $replacement) {
return $v == $value ? $replacement : $v;
}, $arr);
To replace multiple occurrences of multiple values using array of value => replacement:
array_map(function ($v) use ($replacement) {
return isset($replacement[$v]) ? $replacement[$v] : $v;
}, $arr);
To replace a single occurrence of one value, you'd use array_search as you do. Because the implementation is so short, there isn't much reason for the PHP developers to create a standard function to perform the task. Not to say that it doesn't make sense for you to create such a function, if you find yourself needing it often.
While there isn't one function equivalent to the sample code, you can use array_keys (with the optional search value parameter), array_fill and array_replace to achieve the same thing:
EDIT by Tomas: the code was not working, corrected it:
$ar = array_replace($ar,
array_fill_keys(
array_keys($ar, $value),
$replacement
)
);
If performance is an issue, one may consider not to create multiple functions within array_map(). Note that isset() is extremely fast, and this solutions does not call any other functions at all.
$replacements = array(
'search1' => 'replace1',
'search2' => 'replace2',
'search3' => 'replace3'
);
foreach ($a as $key => $value) {
if (isset($replacements[$value])) {
$a[$key] = $replacements[$value];
}
}
Try this function.
public function recursive_array_replace ($find, $replace, $array) {
if (!is_array($array)) {
return str_replace($find, $replace, $array);
}
$newArray = [];
foreach ($array as $key => $value) {
$newArray[$key] = recursive_array_replace($find, $replace, $value);
}
return $newArray;
}
Cheers!
$ar[array_search('green', $ar)] = 'value';
Depending whether it's the value, the key or both you want to find and replace on you could do something like this:
$array = json_decode( str_replace( $replace, $with, json_encode( $array ) ), true );
I'm not saying this is the most efficient or elegant, but nice and simple.
What about array_walk() with callback?
$array = ['*pasta', 'cola', 'pizza'];
$search = '*';
$replace = '\*';
array_walk($array,
function (&$v) use ($search, $replace){
$v = str_replace($search, $replace, $v);
}
);
print_r($array);
Based on Deept Raghav's answer, I created the follow solution that does regular expression search.
$arr = [
'Array Element 1',
'Array Element 2',
'Replace Me',
'Array Element 4',
];
$arr = array_replace(
$arr,
array_fill_keys(
array_keys(
preg_grep('/^Replace/', $arr)
),
'Array Element 3'
)
);
echo '<pre>', var_export($arr), '</pre>';
PhpFiddle: http://phpfiddle.org/lite/code/un7u-j1pt
PHP 8, a strict version to replace one string value with another:
array_map(fn (string $value): string => $value === $find ? $replace : $value, $array);
An example - replace value foo with bar:
array_map(fn (string $value): string => $value === 'foo' ? 'bar' : $value, $array);
You can make full string matches without specifying the keys of qualifying values, by calling preg_replace() with a pattern containing start and end of string anchors (^, $). If your search term may contain characters which have a special meaning to the regex engine, then be sure to escape them with preg_quote() to avoid breakage. While regex is not entirely called for, regex offers some very convenient ways to tweak the search term handling. (Demo)
function array_replace_value(&$ar, $value, $replacement)
{
$ar = preg_replace(
'/^' . preg_quote($value, '/') . '$/',
$replacement,
$ar
);
}
I might be more inclined to use array_map() with arrow function syntax so that global variables can be accessed within the custom function scope. (Demo)
$needle = 'foo';
$newValue = 'bar';
var_export(
array_map(fn($v) => $v === $needle ? $newValue : $v, $array)
);
$ar = array(1,2,3,4,5,6,7,8);
$find = array(2,3);
$replace = array(13);
function update_bundle_package($ar,$find,$replace){
foreach ($find as $x => $y) {
///TO REMOVE PACKAGE
if (($key = array_search($y, $ar)) !== false) {
unset($ar[$key]);
}
///TO REMOVE PACKAGE
}
$ar = array_merge($ar, $replace);
}
<b>$green_key = array_search('green', $input); // returns the first key whose value is 'green'
$input[$green_key] = 'apple'; // replace 'green' with 'apple'