preg_replace Pattern - php

i'm not very firm with preg_replace - in other Words i do not really understand - so i hope you can help me.
I have a string in a Text like this one: [demo category=1] and want to replace with the Content of Category (id=1) e.g. "This is the Content of my first Category"
This is my startpoint Pattern - that's all i have:
'/[demo\s*.*?]/i';
Hope you can help?

Firstly, you need to escape the square brackets as they are special characters in PCREs:
'/\[demo\s*.*?\]/i';
Secondly, it sounds like you want to do something with the digit at the end, so you'll want to capture it using parenthesis:
'/\[demo\s*.*?=(\d+)\]/i';
The braces will capture \d+ and store it in a reference. \d+ will match a string of numbers only.
Finally, it sounds like you need to use preg_replace_callback to perform a special function on the matches in order to get the string you want:
function replaceMyStr($matches)
{
$strNum = array("1"=>"first", "2"=>"second", "3"=>"third"); // ...etc
return "This is the Content of my ".$strNum($matches[1])." Category.";
// $matches[1] will contain the captured number
}
preg_replace_callback('/\[demo\s*.*?=(\d+)\]/i', "replaceMyStr", "[demo category=1]");

further to the above answers, you have 2 ways to do the actual replacing. assuming you have 10 category names you want to replace, you can either do something like
for ($i = 1; $i <= $max_category; $i++) {
$category_name = get_category_name($i);
$s = preg_replace("/\[demo\s+category=(\d+)\]/i", $category_name, $s);
}
or
$s = preg_replace_callback("/\[demo\s+category=(\d+)\]/i", "get_category_name", $s);
in both cases, get_category_name($id) is a function that will get a category name for an id. you should test both options to evaluate which is faster for your uses.

The pattern is going to be like this
/\[demo\s+category=(\d+)\]/i'
(you need to escape brackets because they're special)

The [ and ] characters have special meaning (they denote character classes - ranges and collections of character). You need to escape [ as \[ (and evidently in PHP, unlike other regex flavors, you also need to escape ]). Also I suggest you make use of the character class [^]] = match any character that is not a ]
/\[demo\s+[^]]*\]/i
should work better.
Edit: If you want to extract the name and number, then you can use
/\[demo\s+(\w+)\s*=\s*(\d+)\]/i

Related

preg_replace - similar patterns

I have a string that contains something like "LAB_FF, LAB_FF12" and I'm trying to use preg_replace to look for both patterns and replace them with different strings using a pattern match of;
/LAB_[0-9A-F]{2}|LAB_[0-9A-F]{4}/
So input would be
LAB_FF, LAB_FF12
and the output would need to be
DAB_FF, HAD_FF12
Problem is, for the second string, it interprets it as "LAB_FF" instead of "LAB_FF12" and so the output is
DAB_FF, DAB_FF
I've tried splitting the input line out using 2 different preg_match statements, the first looking for the {2} pattern and the second looking for the {4} pattern. This sort of works in that I can get the correct output into 2 separate strings but then can't combine the two strings to give the single amended output.
\b is word boundary. Meaning it will look at where the word ends and not only pattern match.
https://regex101.com/r/upY0gn/1
$pattern = "/\bLAB_[0-9A-F]{2}\b|\bLAB_[0-9A-F]{4}\b/";
Seeing the comment on the other answer about how to replace the string.
This is one way.
The pattern will create empty entries in the output array for each pattern that fails.
In this case one (the first).
Then it's just a matter of substr.
$re = '/(\bLAB_[0-9A-F]{2}\b)|(\bLAB_[0-9A-F]{4}\b)/';
$str = 'LAB_FF12';
preg_match($re, $str, $matches);
var_dump($matches);
$substitutes = ["", "DAB", "HAD"];
For($i=1; $i<count($matches); $i++){
If($matches[$i] != ""){
$result = $substitutes[$i] . substr($matches[$i],3);
Break;
}
}
Echo $result;
https://3v4l.org/gRvHv
You can specify exact amounts in one set of curly braces, e.g. `{2,4}.
Just tested this and seems to work:
/LAB_[0-9A-F]{2,4}/
LAB_FF, LAB_FFF, LAB_FFFF
EDIT: My mistake, that actually matches between 2 and 4. If you change the order of your selections it matches the first it comes to, e.g.
/LAB_([0-9A-F]{4}|[0-9A-F]{2})/
LAB_FF, LAB_FFFF
EDIT2: The following will match LAB_even_amount_of_characters:
/LAB_([0-9A-F]{2})+/
LAB_FF, LAB_FFFF, LAB_FFFFFF...

regular expression gone wrong

I want to find all strings looking like [!plugin=tesplugin arg=dfd arg=2!] and put them in array.
Important feature: the string could contain arg=uments or NOT(in some cases). and of course there could be any number of arg's. So the string could look like:
[!plugin=myname!] or [!plugin=whatever1 arg=22!] or even [!plugin=gal-one arg=1 arg=text arg=tx99!]. I need to put them all in $strarray items
Here is what i did...
$inp = "[!plugin=tesplugin arg=dfd!] sometxt [!plugin=second arg=1 arg=2!] 1sd";
preg_match_all('/\[!plugin=[a-z0-9 -_=]*!]/i', $inp, $str);
but $str[0][0] contains:
[!plugin=tesplugin arg=dfd!] sometxt [!plugin=second arg=1 arg=2!]
instead of putting each expression in a new array item..
I think my problem in regex.. but can't find one. Plz help...
The last ] needs to be escaped and the - in the character class needs to be at the start, end, or escaped. As is it is a range of ascii characters between a space and underscore.
\[!plugin=[a-z0-9 \-_=]*!\]
Regex101 Demo: https://regex101.com/r/zV4bO2/1

Matches text inside brackets with Regex in PHP

I have some text like:
name: [my_name]
email: [my_email]
I'd like to grab the fields in square brackets with regex—how would I do that?
I've tried using this pattern: [*.?]
Unfortunately it doesn't work. PHP gives this error:
compilation failed: nothing to repeat at offset 0
What's wrong? Is the pattern correct?
The brackets are special characters in regex. To match them you'll have to escape them with a back-slash. Something like \[(.*?)\]. Adding the parens () captures whatever is matched inside it so you you can use it later. Otherwise you're just matching on the whole pattern and you'd have to manually strip the brackets.
You should move the * and escape the [ and ]. So make it \[.*\] Since . matches any character already and * says: 0 or more of that char. So .* is 0 or more of any char
No, you got the order wrong. It should be something like
\[(.*)\]
.* = Something repeated as many times as possible.
The compilation error you get is because the compiler does not now what to repeat, as [ is a special character in regular expressions. The ? you added would also allow nothing within the brackets, which I figured you don't want, so I removed it. The question mark makes the foregoing statement optional. The parentheses aroudn the .* are used to capture the result. If you don't add those, the regex will match, but you won't get whats inside the brackets as result.
<?php
$text =
"name: [my_name]
email: [my_email]";
$pattern = '/\[(.*)\]/';
$matches = array();
preg_match_all($pattern, $text, $matches);
$name = $matches[1][0];
$email = $matches[1][1];
print "$name<br />";
print "$email";
?>
will output
my_name
my_email
/ is the delimiter (not part of the actual pattern per se). The \ is for escaping the [ and ] brackets, as they define character class definitions in patterns when not escaped. ( and ) define subpatterns, which means that text captured by a subpattern will be put into the array referenced by the third parameter of preg_match_all (in this case $matches).
Escape it!
[ and ] special characters, so you need to escape them:
\[*.?\]

regex to find all text after delimited string

I have some content that contains a token string in the form
$string_text = '[widget_abc]This is some text. This is some text, etc...';
And I want to pull all the text after the first ']' character
So the returned value I'm looking for in this example is:
This is some text. This is some text, etc...
preg_match("/^.+?\](.+)$/is" , $string_text, $match);
echo trim($match[1]);
Edit
As per author's request - added explanation:
preg_match(param1, param2, param3) is a function that allows you to match a single case scenario of a regular expression that you're looking for
param1 = "/^.+?](.+?)$/is"
"//" is what you put on the outside of your regular expression in param1
the i at the end represents case insensitive (it doesn't care if your letters are 'a' or 'A')
s - allows your script to go over multiple lines
^ - start the check from the beginning of the string
$ - go all the way to end of the string
. - represents any character
.+ - at least one or more characters of anything
.+? - at least one more more characters of anything until you reach
.+?] - at least one or more characters of anything until you reach ] (there is a backslash before ] because it represents something in regular expressions - look it up)
(.+)$ - capture everything after ] and store it as a seperate element in the array defined in param3
param2 = the string that you created.
I tried to simplify the explanations, I might be off, but I think I'm right for the most part.
The regex (?<=]).* will solve this problem if you can guarantee that there are no other square brackets on the line. In PHP the code will be:
if (preg_match('/(?<=\]).*/', $input, $group)) {
$match = $group[0];
}
This will transform [widget_abc]This is some text. This is some text, etc... into This is some text. This is some text, etc.... It matches everything that follows the ].
$output = preg_replace('/^[^\]]*\]/', '', $string_text);
Is there any particular reason why a regex is wanted here?
echo substr(strstr($string_text, ']'), 1);
A regex is definitely overkill for this instance.
Here is a nice one-liner :
list(, $result) = explode(']', $inputText, 2);
It does the job and is way less expensive than using regular expressions.

Get Everything between two characters

I'm using PHP. I'm trying to get a Regex pattern to match everything between value=" and " i.e. Line 1 Line 2,...,to Line 4.
value="Line 1
Line 2
Line 3
Line 4"
I've tried /.*?/ but it doesn't seem to work.
I'd appreciate some help.
Thanks.
P.S. I'd just like to add, in response to some comments, that all strings between the first " and last " are acceptable. I'm just trying to find a way to get everything between the very first " and very last " even when there is a " in between. I hope this makes sense. Thanks.
Assuming the desired character is "double quote":
$pat = '/\"([^\"]*?)\"/'; // text between quotes excluding quotes
$value='"Line 1 Line 2 Line 3 Line 4"';
preg_match($pat, $value, $matches);
echo $matches[1]; // $matches[0] is string with the outer quotes
if you just want answer and not want specific regex,then you can use this:
<?php
$str='value="Line 1
Line 2
Line 3
Line 4"';
$need=explode("\"",$str);
var_dump($need[1]);
?>
/.*?/ has the effect to not match the new line characters. If you want to match them too, you need to use a regular expression like /([^"]*)/.
I agree with Josh K that a regular expression is not required in this case (especially if you know there will not be any apices apart the one to delimit the string). You could adopt the solution given by him as well.
If you must use regex:
if (preg_match('!"([^"]+)"!', $value, $m))
echo $m[1];
You need s pattern modifier. Something like: /value="(.*)"/s
I'm not a regex guru, but why not just explode it?
// Say $var contains this value="..." string
$arr = explode('value="');
$mid = explode('"', $arr[1]);
$fin = $mid[0]; // Contains what you're looking for.
The specification isn't clear, but you can try something like this:
/value="[^"]*"/
Explanation:
First, value=" is matched literally
Then, match [^"]*, i.e. anything but ", possibly spanning multiple lines
Lastly, match " literally
This does not allow " to appear between the "real" quotes, not even if it's escaped by e.g. preceding with a backslash.
The […] is a character class. Something like [aeiou] matches one of any of the lowercase vowels. [^…] is a negated character class. [^aeiou] matches one of anything but the lowercase vowels.
References
regular-expressions.info/Examples - Programming Language Constructs - Strings
Has variations on different string patterns (e.g. allowing escaped quotes)
Related questions
Difference between .*? and .* for regex
As much as is practical, negated character class is always a better option than .*?

Categories