preg_replace('/([a-z]+)([0-9]+)/', '$2$1', $str);
I want to store $1 and $2 in a variable. How can I store it in a variable?
Finding matches is the job of preg_match().
preg_match('/([a-z]+)([0-9]+)/', $str, $matches);
matches:
If matches is provided, then it is filled with the results of search. $matches[0] will contain the text that matched the full
pattern, $matches[1] will have the text that matched the first
captured parenthesized subpattern, and so on.
$full_pattern = $matches[0]
$a = $matches[1] // $1
$b = $matches[2] // $2
$c = $matches[3] // $3
$n = $matches[n] // $n
Use preg_replace_callback:
$one; $two;
function callback($matches)
{
global $one,$two;
$one = $matches[0];
$two = $matches[1];
return $matches[1].$matches[0];
}
preg_replace_callback('/([a-z]+)([0-9]+)/', 'callback', $str);
NOTE
Global is... not a good idea. I actually left that in because it is a concise, clear example of how to accomplish what you're trying to do. I would that I had never used the word, but global is there now and I don't feel right removing it. Actually, its existence saddens me deeply. You are far better off with something like this:
class Replacer
{
private $matches, $pattern, $callback;
public function __construct($pattern, $callback)
{
$this->pattern = $pattern;
$this->callback = $callback;
}
public function getPregCallback()
{
return array( $this, '_callback' );
}
public function _callback( array $matches )
{
$template = $this->pattern;
foreach( $matches as $key => $val )
{
if( $this->callback )
{
$matches[ $key ] = $val = $this->callback( $val );
}
$template = str_replace( '$' . ( $key + 1 ), $val, $template );
}
$this->matches = $matches;
return $template;
}
public function getMatches(){ return $this->matches; }
}
USE
// does what the first example did, plus it calls strtolower on all
// of the elements.
$r = new Replacer( '$2$1', 'strtolower' );
preg_replace_callback('/([a-z]+)([0-9]+)/', $r->getPregCallback(), $str);
list( $a, $b ) = $r->getMatches();
Use preg_replace_callback:
preg_replace_callback('/([a-z]+)([0-9]+)/', function($m) {
// save data
return $m[1].$m[0];
}, $str);
(This uses PHP 5.3 anonymous function syntax, on older PHP just define a normal function and pass its name as the second parameter.)
use preg_replace with "e" ( eval flag)
or better use
preg_replace_callback
http://php.net/manual/en/function.preg-replace-callback.php
see code here :
http://codepad.org/22Qh3wRA
<?php
$str = "a9";
preg_replace_callback('/([a-z]+)([0-9]+)/', "callBackFunc", $str);
function callBackFunc($matches)
{
var_dump($matches);
// here you can assign $matches elements to variables.
}
?>
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.
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 need function in PHP for handle replacement something like this.
$pattern = ':foo/anotherString';
$replacement = array(
'foo' => 'HelloMe'
);
bazFunction($pattern, $replacement); // return 'HelloMe/anotherString';
this method used in some frameworks as route patterns. i want to know which function handle that.
this should do (5.3 required because of the closure)
function my_replace($pattern, $replacement) {
// add ':' prefix to every key
$keys = array_map(function($element) {
return ':' . $element;
}, array_keys($replacement));
return str_replace($keys, array_values($replacement), $pattern);
}
You wouldn't need this function if you pass the stuff directly to str_replace
str_replace(array(':foo'), array('HelloMe'), ':foo/anotherString');
$string = "foo/anotherString";
$replacement = array('foo','HelloMe');
$newString = str_replace($replacement[],,$string);
It seems that php got the function for you...
str_replace ( ":foo", "HelloMe" , $pattern )
will give you this output: HelloMe/anotherString
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'
In perl, I can do: 1 while $var =~ s/a/b/;, and it will replace all a with b. In many cases, I would use it more like 1 while $var =~ s/^"(.*)"$/$1/; to remove all pairs of double quotes around a string.
Is there a way to do something similar to this in PHP, without having to do
while (preg_match('/^"(.*)"$/', $var)) {
$var = preg_replace('/^"(.*)"$/', '$1', $var, 1);
}
Because apparently,
while ($var = preg_replace('/^"(.*)"$/', '$1', $var, 1)) { 1; }
doesn't work.
EDIT: The specific situation I'm working in involves replacing values in a string with values from an associative array:
$text = "This is [site_name], home of the [people_type]".
$array = ('site_name' => 'StackOverflow.com', 'people_type' => 'crazy coders');
where I would be doing:
while (preg_match('/\[.*?\]/', $text)) {
$text = preg_replace('/\[(.*?)\]/', '$array[\'$1\']', $text, 1);
}
with the intended output being 'This is StackOverflow.com, home of the crazy coders'
preg_replace('#\[(.*?)\]#e', "\$array['$1']", $text);
In all of the cases, you can get rid of the loop by (e.g.) using the /g global replace option or rewriting the regexp:
$var =~ s/a/b/g;
$var =~ s/^("+)(.*)\1$/$2/;
The same patterns should work in PHP. You can also get rid of the $limit argument to preg_replace:
$text = preg_replace('/\[(.*?)\]/e', '$array[\'$1\']', $text);
Regular expressions can handle their own loops. Looping outside the RE is inefficient, since the RE has to process text it already processed in previous iterations.
Could something like this work?
$var = preg_replace('/^("+)(.*)\1$', '$2', $var, 1);
What does your input data look like?
Because you're checking for double quotes only at the head and tail of the string. If that's accurate, then you don't need to capture a backreference at all. Also, that would make sending 1 as the 4th parameter completely superfluous.
$var = '"foo"';
// This works
echo preg_replace( '/^"(.*)"$/', '$1', $var );
// So does this
echo preg_replace( '/^"|"$/', '', $var );
But if your input data looks different, that would change my answer.
EDIT
Here's my take on your actual data
class VariableExpander
{
protected $source;
public function __construct( array $source )
{
$this->setSource( $source );
}
public function setSource( array $source )
{
$this->source = $source;
}
public function parse( $input )
{
return preg_replace_callback( '/\[([a-z_]+)\]/i', array( $this, 'expand' ), $input );
}
protected function expand( $matches )
{
return isset( $this->source[$matches[1]] )
? $this->source[$matches[1]]
: '';
}
}
$text = "This is [site_name], home of the [people_type]";
$data = array(
'site_name' => 'StackOverflow.com'
, 'people_type' => 'crazy coders'
);
$ve = new VariableExpander( $data );
echo $ve->parse( $text );
The class is just for encapsulation - you could do this in a structured way if you wanted.
Use do-while:
do {
$var = preg_replace('/^"(.*)"$/', "$1", $var, 1, $count);
} while ($count == 1);
Requires at least php-5.1.0 due to its use of $count.
You could also write
do {
$last = $var;
$var = preg_replace('/^"(.*)"$/', "$1", $var);
} while ($last != $var);