I'm looking for a regular expression to remove a single parameter from a query string, and I want to do it in a single regular expression if possible.
Say I want to remove the foo parameter. Right now I use this:
/&?foo\=[^&]+/
That works as long as foo is not the first parameter in the query string. If it is, then my new query string starts with an ampersand. (For example, "foo=123&bar=456" gives a result of "&bar=456".) Right now, I'm just checking after the regex if the query string starts with ampersand, and chopping it off if it does.
Example edge cases:
Input | Output
-------------------------+-----------------
foo=123 | (empty string)
foo=123&bar=456 | bar=456
bar=456&foo=123 | bar=456
abc=789&foo=123&bar=456 | abc=789&bar=456
Edit
OK as pointed out in comments there are there are way more edge cases than I originally considered. I got the following regex to work with all of them:
/&foo(\=[^&]*)?(?=&|$)|^foo(\=[^&]*)?(&|$)/
This is modified from Mark Byers's answer, which is why I'm accepting that one, but Roger Pate's input helped a lot too.
Here is the full suite of test cases I'm using, and a Perl script which tests them.
Input | Output
-------------------------+-------------------
foo |
foo&bar=456 | bar=456
bar=456&foo | bar=456
abc=789&foo&bar=456 | abc=789&bar=456
foo= |
foo=&bar=456 | bar=456
bar=456&foo= | bar=456
abc=789&foo=&bar=456 | abc=789&bar=456
foo=123 |
foo=123&bar=456 | bar=456
bar=456&foo=123 | bar=456
abc=789&foo=123&bar=456 | abc=789&bar=456
xfoo | xfoo
xfoo&bar=456 | xfoo&bar=456
bar=456&xfoo | bar=456&xfoo
abc=789&xfoo&bar=456 | abc=789&xfoo&bar=456
xfoo= | xfoo=
xfoo=&bar=456 | xfoo=&bar=456
bar=456&xfoo= | bar=456&xfoo=
abc=789&xfoo=&bar=456 | abc=789&xfoo=&bar=456
xfoo=123 | xfoo=123
xfoo=123&bar=456 | xfoo=123&bar=456
bar=456&xfoo=123 | bar=456&xfoo=123
abc=789&xfoo=123&bar=456 | abc=789&xfoo=123&bar=456
foox | foox
foox&bar=456 | foox&bar=456
bar=456&foox | bar=456&foox
abc=789&foox&bar=456 | abc=789&foox&bar=456
foox= | foox=
foox=&bar=456 | foox=&bar=456
bar=456&foox= | bar=456&foox=
abc=789&foox=&bar=456 | abc=789&foox=&bar=456
foox=123 | foox=123
foox=123&bar=456 | foox=123&bar=456
bar=456&foox=123 | bar=456&foox=123
abc=789&foox=123&bar=456 | abc=789&foox=123&bar=456
Test script (Perl)
@in = ('foo' , 'foo&bar=456' , 'bar=456&foo' , 'abc=789&foo&bar=456'
,'foo=' , 'foo=&bar=456' , 'bar=456&foo=' , 'abc=789&foo=&bar=456'
,'foo=123' , 'foo=123&bar=456' , 'bar=456&foo=123' , 'abc=789&foo=123&bar=456'
,'xfoo' , 'xfoo&bar=456' , 'bar=456&xfoo' , 'abc=789&xfoo&bar=456'
,'xfoo=' , 'xfoo=&bar=456' , 'bar=456&xfoo=' , 'abc=789&xfoo=&bar=456'
,'xfoo=123', 'xfoo=123&bar=456', 'bar=456&xfoo=123', 'abc=789&xfoo=123&bar=456'
,'foox' , 'foox&bar=456' , 'bar=456&foox' , 'abc=789&foox&bar=456'
,'foox=' , 'foox=&bar=456' , 'bar=456&foox=' , 'abc=789&foox=&bar=456'
,'foox=123', 'foox=123&bar=456', 'bar=456&foox=123', 'abc=789&foox=123&bar=456'
);
@exp = ('' , 'bar=456' , 'bar=456' , 'abc=789&bar=456'
,'' , 'bar=456' , 'bar=456' , 'abc=789&bar=456'
,'' , 'bar=456' , 'bar=456' , 'abc=789&bar=456'
,'xfoo' , 'xfoo&bar=456' , 'bar=456&xfoo' , 'abc=789&xfoo&bar=456'
,'xfoo=' , 'xfoo=&bar=456' , 'bar=456&xfoo=' , 'abc=789&xfoo=&bar=456'
,'xfoo=123', 'xfoo=123&bar=456', 'bar=456&xfoo=123', 'abc=789&xfoo=123&bar=456'
,'foox' , 'foox&bar=456' , 'bar=456&foox' , 'abc=789&foox&bar=456'
,'foox=' , 'foox=&bar=456' , 'bar=456&foox=' , 'abc=789&foox=&bar=456'
,'foox=123', 'foox=123&bar=456', 'bar=456&foox=123', 'abc=789&foox=123&bar=456'
);
print "Succ | Input | Output | Expected \n";
print "-----+--------------------------+--------------------------+-------------------------\n";
for($i=0; $i <= $#in; $i++)
{
$out = $in[$i];
$out =~ s/_PUT_REGEX_HERE_//;
$succ = ($out eq $exp[$i] ? 'PASS' : 'FAIL');
#if($succ eq 'FAIL')
#{
printf("%s | %- 24s | %- 24s | %- 24s\n", $succ, $in[$i], $out, $exp[$i]);
#}
}