Fastest way to replace string patterns by mask - php

I have string like
$string = "string_key::%foo%:%bar%";
, and array of params
$params = array("foo" => 1, "bar" => 2);
How can I replace this params in $string pattern?
Expected result is
string_key::1:2

First, you need to rewrite the $params array:
$string = "string_key::%foo%:%bar%";
$params = array("foo" => 1, "bar" => 2);
foreach($params as $key => $value) {
$search[] = "%" . $key . "%";
$replace[] = $value;
}
After that, you can simply pass the arrays to str_replace():
$output = str_replace($search, $replace, $string);
View output on Codepad

On a personal note, I did this one:
$string = "string_key::%foo%:%bar%";
$params = array("%foo%" => 1, "%bar%" => 2);
$output = strtr($string, $params);
You do not have to do anything else because if there is some value in the array or the string is not replaced and overlooked.
Fast and simple method for pattern replacement.

I'm not sure what will be the fastest solution for you (it depends on the string size and the number of replacement values you will use).
I normally use this kind of function to perform parameterized replacements. It uses preg_replace_callback and a closure to perform the replacement for each percent enclosed word.
function replaceVariables($str, $vars)
{
// the expression '/%([a-z]+)%/i' could be used as well
// (might be better in some cases)
return preg_replace_callback('/%([^%]+)%/', function($m) use ($vars) {
// $m[1] contains the word inside the percent signs
return isset($vars[$m[1]]) ? $vars[$m[1]] : '';
}, $str);
}
echo replaceVariables("string_key::%foo%:%bar%", array(
"foo" => 1,
"bar" => 2
));
// string_key::1:2
Update
It's different from using str_replace() in cases whereby a percent enclosed value is found without a corresponding replacement.
This line determines the behaviour:
return isset($vars[$m[1]]) ? $vars[$m[1]] : '';
It will replace '%baz%' with an empty string if it's not part of the $vars. But this:
return isset($vars[$m[1]]) ? $vars[$m[1]] : $m[0];
Will leave '%baz%' in your final string.

Related

PHP Regex with recursively filter string and append sub-string to array

I'm basically trying to extract parts of a string AFTER a character "/" but using PHP PCRE (Regular Expressions) NOT PHP substr() function, I would like to test if the initial string has multiple "/" characters using a combination of PHP PCRE (Regular Expressions) and preg_match() or preg_match_all().
I am able to select for a SINGLE iteration using a regular expression.
<?php
$rules = array(
'dbl' => "/(?'d'[^/]+)/(?'p'[^/]+)", // '.../a/a' DOUBLE ITERATION
'single' => "/(?'d'[\w\-]+)",// '.../a' SINGLE ITERATION
'multiple' => "" //MULTIPLE ITERATION
);
$string = "a/b/c/d/e";
foreach ( $rules as $action => $rule ) {
if ( preg_match_all( '~^'.$rule.'$~i', $string, $params ) ) {
switch ($action) {
case 'multiple':
$arr = explode("/", $string);
print_r($arr);
//do something
...
}
}
}
?>
I know this is because of my lack of sufficient knowledge of Regular Expressions, however, I need a dynamic Regex code to match the condition that the initial string has multiple "/" characters and then recursively store these substrings to an array.
I would approach this differently: I would first explode $string on / and then apply logic based on the number of elements in the results.
<?php
$string = "a/b/c/d/e";
$arr = explode("/", $string);
if (count($arr) > 2) {
print_r($arr);
// do something knowing there were 2 or more slashes in $string
}
?>
If you need different actions for 0, 1 or 2 slashes, add elseif blocks testing for fewer elements in $arr and put the corresponding actions there.
To answer the question, Using Wiktor Stribiżew's Regex Code:
<?php
$rules = array(
'dbl' => "/(?'d'[^/]+)/(?'p'[^/]+)", // '.../a/a' DOUBLE ITERATION
'single' => "/(?'d'[\w\-]+)",// '.../a' SINGLE ITERATION
'multiple' => "/[^/]+(?:/[^/]+){2,}/?" //MULTIPLE ITERATION
);
$string = "a/b/c/d/e";
foreach ( $rules as $action => $rule ) {
if ( preg_match_all( '~^'.$rule.'$~i', $string, $params ) ) {
switch ($action) {
case 'multiple':
$arr = explode("/", $string);
print_r($arr);
//do something
...
}
}
}
?>
For others who reference this resource, kindly upvote Wiktor Stribiżew's answer once/ if he posts it.

How can I reuse the key value of the search parameter in the replace parameter in str_replace()?

What would be the syntax to reuse the key value of the search parameter in the replace parameter, for example
$key = array($value1, $value2, …);
echo str_replace($key, "<span class='key'>$key</span>", $content);
The above will return an Array rather than a single array item.
You can also use preg_replace_callback. Str replace doesn't accept arguments in the replacement string.
$key = array($value1, $value2, …);
$regex = addslashes(implode('|', $key));
$content = preg_replace_callback(
"/$regex/",
function ($matches) {
return '<span class="key">'.$matches[0].'</span>';
},
$content
);
bitWorking has a better answer though if you can make each value in the array it's own regular expression.
Use preg_replace
$key = array('/a/', '/b/');
echo preg_replace($key, '<span class="key">$0</span>', 'a b');

Search an Array and remove entry if it doesn't contain A-Z or a A-Z with a dash

I have the following Array:
Array
(
[0] => text
[1] => texture
[2] => beans
[3] =>
)
I am wanting to get rid of entries that don't contain a-z or a-z with a dash. In this case array item 3 (contains just a space).
How would I do this?
Try with:
$input = array( /* your data */ );
function azFilter($var){
return preg_match('/^[a-z-]+$/i', $var);
}
$output = array_filter($input, 'azFilter');
Also in PHP 5.3 there is possible to simplify it:
$input = array( /* your data */ );
$output = array_filter($input, function($var){
return preg_match('/^[a-z-]+$/i', $var);
});
Try:
<?php
$arr = array(
'abc',
'testing-string',
'testing another',
'sdas 213',
'2323'
);
$tmpArr = array();
foreach($arr as $str){
if(preg_match("/^([-a-z])+$/i", $str)){
$tmpArr[] = $str;
}
}
$arr = $tmpArr;
?>
Output:
array
0 => string 'abc' (length=3)
1 => string 'testing-string' (length=14)
For the data you have provided in your question, use the array_filter() function with an empty callback parameter. This will filter out all empty elements.
$array = array( ... );
$array = array_filter($array);
If you need to filter the elements you described in your question text, then you need to add a callback function that will return true (valid) or false (invalid) depending on what you need. You might find the ctype_alpha functions useful for that.
$array = array( ... );
$array = array_filter($array, 'ctype_alpha');
If you need to allow dashes as well, you need to provide an own function as callback:
$array = array( ... );
$array = array_filter($array, function($test) {return preg_match('(^[a-zA-Z-]+$)', $test);});
This sample callback function is making use of the preg_match() function using a regular expression. Regular expressions can be formulated to represent a specifc group of characters, like here a-z, A-Z and the dash - (minus sign) in the example.
Ok , simply you can loop trough the array. Create an regular expression to test if it matches your criteria.If it fails use unset() to remove the selected element.

php preg_match tab separated

I need a regular expression to look for the first N chars on an array until a tab or comma separation is found.
array look like:
array (
0 => '001,Foo,Bar',
1 => '0003,Foo,Bar',
2 => '3000,Foo,Bar',
3 => '3333433,Foo,Bar',
)
I'm looking for the first N chars, so for instance, pattern to search is 0003, get array index 1...
What would be a good way of doing this?
/^(.*?)[,\t]/
?
Try the regular expression /^0003,/ together with preg_grep:
$array = array('001,Foo,Bar', '0003,Foo,Bar', '3000,Foo,Bar', '3333433,Foo,Bar');
$matches = preg_grep('/^0003,/', $array);
var_dump($matches);
A REGEXP replacement would be: strpos() and substr()
Following your edit:
Use trim(), after searching for a comma with strpos() and retrieving the required string with substr().
use preg_split on the string
$length=10;
foreach($arr as $string) {
list($until_tab,$rest)=preg_split("/[\t,]+/", $string);
$match=substr($until_tab, $length);
echo $match;
}
or
array_walk($arr, create_function('&$v', 'list($v,$rest) = preg_split("/[\t,]+/", $string);'); //syntax not checked
This PHP5 code will do a prefix search on the first element, expecting a trailing comma. It's O(n), linear, inefficient, slow, etc. You'll need a better data structure if you want better search speed.
<?php
function searchPrefix(array $a, $needle) {
$expression = '/^' . quotemeta($needle) . ',/';
$results = array();
foreach ($a as $k => $v)
if (preg_match($expression, $v)) $results[] = $k;
return $results;
}
print_r(searchPrefix($a, '0003'));
$pattern = '/^[0-9]/siU';
for($i=0;$i<count($yourarray);$i++)
{
$ids = $yourarray[$i];
if(preg_match($pattern,$ids))
{
$results[$i] = $yourarray[$i];
}
}
print_r($results);
this will print
0 => '001',
1 => '0003',
2 => '3000',
3 => '3333433'

PHP str_replace

I'm currently using str_replace to remove a usrID and the 'comma' immediately after it:
For example:
$usrID = 23;
$string = "22,23,24,25";
$receivers = str_replace($usrID.",", '', $string); //Would output: "22,24,25"
However, I've noticed that if:
$usrID = 25; //or the Last Number in the $string
It does not work, because there is not a trailing 'comma' after the '25'
Is there a better way I can be removing a specific number from the string?
Thanks.
YOu could explode the string into an array :
$list = explode(',', $string);
var_dump($list);
Which will give you :
array
0 => string '22' (length=2)
1 => string '23' (length=2)
2 => string '24' (length=2)
3 => string '25' (length=2)
Then, do whatever you want on that array ; like remove the entry you don't want anymore :
foreach ($list as $key => $value) {
if ($value == $usrID) {
unset($list[$key]);
}
}
var_dump($list);
Which gives you :
array
0 => string '22' (length=2)
2 => string '24' (length=2)
3 => string '25' (length=2)
And, finally, put the pieces back together :
$new_string = implode(',', $list);
var_dump($new_string);
And you get what you wanted :
string '22,24,25' (length=8)
Maybe not as "simple" as a regex ; but the day you'll need to do more with your elements (or the day your elements are more complicated than just plain numbers), that'll still work :-)
EDIT : and if you want to remove "empty" values, like when there are two comma, you just have to modifiy the condition, a bit like this :
foreach ($list as $key => $value) {
if ($value == $usrID || trim($value)==='') {
unset($list[$key]);
}
}
ie, exclude the $values that are empty. The "trim" is used so $string = "22,23, ,24,25"; can also be dealt with, btw.
Another issue is if you have a user 5 and try to remove them, you'd turn 15 into 1, 25 into 2, etc. So you'd have to check for a comma on both sides.
If you want to have a delimited string like that, I'd put a comma on both ends of both the search and the list, though it'd be inefficient if it gets very long.
An example would be:
$receivers = substr(str_replace(','.$usrID.',', ',', ','.$string.','),1,-1);
An option similar to Pascal's, although I think a bit simipler:
$usrID = 23;
$string = "22,23,24,25";
$list = explode(',', $string);
$foundKey = array_search($usrID, $list);
if ($foundKey !== false) {
// the user id has been found, so remove it and implode the string
unset($list[$foundKey]);
$receivers = implode(',', $list);
} else {
// the user id was not found, so the original string is complete
$receivers = $string;
}
Basically, convert the string into an array, find the user ID, if it exists, unset it and then implode the array again.
I would go the simple way: add commas around your list, replace ",23," with a single comma then remove extra commas. Fast and simple.
$usrID = 23;
$string = "22,23,24,25";
$receivers = trim(str_replace(",$usrID,", ',', ",$string,"), ',');
With that said, manipulating values in a comma separated list is usually sign of a bad design. Those values should be in an array instead.
Try using preg:
<?php
$string = "22,23,24,25";
$usrID = '23';
$pattern = '/\b' . $usrID . '\b,?/i';
$replacement = '';
echo preg_replace($pattern, $replacement, $string);
?>
Update: changed $pattern = '/$usrID,?/i'; to $pattern = '/' . $usrID . ',?/i';
Update2: changed $pattern = '/' . $usrID . ',?/i to $pattern = '/\b' . $usrID . '\b,?/i' to address onnodb's comment...
Simple way (providing all 2 digit numbers):
$string = str_replace($userId, ',', $string);
$string = str_replace(',,','', $string);

Categories