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:
"$_" [$_]
Related
I am trying to replace some text if it isn't preceded with a dot (.), but my function seems to result include an unexpected slash ...
<?php
$test="function insertXYZ(e){e.insertXYZ()};";
$search="insertXYZ(";
$replace="zzzz(";
$search=str_replace("(", '\(', $search);
//echo $search."\n\n";
$pattern = '\b' . $search;
$replaceException="999";
$test=preg_replace('/' . "\.".$pattern . '/', "$replaceException", $test);
$test=preg_replace('/' . $pattern . '/', $replace, $test);
$test=preg_replace('/' . $replaceException . '/', ".$search", $test);
echo $test;
?>
A sample of this code can be found at http://sandbox.onlinephpfunctions.com/code/24cab4eece20d22a11dd887da44d63e393b51aa9
which outputs...
function zzzz(e){e.insertXYZ\()};
^
but I want the output to read...
function zzzz(e){e.insertXYZ()};
^
Where am I going wrong?
It's because in this line, you're adding the backslash and then never remove it
$search=str_replace("(", '\(', $search);
You could change your code to the following so that you don't need to manually escape this bracket.
// $search=str_replace("(", '\(', $search); <-- Removed
$pattern = '\b' . preg_quote($search);
However, you could get the same output with much less code
$testString = "function insertXYZ(e){e.insertXYZ()};";
$regex = "/[^.](insertXYZ)/s";
echo(preg_replace($regex, " zzzz", $testString));
[^.] - Character group looking where there's NOT a dot character
(insertXYZ) - matches 'insertXYZ' exactly (case sensitive)
/s - Single line modifier so there's no need to escape the dot character
I need to replace all double quotes in any (variable) given string.
For example:
$text = 'data-caption="hello"world">';
$pattern = '/data-caption="[[\s\S]*?"|(")]*?">/';
$output = preg_replace($pattern, '"', $text);
should result in:
"hello"world"
(The above pattern is my attempt at getting it to work)
The problem is that I don't now in advance if and how many double quotes are going to be in the string.
How can i replace the " with quot; ?
You may match strings between data-caption=" and "> and then replace all " inside that match with " using a mere str_replace:
$text = 'data-caption="<element attribute1="wert" attribute2="wert">Name</element>">';
$pattern = '/data-caption="\K.*?(?=">)/';
$output = preg_replace_callback($pattern, function($m) {
return str_replace('"', '"', $m[0]);
}, $text);
print_r($output);
// => data-caption="<element attribute1="wert" attribute2="wert">Name</element>">
See the PHP demo
Details
data-caption=" - starting delimiter
\K - match reset operator
.*? - any 0+ chars other than line break chars, as few as possible
(?=">) - a positive lookahead that requires the "> substring immediately to the right of the current location.
The match is passed to the anonymous function inside preg_replace_callback (accessible via $m[0]) and that is where it is possible to replace all " symbols in a convenient way.
Looking for a php regex that will allow me to separate out certain characters from words (if they're sticking to the left or right of the word, or even anywhere within the word).
For example,
hello. -> hello .
.hello -> . hello
hello.hello -> hello . hello
I have the below code but it won't work for all cases. Please note that $value could be '.', '?', or any character.
$regex = "/(?<=\S)\\" . $value . "|\\" . $value . "(?=\S)/";
$this->str = preg_replace_callback($regex, function($word) {
return ' ' . $word[0];
}, $this->str);
Also, please help with specifying the part where I can turn on (or off) the 3rd condition.
[UPDATE]
I think there might be confusion about exact requirements. Let me try to be more specific. I want a regex which will help me seperate out certain characters which are either at the end or the beginning of a group of text. What is group of text? Group of text could be any length (>=1) and contain any characters however it must begin with a-z or 0-9. Again, would be nice if this aspect would be highlighted in solution so that if we want group of text to begin&end with more characters (not just a-z or 0-9) it's possible.
$character = '.', string is ".hello.world." => ". hello.world ."
$character = '.', string is ".1ello.worl2." => ". 1ello.worl2 ."
$character = '.', string is ".?1ello.worl2." => ".?1ello.worl2 ."
$character = '.', string is "4/5.5" => "4/5.5"
$character = '.', string is "4.?1+/5" => "4.?1+/5"
$character = '.', string is ".4/5.5." => ". 4/5.5 ."
$character = '/', string is ".hello?.world/" => ".hello?.world /"
$character = '/', string is ".hello?.worl9/" => ".hello?.worl9 /"
Hope, its more clear now.
You can use 3 alternatives each captured into its own capture group, and use a preg_replace_callback to apply the corresponding replacement:
$wrd = ".";
$re = '~(?<=\S)(' . preg_quote($wrd) . ')(?=\S)|(?<=\S)(' . preg_quote($wrd) . ')|(' . preg_quote($wrd) . ')(?=\S)~';
$str = "hello.\n.hello\nhello.hello";
$result = preg_replace_callback($re, function($m) {
if (!empty($m[1])) {
return " " . $m[1] . " ";
} else if (!empty($m[2])) {
return " " . $m[2];
} else return $m[3] . " ";
}, $str);
echo $result;
See the IDEONE demo
The regex will be
(?<=\S)(\.)(?=\S)|(?<=\S)(\.)|(\.)(?=\S)
| 1| | 2| | 3|
See regex demo
The first group is your Case 3 (hello.hello -> hello . hello), the second group is your Case 1 (hello. -> hello .) and the third group singals your Case 2 (.hello -> . hello).
UPDATE (handling exceptions)
If you have exceptions, you can add more capturing groups. E.g., you want to protect the dot in float numbers. Add a (\d\.\d) alternative, and check inside the callback function if it is not empty. If not, just restore it with return $m[n]:
$wrd = ".";
$re = '~(\d\.\d)|(?<=\S)(' . preg_quote($wrd) . ')(?=\S)|(?<=\S)(' . preg_quote($wrd) . ')|(' . preg_quote($wrd) . ')(?=\S)~';
$str = "hello.\n.hello\nhello.hello\nhello. 3.5/5\nhello.3\na./b";
$result = preg_replace_callback($re, function($m) {
if ( !empty($m[1])) { // The dot as a decimal separator
return $m[1]; // No space is inserted
}
else if (!empty($m[2])) { // A special char is enclosed with non-spaces
return " " . $m[2] . " "; // Add spaces around
} else if (!empty($m[3])) { // A special char is enclosed with non-spaces
return " " . $m[3]; // Add a space before the special char
} else return $m[4] . " "; // A special char is followed with a non-space, add a space on the right
}, $str);
echo $result;
See an updated code demo
Another code demo - based on matching locations before and after the . that are not enclosed with spaces (and protecting a float value) (based on #bobblebubble's solution (deleted)):
$wrd = ".";
$re = '~(\d\.\d)|(?<!\s)(?=' . preg_quote($wrd) . ')|(?<=' . preg_quote($wrd) . ')(?!\s)~';
$str = "hello.\n.hello\nhello.hello\nhello. 3.5/5\nhello.3\na./b";
$result = preg_replace_callback($re, function($m) {
if ( !empty($m[1])) { // The dot as a decimal separator
return $m[1]; // No space is inserted
}
else return " "; // Just insert a space
}, $str);
echo $result;
SUMMARY:
You cannot use \b since your . / ? etc. can appear in mixed "word" and "non-word" contexts
You need to use capturing and preg_replace_callback since there are different replacement schemes
You can use a regex based on word boundaries.
\b(?=\.(?!\S))|(?<=(?<!\S)\.)\b
Would match the boundary (zero-width) between a word and a literal dot if not followed by a non-whitespace \S or not preceded by a non-whitespace using lookarounds to check.
See demo at regex101. Use in a PHP function with value parameter and replace with space.
// $v = character
function my_func($str, $v=".")
{
$v = preg_quote($v, '/');
return preg_replace('/\b(?='.$v.'(?!\S))|(?<=(?<!\S)'.$v.')\b/', " ", $str);
}
PHP demo at eval.in
From what I understand the . can be any non-word character. If that's the case, try this:
$patron = '/(\W+)/';
$this->str = trim(preg_replace($patron, ' $1 ', $this->str));
(\s?[.]\s?)
If you use the above regex, you can simply replace all the matches with " . "
How it works:
I used \s? to capture a leading and trailing whitespace, if there is any.
[.] is a char class, so you should add all of the "certain characters" you want to find.
A regex that catches the first 2 conditions and never the third is (\s[.]\s?|\s?[.]\s). (Again, you'll need to replace the capture with " . ", and also add your "certain characters" to the char classes.)
You can then choose which regex you will use.
I have a generic routine which used to substitute out short-codes (which begin with a "^" character) with gender specific options. I have been asked to extend this to correct some common misspellings. These words won't have a special character at the start.
Until now I have been using PHP's str_replace function but because of the possibility of some words appearing within others, I need to ensure that the code uses word boundaries when matching. I am now attempting to use preg_replace.
While the actual code is getting data from a database table, including the gender specific replacements, I can reproduce the issue with simpler code for the purposes of asking this question.
Consider the following array with $search => $replace structure:
$subs = array("^Heshe" => "He",
"apples" => "bananas");
I then want to cycle through the array to replace the tokens:
$message = "^Heshe likes apples but not crabapples.";
foreach ($subs as $search => $replace)
{
$pattern = '/\b' . preg_quote($search, '/') . '\b/u';
$message = preg_replace($pattern, $replace, $message);
}
echo $message;
I expect the message He likes bananas but not crabapples. to be displayed, but instead I get the message ^Heshe likes bananas but not crabapples.
I have also tried $pattern = '/\b\Q' . $search . '\E\b/u', also with the same results.
Unfortunately, the "^" characters are part of some legacy system and changing it is not feasible. How do I get the regex to work?
Problem is this line:
$pattern = '/\b' . preg_quote($search, '/') . '\b/u';
As $search is ^Heshe you cannot match \b (word boundary) before ^ since that is not a word character.
You can use lookarounds instead in your pattern like this:
$pattern = '/(?<!\w)' . preg_quote($search, '/') . '(?!\w)/u';
Which means match $search if it is not followed and preceded by a word char.
Or else use:
$pattern = '/(?<=\s|^)' . preg_quote($search, '/') . '(?=\s|$)/u';
Which means match $search if it is followed and preceded by a whitespace or line start/end.
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);