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 | Expected 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
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 Javascript snippet which tests them:
$(function() { var regex = /&foo(\=[^&]*)?(?=&|$)|^foo(\=[^&]*)?(&|$)/; var escapeHtml = function (str) { var map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return str.replace(/[&<>"']/g, function(m) { return map[m]; }); }; //test cases var tests = [ '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' ]; //expected results var expected = [ '' , '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' ]; for(var i = 0; i < tests.length; i++) { var output = tests[i].replace(regex, ''); var success = (output == expected[i]); $('#output').append( '<tr class="' + (success ? 'passed' : 'failed') + '">' + '<td>' + (success ? 'PASS' : 'FAIL') + '</td>' + '<td>' + escapeHtml(tests[i]) + '</td>' + '<td>' + escapeHtml(output) + '</td>' + '<td>' + escapeHtml(expected[i]) + '</td>' + '</tr>' ); } });
#output { border-collapse: collapse; } #output tr.passed { background-color: #af8; } #output tr.failed { background-color: #fc8; } #output td, #output th { border: 1px solid black; padding: 2px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <table id="output"> <tr> <th>Succ?</th> <th>Input</th> <th>Output</th> <th>Expected</th> </tr> </table>
If you want to do this in just one regular expression, you could do this:
/&foo(=[^&]*)?|^foo(=[^&]*)?&?/
This is because you need to match either an ampersand before the foo=..., or one after, or neither, but not both.
To be honest, I think it's better the way you did it: removing the trailing ampersand in a separate step.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With