I want to replace { by {{} and } by {}}, because, I need to escape those { & } with {}.
if I've as input {blah} I want my script to output {{}blah{}}, see?
But it is not working look at what I did
$output = str_replace(array("}", "{"), array("{}}", "{{}"), '{blah}');
But as output I got this : {{}blah{{}}} instead of {{}blah{}}
PHP iterates the whole string for each array item you put in the $search parameter.
It is in fact replacing '{blah}' into '{blah{}}' with your first array item '{', and then from that into '{{}blah{{}}}' because there is another '{' after the first replacement.
You better off doing this with regular expression, with a single RegExp pattern it will run only once in your input string.
$str = preg_replace('/(\{|\})/', '{\\1}', '{blah}');
That's because the replacement itself contains the string to search for. I would rewrite it with preg_replace_callback instead:
echo preg_replace_callback('/{|}/', function($match) {
return $match[0] == '{' ? '{{}' : '{}}';
}, '{bla}');
// {{}bla{}}
Related
I have a json and I need to match all "text" keys as well as the "html" keys.
For example, the json could be like below:
[{
"layout":12,
"text":"Lorem",
"html":"<div>Ipsum</div>"
}]
Or it could be like below:
[{
"layout":12,
"settings":{
"text":"Lorem",
"atts":{
"html":"<div>Ipsum</div>"
}
}
}]
The json is not always using the same structure so I have to match the keys and get their values using preg_match_all. I have tried the following to get the value of the "text" key:
preg_match_all('|"text":"([^"]*)"|',$json,$match_txt,PREG_SET_ORDER);
The above works fine for matching a single key. When it comes to matching a second key ("html" in this case) it just doesn't work. I have tried the following:
preg_match_all('|"text|html":"([^"]*)"|',$json,$match_txt,PREG_SET_ORDER);
Can you please give me some hints why the OR operator (text|html) doesn't work? Strangely, the above (multi-pattern) regex works fine when I test it in an online tester but it doesn't work in my php files.
Fixing text|html
You should add text|html to a group, otherwise it will look for "text or html".
|"(text|html)":"([^"]*)"|
Delimiters
This won't currently work with your delimiters though as you use the pipe (|) inside of the expression. You should change your delimiters to something else, here I've used /.
/"(text|html)":"([^"]*)"/
If you still want to use the pipe as your delimiters, you should escape the pipe within the expression.
|"(text\|html)":"([^"]*)"|
If you don't want to manually escape it, preg_quote() can do it for you.
$exp = preg_quote('"(text|html)":"([^"]*)"');
preg_match_all("|{$exp}|",$json,$match_txt,PREG_SET_ORDER);
Parsing JSON
Although that regex will work, it will need additional parsing and it makes more sense to use a recursive function for this.
json_decode() will decode a JSON string into the relative data types. In the example below I've passed an additional argument true which means I will get an associative array where you would normally get an object.
Once findKeyData() is called, it will recursively call itself and work through all of the data until it finds the specified key. If not, it returns null.
function findKeyData($data, $key) {
foreach ($data as $k => $v) {
if (is_array($v)) {
$data = findKeyData($v, $key);
if (! is_null($data)) {
return $data;
}
}
if ($k == $key) {
return $v;
}
}
return null;
}
$json1 = json_decode('[{
"layout":12,
"text":"Lorem",
"html":"<div>Ipsum</div>"
}]', true);
$json2 = json_decode('[{
"layout":12,
"settings":{
"text":"Lorem",
"atts":{
"html":"<div>Ipsum</div>"
}
}
}]', true);
var_dump(findKeyData($json1, 'text')); // Lorem
var_dump(findKeyData($json1, 'html')); // <div>Ipsum</div>
var_dump(findKeyData($json2, 'text')); // Lorem
var_dump(findKeyData($json2, 'html')); // <div>Ipsum</div>
preg_match_all('/"(?:text|html)":"([^"]*)"/',$json,$match_txt,PREG_SET_ORDER);
print $match_txt[0][0]." with group 1: ".$match_txt[0][1]."\n";
print $match_txt[1][0]." with group 1: ".$match_txt[1][1]."\n";
returns:
$ php -f test.php
"text":"Lorem" with group 1: Lorem
"html":"<div>Ipsum</div>" with group 1: <div>Ipsum</div>
The enclosing parentheses are needed : (?:text|html); I couldn't get it to work on https://regex101.com without. ?: means the content of the parentheses will not be captured (i.e., not available in the results).
I also replaced the pipe (|) delimiter with forward slashes since you also have a pipe inside the regex. Another option is to escape the pipe inside the regex: |"(?:text\|html)":"([^"]*)"|.
I don't see any reason to use a regex to parse a valid json string:
array_walk_recursive(json_decode($json, true), function ($v, $k) {
if ( in_array($k, ['text', 'html']) )
echo "$k -> $v\n";
});
demo
You use the Pipe | character as delimiter, I think this will break your regexp. Does it work using another delimiter like
preg_match_all('#"text|html":"([^"]*)"#',$json,$match_txt,PREG_SET_ORDER);
?
Small problem:
$content='/p test some text';
when "/p" is in front of the line the string should be exploded to an array
if(preg_match('^(/p)',$content)==true) {
$private=explode(" ",$content,3);
}
i think their is an error, but i've no idea for the correct search parameter
This should work for you:
(No need to compare it with true, because if it doesn't find anything it returns an empty array, which then is false. Also you need delimiters for your regex and escape the slash with a backslash)
$content='/p test some text';
if(preg_match('/^\/p/',$content)) {
//^ ^ See delimiters
$private=explode(" ",$content,3);
}
Why not a simple test
if ($content{0} == '/' && $content{1} == 'p' ) {
$private=explode(" ",$content,3);
}
I am using preg_match() to extract pieces of text from a variable, and let's say the variable looks like this:
[htmlcode]This is supposed to be displayed[/htmlcode]
middle text
[htmlcode]This is also supposed to be displayed[/htmlcode]
i want to extract the contents of the [htmlcode]'s and input them into an array. i am doing this by using preg_match().
preg_match('/\[htmlcode\]([^\"]*)\[\/htmlcode\]/ms', $text, $matches);
foreach($matches as $value){
return $value . "<br />";
}
The above code outputs
[htmlcode]This is supposed to be displayed[/htmlcode]middle text[htmlcode]This is also supposed to be displayed[/htmlcode]
instead of
[htmlcode]This is supposed to be displayed[/htmlcode]
[htmlcode]This is also supposed to be displayed[/htmlcode]
and if have offically run out of ideas
As explained already; the * pattern is greedy. Another thing is to use preg_match_all() function. It'll return you a multi-dimension array of matched content.
preg_match_all('#\[htmlcode\]([^\"]*?)\[/htmlcode\]#ms', $text, $matches);
foreach( $matches[1] as $value ) {
And you'll get this: http://codepad.viper-7.com/z2GuSd
A * grouper is greedy, i.e. it will eat everything until last [/htmlcode]. Try replacing * with non-greedy *?.
* is by default greedy, ([^\"]*?) (notice the added ?) should make it lazy.
What do lazy and greedy mean in the context of regular expressions?
Look at this piece of code:
preg_match('/\[htmlcode\]([^\"]*)\[\/htmlcode\]/ms', $text, $matches);
foreach($matches as $value){
return $value . "<br />";
}
Now, if your pattern works fine and all is ok, you should know:
return statement will break all loops and will exit the function.
The first element in matches is the whole match, the whole string. In your case $text
So, what you did is returned the first big string and exited the function.
I suggest you can check for desired results:
$matches[1] and $matches[2]
I have string as abvd.qweqw.sdfs.a=aqwrwewrwerrew. I need to parse this string and get piece before = and after =. Symbol . can occur many times. So, please, tell me, which regular expression can I use for parsing? Thank you.
Purely based on your example:
/([a-z.]+)=([a-z]+)/
Edit
But actually:
/([a-z_.]+)=(.*)/i
The results are in memory groups 1 and 2. In code:
if (preg_match('/^([a-z_.]+)=(.*)/i', $str, $matches)) {
// $matches[1] contains part before =
// $matches[2] contains part after =
}
Btw, I've tweaked the expression by anchoring it (using ^). If that doesn't work, just remove it from the expression.
You can use simple string function for that.
list($first, $second) = explode('=', 'abvd.qweqw.sdfs.a=aqwrwewrwerrew);
Thats the full code.
<?php
if(preg_match('/([a-z.]+)=([a-z]+)/', "abvd.qweqw.sdfs.a=aqwrwewrwerrew", $matches)){
print $matches[1]."\n";
print $matches[2]."\n";
}
?>
I have a string like this:
http://mysite.com/script.php?fruit=apple
And I have an associative array like this:
$fruitArray["apple"] = "green";
$fruitArray ["banana"] = "yellow";
I am trying to use preg_replace on the string, using the key in the array to back reference apple and replace it with green, like this:
$string = preg_replace('|http://mysite.com/script.php\?fruit=([a-zA-Z0-9_-]*)|', 'http://mysite.com/'.$fruitArray[$1].'/', $string);
The process should return
http://mysite.com/green/
Obviously this isn’t working for me; how can I manipulate $fruitArray[$1] in the preg_replace statement so that the PHP is recognised, back referenced, and replaced with green?
Thanks!
You need to use the /e eval flag, or if you can spare a few lines preg_replace_callback.
$string = preg_replace(
'|http://mysite.com/script.php\?fruit=([a-zA-Z0-9_-]*)|e',
' "http://mysite.com/" . $fruitArray["$1"] ',
$string
);
Notice how the whole URL concatenation expression is enclosed in single quotes. It will be interpreted as PHP expression later, the spaces will vanish and the static URL string will be concatenated with whatever is in the fruitArray.