There is a string in format:
else if($rule=='somerule1')
echo '{"s":1,"n":"name surname"}';
else if($rule=='somerule2')
echo '{"s":1,"n":"another text here"}';
...
"s" can have only number, "n" any text.
In input I have $rule value, and I need to remove the else if block that corresponds to this value. I am trying this:
$str = preg_replace("/else if\(\$rule=='$rule'\)\necho '{\"s\":[0-9],\"n\":\".*\"/", "", $str);
where $str is a string, that contains blocks I mentioned above, $rule is a string with rule I need to remove. But the function returns $str without changes.
What do I do wrong?
For example, script to change "s" value to 1 works nice:
$str = preg_replace("/$rule'\)\necho '{\"s\":[0-9]/", $rule."')\necho '{\"s\":1", $str);
So, probably, I am doing mistake with = symbol, or maybe with space, or with .*.
The regex pattern can be much less strict, much simpler, and far easier to read/maintain.
You need to literally match the first line (conditional expression) with the only dynamic component being the $rule variable, then match the entire line that immediately follows it.
Code: (Demo)
$contents = <<<'TEXT'
else if($rule=='somerule1')
echo '{"s":1,"n":"name surname"}';
else if($rule=='somerule2')
echo '{"s":1,"n":"another text here"}';
TEXT;
$rule = "somerule1";
echo preg_replace("~\Qelse if(\$rule=='$rule')\E\R.+~", "", $contents);
Output:
else if($rule=='somerule2')
echo '{"s":1,"n":"another text here"}';
So, what have I done? Here's the official pattern demo.
\Q...\E means "treat everything in between these two metacharacters literally"
Then the only character that needs escaping is the first $, this is not to stop it from being interpreted as a end-of-string metacharacter, but as the start of the $rule variable because the pattern is wrapped in double quotes.
The second occurrence of $rule in the pattern DOES need to be interpreted as the variable so it is not escaped.
The \R is a metacharacter which means \n, \r and \r\n
Finally match all of the next line with the "any character" . with a one or more quantifier (+).
The pattern does not match because you have to use a double escape to match the backslash \\\$.
Apart from that, you are not matching the whole line as this part ".*\" stops at the double quote before }';
$str = 'else if($rule==\'somerule1\')
echo \'{"s":1,"n":"name surname"}\';
else if($rule==\'somerule2\')
echo \'{"s":1,"n":"another text here"}\';';
$rule = "somerule1";
$pattern = "/else if\(\\\$rule=='$rule'\)\necho '{\"s\":\d+,\"n\":\"[^\"]*\"}';/";
$str = preg_replace($pattern, "", $str);
echo $str;
Output
else if($rule=='somerule2')
echo '{"s":1,"n":"another text here"}';
Php demo
Related
I am newbie in PHP. I want to replace certain characters in a string. My code is in below:
$str="this 'is' a new 'string and i wanna' replace \"in\" \"it here\"";
$find = [
'\'',
'"'
];
$replace = [
['^', '*']
['#', '#']
];
$result = null;
$odd = true;
for ($i=0; $i < strlen($str); $i++) {
if (in_array($str[$i], $find)) {
$key = array_search($str[$i], $find);
$result .= $odd ? $replace[$key][0] : $replace[$key][1];
$odd = !$odd;
} else {
$result .= $str[$i];
}
}
echo $result;
the output of the above code is:
this ^is* a new ^string and i wanna* replace #in# #it here#.
but I want the output to be:
this ^is* a new 'string and i wanna' replace #in# "it here".
That means character will replace for both quotation(left quotation and right quotation- condition is for ' and "). for single quotation, string will not be replaced either if have left or right quotation. it will be replaced for left and right quotation.
Ok, I don't know what all that code is trying to accomplish.
But anyway here is my go at it
$str = "this 'is' a new 'string and i wanna' replace \"in\" \"it here\"";
$str = preg_replace(["/'([^']+)'/",'/"([^"]+)"/'], ["^$1*", "#$1#"], $str, 1);
print_r($str);
You can test it here
Ouptput
this ^is* a new 'string and i wanna' replace #in# "it here"
Using preg_replace and a fairly simple Regular expression, we can replace the quotes. Now the trick here is the fourth parameter of preg_replace is $count And is defined as this:
count If specified, this variable will be filled with the number of replacements done.
Therefore, setting this to 1 limits it to the first match only. In other words it will do $count replacements, or 1 in this case. Now because it's an array of patterns, each pattern is treated separately. So each one is basically treated as a separate operation, and thus each is allowed $count matches, or each get 1 match/replacement.
Now rather or not this fits every use case you have I cannot say, but it's the most straight forward way to do it for the example you provided.
As for the match itself /'([^']+)'/
/ opening and closing "delimiters" for the Expression (its a required thing, although it doesn't have to be /)
' literal match, matches ' one time (the opening quote)
( ... ) capture group (group1) so we can use it in the replacement, as $1
[^']+ character set with a [^ not modifier, match anything not in the set, so anything that is not a ' one or more times, greedy
' literal match, matches ' one time (the ending quote)
The replacement "^$1*"
^ literal, adds this char in
$1 use the contents of the capture group (group1)
* literal, adds the char in
Hope that helps understand how it works.
UPDATE
Ok I think I finally deciphered what you want:
string will be replaced for if any word have left and right quotation. example..'word'..here string will be changed..but 'word...in this case not change or word' also not be changed.
This seems like you are trying to say only "whole" words with no spaces.
So in that case we have to adjust our regular expression like this:
$str = preg_replace(["/'([-\w]+)'/",'/"([-\w]+)"/'], ["^$1*", "#$1#"], $str);
So we removed the limit $count and we changed what is in the character group to be more strict:
[-\w]+ the \w means the working set, or in other words a-zA-Z0-9_ then the - is a literal (it has to/should go first in this case)
What we are saying with this is to match only strings that start and end with a quote(single|double) and only if the string within them match the working set plus the hyphen. This does not include the space. This way in the first case, your example, it produces the same result, but if you were to flip it to
//[ORIGINAL] this 'is' a new 'string and i wanna' replace \"in\" \"it here\"
this a new 'string and i wanna' replace 'is' \"it here\" \"in\"
You would get his output
this a new 'string and i wanna' replace ^is* \"it here\" #in#
Before this change you would have gotten
this a new ^string and i wanna* replace 'is' #it here# "in"
In other words it would have only replaced the first occurrence, now it will replace anything between the quotes if and only if it's a whole word.
As a final note you can be even more strict if you only want alpha characters by changing the character set to this [a-zA-Z]+, then it will match only a to z, upper or lower case. Whereas the example above will match 0 to 9 (or any combination of them) the - hyphen, the _ underline and the previously mentioned alpha sets.
Hope that is what you need.
I have a file that contains a collection strings. All of the strings begin with the same set of characters and end with the same character. I need to find all of the strings that match a certain pattern, and then remove particular characters from them before saving the file. Each string looks like this:
Data_*: " ... "
where Data_ is the same for each string, the asterisk is an incrementing integer that is either two or three digits, and the colon and the double quotation marks are the same for each string. The ... is completely different in every string and it's the part of each I need to work with. I need to remove all double quotation marks from the ... , preserving the enclosing double quotation marks. I don't need to replace them, just remove them.
So for example, I need this...
Data_83: "He said, "Yes!" to the question"
to become this...
Data_83: "He said, Yes! to the question"
I am familiar with PHP and would like to use this. I know how to do something like...
<?php
$filename = 'path/to/file';
$content = file_get_contents($filename);
$new_content = str_replace('"', '', $content);
file_put_contents($filename, $new_content);
And I'm pretty sure a regular expression will be what I'm wanting to use to find the strings and remove the extra double quotation marks. But I'm very new to regular expressions and need some help here.
EDIT:
I should have mentioned, the file is a PHP file containing an object. It looks a bit like this:
<?php
$thing = {
Data_83: "He said, "Yes!" to the question",
Data_84: "Another string with "unwanted" quotes"
}
You may use preg_replace_callback with a regex like
'~^(\h*Data_\d{2,}:\h*")(.*)"~m'
Note that you may make it safer if you specify an optional , at the end of the line: '~^(\h*Data_\d{2,}:\h*")(.*)",?\h*$~m' but you might need to introduce another capturing group then (around ,?\h*, and then append $m[3] in the preg_replace_callback callback function).
Details
^ - start of the line (m is a multiline modifier)
(\h*Data_\d{2,}:\h*") - Group 1 ($m[1]):
\h* - 0+ horizontal whitespaces
Data_ - Data_ substring
\d{2,} - 2 or more digits
: - a colon
\h* - 0+ horizontal whitespaces
" - double quote
(.*) - Group 2 ($m[2]): any 0+ chars other than line break chars, as many as possible, up to the last...
" - double quote (on a line).
The $m represents the whole match object, and you only need to remove the " inside $m[2], the second capture.
See the PHP demo:
preg_replace_callback('~^(\h*Data_\d{2,}:\h*")(.*)"~m', function($m) {
return $m[1] . str_replace('"', '', $m[2]) . '"';
}, $content);
Not as elegant but you could create a UDF:
function RemoveNestedQuotes($string)
{
$firstPart = explode(":", $string)[0];
preg_match('/"(.*)"/', $string, $matches, PREG_OFFSET_CAPTURE);
$tmpString = $matches[1][0];
return $firstPart . ': "' . preg_replace('/"/', '', $tmpString) . '"';
}
example:
$string = 'Data_83: "He said, "Yes!" to the question"';
echo RemoveNestedQuotes($string);
// Data_83: "He said, Yes! to the question"
One more step after str_replace with implode and explode. You can just do it like this.
<?php
$string = 'Data_83: "He said, "Yes!" to the question"';
$string = str_replace('"', '', $string);
echo $string =implode(': "',explode(': ',$string)).'"';
?>
Demo : https://eval.in/912466
Program Output
Data_83: "He said, Yes! to the question"
Just to replace " quotes
<?php
$string = 'Data_83: "He said, "Yes!" to the question"';
echo preg_replace('/"/', '', $string);
?>
Demo : https://eval.in/912457
The way I see it, you don't need to make any preg_replace_callback() calls or a convoluted run of explosions and replacements. You merely need to disqualify the 2 double quotes that you wish to retain and match the rest for removal.
Code: (Demo)
$string = 'Data_83: "He said, "Yes!" to the question",
Data_184: "He said, "WTF!" to the question"';
echo preg_replace('/^[^"]+"(*SKIP)(*FAIL)|"(?!,\R|$)/m','',$string);
Output:
Data_83: "He said, Yes! to the question",
Data_184: "He said, WTF! to the question"
Pattern Demo
/^[^"]+"(*SKIP)(*FAIL)|"(?!,?$)/m
This pattern says:
match from the start of each line until you reach the first double quote, then DISQUALIFY it.
then after the |, match all double quotes that are not optionally followed by a comma then the end of line.
While this pattern worked on regex101 with my sample input, when I transferred it to the php sandbox to whack together a demo, I needed to add \R to maintain accuracy. You can test to see which is appropriate for your server/environment.
This is the code:
<?php
$pattern =' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$text = "kdaiuyq7e611422^^$^vbnvcn^vznbsjhf";
$text_split = str_split($text,1);
$data = '';
foreach($text_split as $value){
if (preg_match("/".$value."/", $pattern )){
$data = $data.$value;
}
if (!preg_match('/'.$value.'/', $pattern )){
break;
}
}
echo $data;
?>
Current output:
kdaiuyq7e611422^^$^vbnvcn^vznbsjhf
Expected output:
kdaiuyq7e611422
Please help me editing my code error. In pattern there is no ^ or $. But preg_match is showing matched which is doubtful.
You string $text have ^ which will match the begin of the string $pattern.
So the preg_match('/^/', $pattern) will return true, then the ^ will append to $data.
You should escape the ^ as a raw char, not a special char with preg_match('/\^/', $pattern) by the help of preg_quote() which will escape the special char.
There is no need to split your string up like that, the whole point of a regular expression is you can specify all the conditions within the expression. You can condense your entire code down to this:
$pattern = '/^[[:word:] ]+/';
$text = 'kdaiuyq7e611422^^$^vbnvcn^vznbsjhf';
preg_match($pattern, $text, $matches);
echo $matches[0];
Kris has accurately isolated that escaping in your method is the monkey wrench. This can be solved with preg_quote() or wrapping pattern characters in \Q ... \E (force characters to be interpreted literally).
Slapping that bandaid on your method (as you have done while answering your own question) doesn't help you to see what you should be doing.
I recommend that you do away with the character mask, the str_split(), and the looped calls of preg_match(). Your task can be accomplished far more briefly/efficiently/directly with a single preg_match() call. Here is the clean way that obeys your character mask fully:
Code: (Demo)
$text = "kdaiuyq7e611422^^$^vbnvcn^vznbsjhf";
echo preg_match('/^[a-z\d ]+/i',$text,$out)?$out[0]:'No Match';
Output:
kdaiuyq7e611422
miknik's method was close to this, but it did not maintain 100% accuracy given your question requirements. I'll explain:
[:word:] is a POSIX Character Class (functioning like \w) that represents letters(uppercase and lowercase), numbers, and an underscore. Unfortunately for miknik, the underscore is not in your list of wanted characters, so this renders the pattern slightly inaccurate and may be untrustworthy for your project.
I am working with a slug function and I dont fully understand some of it and was looking for some help on explaining.
My first question is about this line in my slug function $string = preg_replace('# +#', '-', $string); Now I understand that this replaces all spaces with a '-'. What I don't understand is what the + sign is in there for which comes after the white space in between the #.
Which leads to my next problem. I want a trim function that will get rid of spaces but only the spaces after they enter the value. For example someone accidentally entered "Arizona " with two spaces after the a and it destroyed the pages linked to Arizona.
So after all my rambling I basically want to figure out how I can use a trim to get rid of accidental spaces but still have the preg_replace insert '-' in between words.
ex.. "Sun City West " = "sun-city-west"
This is my full slug function-
function getSlug($string){
if(isset($string) && $string <> ""){
$string = strtolower($string);
//var_dump($string); echo "<br>";
$string = preg_replace('#[^\w ]+#', '', $string);
//var_dump($string); echo "<br>";
$string = preg_replace('# +#', '-', $string);
}
return $string;
}
You can try this:
function getSlug($string) {
return preg_replace('#\s+#', '-', trim($string));
}
It first trims extra spaces at the beginning and end of the string, and then replaces all the other with the - character.
Here your regex is:
#\s+#
which is:
# = regex delimiter
\s = any space character
+ = match the previous character or group one or more times
# = regex delimiter again
so the regex here means: "match any sequence of one or more whitespace character"
The + means at least one of the preceding character, so it matches one or more spaces. The # signs are one of the ways of marking the start and end of a regular expression's pattern block.
For a trim function, PHP handily provides trim() which removes all leading and trailing whitespace.
I'm trying to use regular expressions (preg_match and preg_replace) to do the following:
Find a string like this:
{%title=append me to the title%}
Then extract out the title part and the append me to the title part. Which I can then use to perform a str_replace(), etc.
Given that I'm terrible at regular expressions, my code is failing...
preg_match('/\{\%title\=(\w+.)\%\}/', $string, $matches);
What pattern do I need? :/
I think it's because the \w operator doesn't match spaces. Because everything after the equal sign is required to fit in before your closing %, it all has to match whatever is inside those brackets (or else the entire expression fails to match).
This bit of code worked for me:
$str = '{%title=append me to the title%}';
preg_match('/{%title=([\w ]+)%}/', $str, $matches);
print_r($matches);
//gives:
//Array ([0] => {%title=append me to the title%} [1] => append me to the title )
Note that the use of the + (one or more) means that an empty expression, ie. {%title=%} won't match. Depending on what you expect for white space, you might want to use the \s after the \w character class instead of an actual space character. \s will match tabs, newlines, etc.
You can try:
$str = '{%title=append me to the title%}';
// capture the thing between % and = as title
// and between = and % as the other part.
if(preg_match('#{%(\w+)\s*=\s*(.*?)%}#',$str,$matches)) {
$title = $matches[1]; // extract the title.
$append = $matches[2]; // extract the appending part.
}
// find these.
$find = array("/$append/","/$title/");
// replace the found things with these.
$replace = array('IS GOOD','TITLE');
// use preg_replace for replacement.
$str = preg_replace($find,$replace,$str);
var_dump($str);
Output:
string(17) "{%TITLE=IS GOOD%}"
Note:
In your regex: /\{\%title\=(\w+.)\%\}/
There is no need to escape % as its
not a meta char.
There is no need to escape { and }.
These are meta char but only when
used as a quantifier in the form of
{min,max} or {,max} or {min,}
or {num}. So in your case they are treated literally.
Try this:
preg_match('/(title)\=(.*?)([%}])/s', $string, $matches);
The match[1] has your title and match[2] has the other part.