Page 1 of 1
can't find double-quotes in preg_replace
Posted: Fri Dec 10, 2010 4:30 pm
by Swede78
I've been trying for hours, and searching for hours how to do this. I want to add a prefix to an HTML form select name. Here's the code that's failing:
Code: Select all
$prefix = 'prefix_';
$str = '<select name="course">';
$str = preg_replace("/(<\s*input[^>]+)(\s*name\s*=\s*)('|\"?)\s*(\w+)\s*('|\"?\s+)([^>]*>)/is", "\\1"."\\2"."\\3".$prefix."\\4"."\\5"."\\6", $str);
echo $str;
// I want it to return <select name="prefix_course">
Please help me stop pulling my hair out.
Re: can't find double-quotes in preg_replace
Posted: Fri Dec 10, 2010 6:33 pm
by ridgerunner
First off, when writing a complex regex, it helps to write it out using free-spacing mode with lots of comments. Here is your regex with added comments:
Code: Select all
<?php
$prefix = 'prefix_';
$str = '<select name="course">';
$re = '/
(<\s*input[^>]+) # $1: INPUT opening tag, everthing up to "name".
(\s*name\s*=\s*) # $2: "name = " attribute, equals sign, optional ws.
(\'|"?)\s* # $3: Single or optional double quote, optional ws.
(\w+)\s* # $4: First word of "name" attribute value, optional ws.
(\'|"?\s+) # $5: Single or optional double quote, one or more ws.
([^>]*>) # $6: Remainder of INPUT opening tag.
/six';
$str = preg_replace($re, "\\1"."\\2"."\\3".$prefix."\\4"."\\5"."\\6", $str);
echo $str;
// I want it to return <select name="prefix_course">
?>
The problem is the subexpression for the closing quote: "('|\"?\s+)". It says: "
Match and capture either a single quote or an optional double quote followed by one or more spaces." The first reason your regex does not match is because there are no spaces following the closing quote in the subject string. Secondly, your regex specifies an INPUT tag when I think you are trying to match a SELECT tag. Here is an improved version:
Code: Select all
<?php
$prefix = 'prefix_';
$str = '<select name="course">';
$re = '/
( # $1: Everything up to name attribute value.
<select # Opening delim and tagname.
[^>]+? # Lazily match everything up to "name" attribute.
\bname\s*=\s* # "name = " attribute and equals sign with optional ws.
) # End $1. Everything up to name attribute value.
([\'"]?)\s* # $2: Optional single or double quote, optional ws.
(\w+)\s* # $3: First word of "name" value, optional ws.
(?(2)\2) # If value had opening quote, match same closing quote.
([^>]*>) # $4: Remainder of input opening tag.
/ix';
$str = preg_replace($re, '$1"' . $prefix . '$3"$4', $str);
echo $str;
?>
Hope this helps!

Re: can't find double-quotes in preg_replace
Posted: Mon Dec 13, 2010 1:36 pm
by Swede78
Thank you ridgerunner for the thorough explanation. I was also applying this to input tags, so I accidentally copied the wrong line when into here. I'm obviously still learning regex, and what you've shown me here has taught me a lot more. I'm very grateful for the help with this. I'm going to go back and clean up some of my past code based on this, because I see now that I've been doing things not quite as efficiently as I could.
One thing though... I thought the s modifier was needed, because it seems that HTML allows what I'm looking for to be broken up into multiple lines.
For example, the following HTML will work:
<select
name =
"course">
And, your regex code works when applied to that HTML. I thought it wouldn't unless the s modifier was used. That makes me scratch my head, but I think I understand everything else. Thanks!!!
Re: can't find double-quotes in preg_replace
Posted: Mon Dec 13, 2010 1:38 pm
by Swede78
Ahhh.... I see how you did that now. x modified enables "free-spacing mode". In this mode, whitespace between regex tokens is ignored, and an unescaped # starts a comment.
Re: can't find double-quotes in preg_replace
Posted: Mon Dec 13, 2010 1:54 pm
by AbraCadaver
Swede78 wrote:Ahhh.... I see how you did that now. x modified enables "free-spacing mode". In this mode, whitespace between regex tokens is ignored, and an unescaped # starts a comment.
Also, the s modifier allows the . (dot) to match newlines. It's not needed if you aren't using the dot in your pattern. In ridgerunner's pattern, they're specifying exactly what to match or what not to match so newlines are OK.
Re: can't find double-quotes in preg_replace
Posted: Mon Dec 13, 2010 2:31 pm
by Swede78
I was wondering why you chose not to use the word boundary (/b) for "select", and only "name"?
Re: can't find double-quotes in preg_replace
Posted: Mon Dec 13, 2010 2:49 pm
by Swede78
I modifed the code to look for the NAME or ID of SELECT, INPUT, OR TEXTAREA tags. I believe this is working. Thanks for all the help. Note that I added optional ws between opening bracket and tagname.
Code: Select all
$prefix = 'prefix_';
$str = '<select name="course">';
$re = '/
( # $1: Everything up to opening tag.
<\s*(?:\binput|\bselect|\btextarea) # Opening delim, optional ws, and tagname (input, select, or textarea).
[^>]+? # Lazily match everything up to "name" or "id" attribute.
(?:\bname|\bid)\s*=\s* # "name" or "id" attribute and equals sign with optional ws.
) # End $1
([\'"]?)\s* # $2: Optional single or double quote, optional ws.
(\w+)\s* # $3: First word of "name" value, optional ws.
(?(2)\2) # If value had opening quote, match same closing quote.
([^>]*>) # $4: Remainder of opening tag.
/ix';
$str = preg_replace($re, '$1"' . $prefix . '$3"$4', $str);