Simplest way to use wildcard in string replacement? - php

I have the following strings:
Johnny arrived at BOB
Peter is at SUSAN
I want a function where I can do this:
$string = stripWithWildCard("Johnny arrived at BOB", "*at ")
$string must equal BOB. Also if I do this:
$string = stripWithWildCard("Peter is at SUSAN", "*at ");
$string must be equal to SUSAN.
What is the shortest way to do this?

A regular expression. You substitute .* for * and replace with the empty string:
echo preg_replace('/.*at /', '', 'Johnny arrived at BOB');
Keep in mind that if the string "*at " is not hardcoded then you also need to quote any characters which have special meaning in regular expressions. So you would have:
$find = '*at ';
$find = preg_quote($find, '/'); // "/" is the delimiter used below
$find = str_replace('\*', '.*'); // preg_quote escaped that, unescape and convert
echo preg_replace('/'.$find.'/', '', $input);

Related

Unable to replace `$_` by something else in preg_replace()

I am investigating, but I am not able to find the solution to this.
The idea is to replace the characters $_ from a string with something else.
If you remove the dollar sign from the $search variable, it kind of works (but not in a desirable way).
It is not working because the dollar sign is a special character, but I cannot find how to scape it.
This is what I have:
$search = '$_'; // replace to '_' OR '[$_]' it returs "$1" instead of "1"
$replace = 1;
$regex = '#".*?"(*SKIP)(*FAIL)|\b' . $search . '\b#s';
$fullInput = '"$_" $_';
$r = preg_replace([$regex], $replace, $fullInput);
echo $r . PHP_EOL;
// Output with current code : "$_" $_
// Output with '_' or '[$_]': "$_" $1
//
// Expected result: "$_" 1
To have into account, if the text is between quotes, it should not be replaced.
You may use this regex for search:
"[^\\"]*(?:\\.|[^\\"]*)*"(*SKIP)(*F)|\$_
and replace it with [$0]
Pattern before | matches a double quoted string allowing an escaped quote in between. Pattern after | matches $_.
RegEx Demo
RegEx Details:
"[^\\"]*(?:\\.|[^\\"]*)*": Match a double quoted string. We allow escaped characters in this match.
(*SKIP)(*F): Skip and fail this match
|: OR
\$_: Match literal text $_
Code:
$search = '$_';
$replace = '[$0]';
$regex = '/"[^\\"]*(?:\\.|[^\\"]*)*"(*SKIP)(*F)|' . preg_quote($search, '/') . '/';
$fullInput = '"$_" $_';
$r = preg_replace($regex, $replace, $fullInput);
echo $r . PHP_EOL;
Output:
"$_" [$_]

Avoid backreference replacement in php's preg_replace

Consider the below use of preg_replace
$str='{{description}}';
$repValue='$0.0 $00.00 $000.000 $1.1 $11.11 $111.111';
$field = 'description';
$pattern = '/{{'.$field.'}}/';
$str =preg_replace($pattern, $repValue, $str );
echo $str;
// Expected output: $0.0 $00.00 $000.000 $1.1 $11.11 $111.11
// Actual output: {{description}}.0 {{description}}.00 {{description}}0.000 .1 .11 1.111
Here is a phpFiddle showing the issue
It's clear to me that the actual output is not as expected because preg_replace is viewing $0, $0, $0, $1, $11, and $11 as back references for matched groups replacing $0 with the full match and $1 and $11 with an empty string since there are no capture groups 1 or 11.
How can I prevent preg_replace from treating prices in my replacement value as back references and attempting to fill them?
Note that $repValue is dynamic and it's content will not be know before the operation.
Escape the dollar character before using a character translation (strtr):
$repValue = strtr('$0.0 $00.00 $000.000 $1.1 $11.11 $111.111', ['$'=>'\$']);
For more complicated cases (with dollars and escaped dollars) you can do this kind of substitution (totally waterproof this time):
$str = strtr($str, ['%'=>'%%', '$'=>'$%', '\\'=>'\\%']);
$repValue = strtr($repValue, ['%'=>'%%', '$'=>'$%', '\\'=>'\\%']);
$pattern = '/{{' . strtr($field, ['%'=>'%%', '$'=>'$%', '\\'=>'\\%']) . '}}/';
$str = preg_replace($pattern, $repValue, $str );
echo strtr($str, ['%%'=>'%', '$%'=>'$', '\\%'=>'\\']);
Note: if $field contains only a literal string (not a subpattern), you don't need to use preg_replace. You can use str_replace instead and in this case you don't have to substitute anything.

Operation on string in PHP. Remove part of string

How can i remove part of string from example:
##lang_eng_begin##test##lang_eng_end##
##lang_fr_begin##school##lang_fr_end##
##lang_esp_begin##test33##lang_esp_end##
I always want to pull middle of string: test, school, test33. from this string.
I Read about ltrim, substr and other but I had no good ideas how to do this. Becouse each of strings can have other length for example :
'eng', 'fr'
I just want have string from middle between ## and ##. to Maye someone can help me? I tried:
foreach ($article as $art) {
$title = $art->titl = str_replace("##lang_eng_begin##", "", $art->title);
$art->cleanTitle = str_replace("##lang_eng_end##", "", $title);
}
But there
##lang_eng_end##
can be changed to
##lang_ger_end##
in next row so i ahvent idea how to fix that
If your strings are always in this format, an explode way looks easy:
$str = "##lang_eng_begin##test##lang_eng_end## ";
$res = explode("##", $str)[2];
echo $res;
You may use a regex and extract the value in between the non-starting ## and next ##:
$re = "/(?!^)##(.*?)##/";
$str = "##lang_eng_begin##test##lang_eng_end## ";
preg_match($re, $str, $match);
print_r($match[1]);
See the PHP demo. Here, the regex matches a ## that is not at the string start ((?!^)##), then captures into Group 1 any 0+ chars other than newline as few as possible ((.*?)) up to the first ## substring.
Or, replace all ##...## substrings with `preg_replace:
$re = "/##.*?##/";
$str = "##lang_eng_begin##test##lang_eng_end## ";
echo preg_replace($re, "", $str);
See another demo. Here, we just remove all non-overlapping substrings beginning with ##, then having any 0+ chars other than a newline up to the first ##.

Merge two regexp in single one php

I need to know if there is any way to merge two regular expression into a single regexp. Recently I had to make the following php code but I feel that there is a simplified way to achieve this without using multiple preg_replace tags. What I am trying to do is strip off & © etc.. and to remove all multiple spaces
$textinput = 'this is a test input \' """""" """" ##$$%&*)_+!##$%^&*) 123 456';
$var = preg_replace("/&#?[a-z0-9]{2,8};/i",'',$textinput)
$string = preg_replace('/\s+/', ' ', $var);
output
this is a test input ' """""""""" ##$$%&*)_+!##$%^&*) 123 456
I am aware about the html_entity_decode function in php to strip the special characters off, well this just an example! How can I merge both of the regexp into a single one?
Thank you!
This will do your two replacements in one efficient step (without losing the whitespace character):
$replaced = preg_replace('~(?:&#?[a-z0-9]{2,8};)+|\s\K\s+~', '', $yourstring);
On the demo, see how all the extra characters are targeted.
Explanation
On the left side of the |, (?:&#?[a-z0-9]{2,8};)+ targets groups such as , not just one at a time but several together if they are touching.
On the right side, the \s matches one space, then the \K tells the engine to drop it from the match (it will not be replaced), then the \s+ matches any whitespace chars that follow
We replace with the empty string.
$var = preg_replace_callback('/&#?[a-z0-9]{2,8};|\s+/i', function($match) {
return $match[0][0] === '&' ? '' : ' ';
}, $textinput);
You could use a logical OR operator to combine both regexes,
(?:&#?[a-z0-9]{2,8};)+|(?<=\s)\s+
Your code would be,
<?php
$mystring = 'this is a test input \' """""" """" ##$$%&*)_+!##$%^&*) 123 456';
$pattern = "~(?:&#?[a-z0-9]{2,8};)+|(?<=\s)\s+~";
$replacement = "";
echo preg_replace($pattern, $replacement, $mystring);
?>
OR
<?php
$mystring = 'this is a test input \' """""" """" ##$$%&*)_+!##$%^&*) 123 456';
$pattern = "~&#?[a-z0-9]{2,8};|(?<=\s)\s+~";
$replacement = "";
echo preg_replace($pattern, $replacement, $mystring);
?>
output:
this is a test input ' """""" """" ##$$%&*)_+!##$%^&*) 123 456

Working regex pattern doesn't work in PHP despite preg_quote

The pattern below seems to work in regex editors, but it doesn't work in PHP (no error).
I thought by adding delimiters and running the pattern through preg_quote would address this.
Would appreciate any help on what step I'm missing here.
Code sample:
$pattern = '%(?<=#address|.)singleline(?=[^\]\[]*\])%';
$pattern = preg_quote($pattern);
$output = preg_replace($pattern, "", $output);
HTML Sample:
<p>[#address|singleline]</p>
preg_quote escapes characters that are regular expression syntax characters. These include . \ + * ? [ ^ ] $ ( ) { } = ! < > | : -. Try not using preg_quote.
$pattern = '%(?<=#address|.)singleline(?=[^\]\[]*\])%';
$output = preg_replace($pattern, "", $output);
EDIT:
You might want to use preg_quote if you had content you wanted to include in your regex pattern which contained characters used in regex syntax. For example:
$input = "item 1 -- total cost: $5.00";
$pattern = "/total cost: " . preg_quote("$5.00") . "/";
// $pattern should now be "/total cost: \$5.00/"
$output = preg_replace($pattern, 'five dollars', $input);
In this case, you need to escape the $ because it is used in the regex syntax. To search for it, your regex should use \$ instead of $. Using preg_quote performs this alteration for you.
I think you should apply preg_quote not for full pattern, bbut only for (maybe) external string. Look at this code:
<?php
$content = 'singleline';
$content = preg_quote($content);
$output = '<p>[#address|singleline]</p>';
$output = preg_replace('%(?<=#address|.)'.$content.'(?=[^\]\[]*\])%', "", $output);
echo $output;
As you can see I apply preg_quote only for $content variable (that might be with some characters which You need to escape)

Categories