'Delimiter must not be alphanumeric or backslash' and preg_replace() [duplicate] - php

I am trying to take a string of text like so:
$string = "This (1) is (2) my (3) example (4) text";
In every instance where there is a positive integer inside of parentheses, I'd like to replace that with simply the integer itself.
The code I'm using now is:
$result = preg_replace("\((\d+)\)", "$0", $string);
But I keep getting a
Delimiter must not be alphanumeric or backslash.
Warning
Any thoughts? I know there are other questions on here that sort of answer the question, but my knowledge of regex is not enough to switch it over to this example.

You are almost there. You are using:
$result = preg_replace("((\d+))", "$0", $string);
The regex you specify as the 1st
argument to preg_* family of function
should be delimited in pair of
delimiters. Since you are not using
any delimiters you get that error.
( and ) are meta char in a regex,
meaning they have special meaning.
Since you want to match literal open
parenthesis and close parenthesis,
you need to escape them using a \.
Anything following \ is treated
literally.
You can capturing the integer
correctly using \d+. But the captured
integer will be in $1 and not $0. $0
will have the entire match, that is
integer within parenthesis.
If you do all the above changes you'll get:
$result = preg_replace("#\((\d+)\)#", "$1", $string);

1) You need to have a delimiter, the / works fine.
2) You have to escape the ( and ) characters so it doesn't think it's another grouping.
3) Also, the replace variables here start at 1, not 0 (0 contains the FULL text match, which would include the parentheses).
$result = preg_replace("/\((\d+)\)/", "\\1", $string);
Something like this should work. Any further questions, go to PHP's preg_replace() documentation - it really is good.

Check the docs - you need to use a delimiter before and after your pattern: "/\((\d+)\)/"
You'll also want to escape the outer parentheses above as they are literals, not a nested matching group.
See: preg_replace manual page

Try:
<?php
$string = "This (1) is (2) my (3) example (4) text";
$output = preg_replace('/\((\d)\)/i', '$1', $string);
echo $output;
?>
The parenthesis chars are special chars in a regular expression. You need to escape them to use them.

Delimiter must not be alphanumeric or backslash.,
try typing your parameters inside "/ .... /" as shown bellow. Else the code will output >>> Delimiter must not be alphanumeric or backslash.
$yourString='hi there, good friend';
$dividorString='there';
$someSstring=preg_replace("/$dividorString/",'', $yourString);
echo($someSstring);
// hi, good friend
.
.
worked for me.

Related

Looking to use preg_replace to remove characters from my strings

I have the right function, just not finding the right regex pattern to remove (ID:999999) from the string. This ID value varies but is all numeric. I like to remove everything including the brackets.
$string = "This is the value I would like removed. (ID:17937)";
$string = preg_replace('#(ID:['0-9']?)#si', "", $string);
Regex is not more forte! And need help with this one.
Try this:
$string = preg_replace('# \(ID:[0-9]+\)#si', "", $string);
You need to escape the parenthesis using backslashes \.
You shouldn't use quotes around the number range.
You should use + (one or more) instead of ? (zero or one).
You can add a space at the start, to avoid having a space at the end of the resulting string.
In PHP regex is in / and not #, after that, parentheses are for capture group so you must escape them to match them.
Also to use preg_replace replacement you will need to use capture group so in your case /(\(ID:[0-9]+\))/si will be the a nice regular expression.
Here are two options:
Code: (Demo)
$string = "This is the value I would like removed. (ID:17937)";
var_export(preg_replace('/ \(ID:\d+\)/',"",$string));
echo "\n\n";
var_export(strstr($string,' (ID:',true));
Output: (I used var_export() to show that the technique is "clean" and gives no trailing whitespaces)
'This is the value I would like removed.'
'This is the value I would like removed.'
Some points:
Regex is a better / more flexible solution if your ID substring can exist anywhere in the string.
Your regex pattern doesn't need a character class if you use the shorthand range character \d.
Regex generally speaking should only be used when standard string function will not suffice or when it is proven to be more efficient for a specific case.
If your ID substring always occurs at the end of the string, strstr() is an elegant/perfect function.
Both of my methods write a (space) before ID to make the output clean.
You don't need either s or i modifiers on your pattern, because s only matters if you use a . (dot) and your ID is probably always uppercase so you don't need a case-insensitive search.

Explode and/or regex text to HTML link in PHP

I have a database of texts that contains this kind of syntax in the middle of English sentences that I need to turn into HTML links using PHP
"text1(text1)":http://www.example.com/mypage
Notes:
text1 is always identical to the text in parenthesis
The whole string always have the quotation marks, parenthesis, colon, so the syntax is the same for each.
Sometimes there is a space at the end of the string, but other times there is a question mark or comma or other punctuation mark.
I need to turn these into basic links, like
text1
How do I do this? Do I need explode or regex or both?
"(.*?)\(\1\)":(.*\/[a-zA-Z0-9]+)(?=\?|\,|\.|$)
You can use this.
See Demo.
http://regex101.com/r/zF6xM2/2
You can use this replacement:
$pattern = '~"([^("]+)\(\1\)":(http://\S+)(?=[\s\pP]|\z)~';
$replacement = '\1';
$result = preg_replace($pattern, $replacement, $text);
pattern details:
([^("]+) this part will capture text1 in the group 1. The advantage of using a negated character class (that excludes the double quote and the opening parenthesis) is multiple:
it allows to use a greedy quantifier, that is faster
since the class excludes the opening parenthesis and is immediatly followed by a parenthesis in the pattern, if in an other part of the text there is content between double quotes but without parenthesis inside, the regex engine will not go backward to test other possibilities, it will skip this substring without backtracking. (This is because the PCRE regex engine converts automatically [^a]+a into [^a]++a before processing the string)
\S+ means all that is not a whitespace one or more times
(?=[\s\pP]|\z) is a lookahead assertion that checks that the url is followed by a whitespace, a punctuation character (\pP) or the end of the string.
You can use this regex:
"(.*?)\(.*?:(.*)
Working demo
An appropriate Regular Expression could be:
$str = '"text1(text1)":http://www.example.com/mypage';
preg_match('#^"([^\(]+)' .
'\(([^\)]+)\)[^"]*":(.+)#', $str, $m);
print ''.$m[2].'' . PHP_EOL;

matching either nothing (beginning of string) or any character but a \

To use a simplified example, I have:
$str = "Hello :special_text:! Look, I can write \:special_text:";
$pattern = /*???*/":special_text:";
$res = preg_replace($pattern, 'world', $str);
$res = str_replace("/:", ":", $res);
$res === "Hello world! Look, I can write :special_text:"; // => true
In other words, I'd like to be able to "escape" something that I'm writing.
I think that I have something almost working (using [^:]? as the first part of pattern), but I don't think that works if $str === ":special_text:", in that^doesn't match[^:]?`.
You can use a negative lookbehind:
(?<!\\):special_text:
This says "replace a :special_text: that isn't preceded by a backslash".
In your second str_replace looks like you want to replace \: by :.
See it in action here.
Also, don't forget if you use backslash in PHP strings you need to escape them once more (if you want a literal \ you need to use PHP \\, and to get a literal \\ you need to use PHP \\\\:
$pattern = '#(?<!\\\\):([^:]+):#';
Here the # is just a regex delimiter.
$pattern = "/[^\\\\]*:special_text:/";
-or-
$pattern = "/(?<!\\\\):special_text:/";
The other answers don't take into account the need to super-escape the backslashes in this situation. It's a little crazy.
To match a literal backslash, one has to write \\\\ as the regex string because the regular expression must be \\, and each backslash must be expressed as \\ inside a string literal. In regexes that feature backslashes repeatedly, this leads to lots of repeated backslashes and makes the resulting strings difficult to understand.
Something like this should do it: /[^\\]\:([a-z]+)\:/i
You can use RegexPal to text your regex against possible strings in realtime.

PHP using preg_replace : "Delimiter must not be alphanumeric or backslash" error

I am trying to take a string of text like so:
$string = "This (1) is (2) my (3) example (4) text";
In every instance where there is a positive integer inside of parentheses, I'd like to replace that with simply the integer itself.
The code I'm using now is:
$result = preg_replace("\((\d+)\)", "$0", $string);
But I keep getting a
Delimiter must not be alphanumeric or backslash.
Warning
Any thoughts? I know there are other questions on here that sort of answer the question, but my knowledge of regex is not enough to switch it over to this example.
You are almost there. You are using:
$result = preg_replace("((\d+))", "$0", $string);
The regex you specify as the 1st
argument to preg_* family of function
should be delimited in pair of
delimiters. Since you are not using
any delimiters you get that error.
( and ) are meta char in a regex,
meaning they have special meaning.
Since you want to match literal open
parenthesis and close parenthesis,
you need to escape them using a \.
Anything following \ is treated
literally.
You can capturing the integer
correctly using \d+. But the captured
integer will be in $1 and not $0. $0
will have the entire match, that is
integer within parenthesis.
If you do all the above changes you'll get:
$result = preg_replace("#\((\d+)\)#", "$1", $string);
1) You need to have a delimiter, the / works fine.
2) You have to escape the ( and ) characters so it doesn't think it's another grouping.
3) Also, the replace variables here start at 1, not 0 (0 contains the FULL text match, which would include the parentheses).
$result = preg_replace("/\((\d+)\)/", "\\1", $string);
Something like this should work. Any further questions, go to PHP's preg_replace() documentation - it really is good.
Check the docs - you need to use a delimiter before and after your pattern: "/\((\d+)\)/"
You'll also want to escape the outer parentheses above as they are literals, not a nested matching group.
See: preg_replace manual page
Try:
<?php
$string = "This (1) is (2) my (3) example (4) text";
$output = preg_replace('/\((\d)\)/i', '$1', $string);
echo $output;
?>
The parenthesis chars are special chars in a regular expression. You need to escape them to use them.
Delimiter must not be alphanumeric or backslash.,
try typing your parameters inside "/ .... /" as shown bellow. Else the code will output >>> Delimiter must not be alphanumeric or backslash.
$yourString='hi there, good friend';
$dividorString='there';
$someSstring=preg_replace("/$dividorString/",'', $yourString);
echo($someSstring);
// hi, good friend
.
.
worked for me.

Regex Question: Matching this pattern with hard or soft quotes

I have this anchor locating regex working pretty well:
$p = '%<a.*\s+name="(.*)"\s*>(?:.*)</a>%im';
It matches <a followed by zero or more of anything followed by a space and name="
It is grabbing the names even if a class or an id precedes the name in the anchor.
What I would like to add is the ability to match on name=' with a single quote (') as well since sooner or later someone will have done this.
Obviously I could just add a second regex written for this but it seems inelegant.
Anyone know how to add the single quote and just use one regex? Any other improvements or recommendations would be very welcome. I can use all the regex help I can get!
Thanks very much for reading,
function findAnchors($html) {
$names = array();
$p = '%<a.*\s+name="(.*)"\s*>(?:.*)</a>%im';
$t = preg_match_all($p, $html, $matches, PREG_SET_ORDER);
if ($matches) {
foreach ($matches as $m) {
$names[] = $m[1];
}
return $names;
}
}
James' comment is actually a very popular, but wrong regex used for string matching. It's wrong because it doesn't allow for escaping of the string delimiter. Given that the string delimiter is ' or " the following regex works
$regex = '([\'"])(.*?)(.{0,2})(?<![^\\\]\\\)(\1)';
\1 is the starting delimeter, \2 is the contents (minus 2 characters) and \3 is the last 2 characters and the ending delimiter. This regex allows for escaping of delimiters as long as the escape character is \ and the escape character hasn't been escaped. IE.,
'Valid'
'Valid \' String'
'Invalid ' String'
'Invalid \\' String'
Try this:
/<a(?:\s+(?!name)[^"'>]+(?:"[^"]*"|'[^']*')?)*\s+name=("[^"]*"|'[^']*')\s*>/im
Here you just have to strip the surrounding quotes:
substr($match[1], 1, -1)
But using a real parser like DOMDocument would be certainly better that this regular expression approach.
Use [] to match character sets:
$p = "%<a.*\s+name=['\"](.*)['\"]\s*>(?:.*)</a>%im";
Your current solution won't match anchors with other attributes following 'name' (e.g. <a name="foo" id="foo">).
Try:
$regex = '%<a\s+\S*\s*name=["']([^"']+)["']%i';
This will extract the contents of the 'name' attribute into the back reference $1.
The \s* will also allow for line breaks between attributes.
You don't need to finish off with the rest of the 'a' tag as the negated character class [^"']+ will be lazy.
Here's another approach:
$rgx='~<a(?:\s+(?>name()|\w+)=(?|"([^"]*)"|\'([^\']*)\'))+?\1~i';
I know this question is old, but when it resurfaced just now I thought up another use for the "empty capturing groups as checkboxes" idiom from the Cookbook. The first, non-capturing group handles the matching of all "name=value" pairs under the control of a reluctant plus (+?). If the attribute name is literally name, the empty group (()) matches nothing, then the backreference (\1) matches nothing again, breaking out of the loop. (The backreference succeeds because the group participated in the match, even though it didn't consume any characters.)
The attribute value is captured each time in group #2, overwriting whatever was captured on the previous iteration. (The branch-reset construct ((?|(...)|(...)) enables us to "re-use" group #2 to capture the value inside the quotes, whichever kind of quotes they were.) Since the loop quits after the name name comes up, the final captured value corresponds to that attribute.
See a demo on Ideone

Categories