Why doesn't preg_replace return anything in this scenario? I've been trying to figure it out all night.
Here is the text contained within $postContent:
Test this. Here is a quote: [Quote]1[/Quote] Quote is now over.
Here is my code:
echo "Test I'm Here!!!";
$startQuotePos = strpos($postContent,'[Quote]')+7;
$endQuotePos = strpos($postContent,'[/Quote]');
$postStrLength = strlen($postContent);
$quotePostID = substr($postContent,$startQuotePos,($endQuotePos-$postStrLength));
$quotePattern = '[Quote]'.$quotePostID.'[/Quote]';
$newPCAQ = preg_replace($quotePattern,$quotePostID,$postContent);
echo "<br />$startQuotePos<br />$endQuotePos<br />$quotePostID<br />Qpattern:$quotePattern<br />PCAQ: $newPCAQ<br />";
This is my results:
Test I'm Here!!!
35
36
1
Qpattern:[Quote]1[/Quote]
PCAQ:
For preg_replace(), "[Quote]" matches a single character that is one of the following: q, u, o, t, or e.
If you want that preg_replace() finds the literal "[Quote]", you need to escape it as "\[Quote\]". preg_quote() is the function you should use: preg_quote("[Quote]").
Your code is also wrong because a regular expression is expected to start with a delimiter. In the preg_replace() call I am showing at the end of my answer, that is #, but you could use another character, as long as it doesn't appear in the regular expression, and it is used also at the end of the regular expression. (In my case, # is followed by a pattern modifier, and pattern modifiers are the only characters allowed after the pattern delimiter.)
If you are going to use preg_replace(), it doesn't make sense that you first find where "[Quote]" is. I would rather use the following code:
$newPCAQ = preg_replace('#\[Quote\](.+?)\[/Quote\]#i', '\1', $postContent);
I will explain the regular expression I am using:
The final '#i' is saying to preg_replace() to ignore the difference between lowercase, and uppercase characters; the string could contain "[QuOte]234[/QuOTE]", and that substring would match the regular expression the same.
I use a question mark in "(.+?)" to avoid ".+" is too greedy, and matches too much characters. without it, the regular expression could include in a single match a substring like "[Quote]234[/Quote] Other text [Quote]475[/Quote]" while this should be matched as two substrings: "[Quote]234[/Quote]", and "[Quote]475[/Quote]".
The '\1' string I am using as replacement string is saying to preg_replace() to use the string matched from the sub-group "(.+?)" as replacement. In other words, the call to preg_replace() is removing "[Quote]", and "[/Quote]" surrounding other text. (It doesn't replace "[/Quote]" that doesn't match with "[Quote]", such as in "[/Quote] Other text [Quote]".)
your regex must start & end with '/':
$quotePattern = '/[Quote]'.$quotePostID.'[/Quote]/';
The reason you don't see anything for the return value of preg_replace is because it has returned NULL (see the manual link for details). This is what preg_replace returns when an error occurs, which is what happened in your situation. The string value of NULL is a zero-length string. You can see this by using var_dump instead, which will tell you that preg_replace returned NULL.
Your regular expression is invalid and as such PHP will throw an E_WARNING level error of Warning: preg_replace(): Unknown modifier '['
There are a couple of reason for this. First, you need to specify an opening and closing delimiter for you regular expression as preg_* functions use PCRE style regular expression. Second, you want to also consider using preg_quote on your patter (sans the delimiter) to ensure it is escaped properly.
$postContent = "Test this. Here is a quote: [Quote]1[/Quote] Quote is now over.";
/* Specify a delimiter for your regular expression */
$delimiter = '#';
$startQuotePos = strpos($postContent,'[Quote]')+7;
$endQuotePos = strpos($postContent,'[/Quote]');
$postStrLength = strlen($postContent);
$quotePostID = substr($postContent,$startQuotePos,($endQuotePos-$postStrLength));
/* Make sure you use the delimiter in your pattern and escape it properly */
$quotePattern = $delimiter . preg_quote("[Quote]{$quotePostID}[/Quote]", $delimiter) . $delimiter;
$newPCAQ = preg_replace($quotePattern,$quotePostID,$postContent);
echo "<br />$startQuotePos<br />$endQuotePos<br />$quotePostID<br />Qpattern:$quotePattern<br />PCAQ: $newPCAQ<br />";
The output will be:
35
36
1
Qpattern:#[Quote]1[/Quote]#
PCAQ: Test this. Here is a quote: 1 Quote is now over.
Related
I'm having a small technical difficulty with a regular expression, I'm trying to look at a string, let's say we have this string:
$string = "error->400";
And another string:
$string = "error->debug->warning";
As an example, I'm basically trying to do a preg_match() that returns true on any instances of -> within it.
This is my attempt but I don't understand why it doesn't work:
preg_match("/^[->]*$/", $string);
Is there a general rule for custom characters that i'm generally missing?
Thanks.
Right now, ^[->]*$ matches any number of "-" or ">" characters, from the beginning to end. You must use a group, not a character class, and anchors are not necessary. Use this to check if "->" is present in the $string:
preg_match("/(->)/", $string);
Have a look at the example.
I am porting code from Node.js to PHP and keep getting errors with this regular expression:
^/[a-z0-9]{6}([^0-9a-z]|$)
PHP complains about a dollar sign:
Unknown modifier '$'
In JavaScript I was able to check if a string was ending with [^0-9a-z] or END OF STRING.
How do I do this in PHP with preg_match()?
My PHP code looks like this:
<?
$sExpression = '^/[a-z0-9]{6}([^0-9a-z]|$)';
if (preg_match('|' . $sExpression . '|', $sUrl)) {
// ...
}
?>
The JavaScript code was similar to this:
var sExpression = '^/[a-z0-9]{6}([^0-9a-z]|$)';
var oRegex = new RegExp(sExpression);
if (oRegex.test(sUrl)) {
// ...
}
To match a string that starts with a slash, followed by six alphanumerics and is then followed by either the end-of-string or something that's not alphanumeric:
preg_match('~^/[a-z0-9]{6}([^0-9a-z]|$)~i', $str);
The original JavaScript probably used new RegExp(<expression>), but PCRE requires a proper enclosure of the expression; those are the ~ characters I've put in the above code. Btw, I've made the expression case insensitive by using the i modifier; feel free to remove it if not desired.
You were using | as the enclosure; as such, you should have escaped the pipe character inside the expression, but by doing so you would have changed the meaning. It's generally best to choose delimiters that do not have a special meaning in an expression; it also helps to choose delimiters that don't occur as such in the expression, e.g., my choice of ~ avoids having to escape any character.
Expressions in PCRE can be generalised as:
<start-delimiter> stuff <end-delimiter> modifiers
Typically, the starting delimiter is the same as the ending delimiter, except for cases such as [expression]i or {expression}i whereby the opening brace is matched with the closing brace :)
Fix the regular expression first:
^/[a-z0-9]{6}([^0-9a-z]|$)
Try this.
As others pointed out, I'm an idiot and saw a / as a \ ... LOL.
Ok, well go at this again,
I’d avoid using the "|" and just do it this way.
if (preg_match('/^\/[a-z0-9]{6}([^0-9a-z]|$)/', $sUrl)) { ... }
Reducing this to just matching a particular character or end of string (PHP),
\D777(\D|$)\
This will match:
xxx777xxx or xxx777 but not xxx7777 or xxx7777xxx
I have the following function which as you can see, replaces certain characters in a string with the pattern, yet it only works when I enter in the pattern as a string like in the first commented out line. I put an echo in there to test what was coming back and its as it should be so I dont know whats going on! Has anyone any clues?
private function check_string( $s )
{
//return preg_replace( '/[^a-z 0-9~%\.:_\\-()"]/i', '', $s );
// a-z 0-9~%\.:_\\-()"
echo $this->permitted_uri_chars;
// /[^a-z 0-9~%\.:_\\-()"]/i
$pattern = '/[^'. $this->permitted_uri_chars .']/i';
return preg_replace( $pattern, '', $s );
}
The error I get is
Message: preg_replace(): Compilation failed: range out of order in character class at offset 18
ANSWER
Thanks to Jason McCreary
$pattern = '/[^'. preg_quote($this->config->item('permitted_uri_chars'), '/') .']+/i';
It is working in the first example because you properly escaped characters for both PHP and the Regular Expression. (i.e. \\).
When using a string, you have only escaped for PHP. So when you use this string in your Regular Expression it is no longer escaped.
This is demonstrated by the following example:
echo '/[^a-z 0-9~%\.:_\\-()"]/i';
// becomes: /[^a-z 0-9~%\.:_\-()"]/i
A few options would be:
Double escape.
Avoid the Regular Expression escaping by placing the dash at the end: /[^a-z 0-9~%.:_()"-]/
Use preg_quote() if you're going to accept strings regular expression syntax.
Note: I'd encourage you to read about escaping inside character classes.
I don't know how to do the following:
find all instances of '/\s[2-9]\)/' and replace the space with a <br /> tag.
Something as simple as this doesn't work:
$preg_num = ' /\s[2-9]\)/';
$preg_fix = "'/<br>/[2-9]\)'";
preg_replace($preg_num,$preg_fix,$notes);
What do I need to change the $preg_fix variable to?
Using a lookahead is simpler than a backreference, IMHO.
$preg_num = '/\s(?=[2-9]\))/';
$preg_fix = '<br/>';
preg_replace($preg_num,$preg_fix,$notes);
This way, you are only replacing the space with the <br/>.
The replacement string is not treated as a regex — it is more like a literal string. If you are trying to put whatever digit [2-9] that was matched in the original regex into the replacement string, capture the character as a group and use a backreference.
$preg_num = '/\s([2-9])\)/';
$preg_fix = "<br />$1)'";
preg_replace($preg_num,$preg_fix,$notes);
For more information:
preg_replace's replacement parameter documentation
Regular expression grouping: "Use Round Brackets for Grouping"
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 .*?