我正在寻找一个正则表达式来从查询字符串中删除单个参数,如果可能的话,我希望在单个正则表达式中执行此操作。
我想要删除foo
参数。现在我用这个:
/&?foo\=[^&]+/
只要foo
不是查询字符串中的第一个参数,就可以正常工作。如果是,那么我的新查询字符串以&符号开头。 (例如,“foo=123&bar=456
”给出“&bar=456
”的结果。)现在,我只是在正则表达式后检查查询字符串是否以&符号开头,如果是,则将其砍掉
示例边缘情况:
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
好的,正如评论中指出的那样,有更多的边缘案例比我原先考虑的更多。我得到以下正则表达式与所有人一起工作:
/&foo(\=[^&]*)?(?=&|$)|^foo(\=[^&]*)?(&|$)/
这是从Mark Byers's answer修改的,这就是为什么我接受那个,但罗杰佩特的投入也帮了很多。
以下是我正在使用的全套测试用例,以及一个测试它们的Javascript代码段:
$(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>
答案 0 :(得分:21)
如果您只想在一个正则表达式中执行此操作,则可以执行以下操作:
/&foo(=[^&]*)?|^foo(=[^&]*)?&?/
这是因为你需要在foo = ...之前匹配一个&符号,或者在一个之后匹配,或者两个都不匹配,但不能两者都匹配。
老实说,我认为你做的方式更好:在一个单独的步骤中删除尾随的&符号。
答案 1 :(得分:6)
/(?<=&|\?)foo(=[^&]*)?(&|$)/
使用lookbehind和最后一组来“锚定”匹配,并允许缺少值。如果您已从查询字符串中删除了问号,请将\?
更改为^
。
然而,正则表达式仍然不能替代查询字符串的真正解析器。
更新:测试脚本:(在codepad.org运行)
import re
regex = r"(^|(?<=&))foo(=[^&]*)?(&|$)"
cases = {
"foo=123": "",
"foo=123&bar=456": "bar=456",
"bar=456&foo=123": "bar=456",
"abc=789&foo=123&bar=456": "abc=789&bar=456",
"oopsfoo=123": "oopsfoo=123",
"oopsfoo=123&bar=456": "oopsfoo=123&bar=456",
"bar=456&oopsfoo=123": "bar=456&oopsfoo=123",
"abc=789&oopsfoo=123&bar=456": "abc=789&oopsfoo=123&bar=456",
"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",
}
failures = 0
for input, expected in cases.items():
got = re.sub(regex, "", input)
if got != expected:
print "failed: input=%r expected=%r got=%r" % (input, expected, got)
failures += 1
if not failures:
print "Success"
它显示了我的方法失败的地方,马克有权利 - 这应该说明为什么你不应该用正则表达式做这个...:P
问题是将查询参数与一个&符号相关联,并且 - 如果你必须使用正则表达式(如果你还没有选择它:P,我会使用一个单独的解析器,它可能在其中使用正则表达式,但实际上仍然理解格式) - 一个解决方案是确保每个参数只有一个&符号:用?
替换前导&
。
这给了/&foo(=[^&]*)?(?=&|$)/
,这是非常直接的,你将获得最好的。删除最终结果中的前导&
(或将其更改回?
等)。修改测试用例以执行此操作使用与上述相同的情况,并将循环更改为:
failures = 0
for input, expected in cases.items():
input = "&" + input
got = re.sub(regex, "", input)
if got[:1] == "&":
got = got[1:]
if got != expected:
print "failed: input=%r expected=%r got=%r" % (input, expected, got)
failures += 1
if not failures:
print "Success"
答案 2 :(得分:4)
拥有以&
开头的查询字符串是无害的 - 为什么不这样做呢?在任何情况下,我建议您搜索尾随的&符号并使用\b
来匹配foo的开头w / o接收前一个字符:
/\bfoo\=[^&]+&?/
答案 3 :(得分:1)
这有点傻但是我开始尝试使用正则表达式来解决这个问题,并希望最终让它工作:)
$str[] = 'foo=123';
$str[] = 'foo=123&bar=456';
$str[] = 'bar=456&foo=123';
$str[] = 'abc=789&foo=123&bar=456';
foreach ($str as $string) {
echo preg_replace('#(?:^|\b)(&?)foo=[^&]+(&?)#e', "'$1'=='&' && '$2'=='&' ? '&' : ''", $string), "\n";
}
替换部分搞砸了,因为如果捕获的字符是'&'
s
此外,不匹配afoo
之类的内容。
答案 4 :(得分:1)
感谢。是的,它使用反斜杠进行转义,你是对的,我不需要/。
这似乎有效,但它没有按照原始问题的要求在一行中完成。
public static string RemoveQueryStringParameter(string url, string keyToRemove)
{
//if first parameter, leave ?, take away trailing &
string pattern = @"\?" + keyToRemove + "[^&]*&?";
url = Regex.Replace(url, pattern, "?");
//if subsequent parameter, take away leading &
pattern = "&" + keyToRemove + "[^&]*";
url = Regex.Replace(url, pattern, "");
return url;
}
答案 5 :(得分:1)
我基于您的实现来获得似乎有用的Java impl:
public static String removeParameterFromQueryString(String queryString,String paramToRemove) {
Preconditions.checkArgument(queryString != null,"Empty querystring");
Preconditions.checkArgument(paramToRemove != null,"Empty param");
String oneParam = "^"+paramToRemove+"(=[^&]*)$";
String begin = "^"+paramToRemove+"(=[^&]*)(&?)";
String end = "&"+paramToRemove+"(=[^&]*)$";
String middle = "(?<=[&])"+paramToRemove+"(=[^&]*)&";
String removedMiddleParams = queryString.replaceAll(middle,"");
String removedBeginParams = removedMiddleParams.replaceAll(begin,"");
String removedEndParams = removedBeginParams.replaceAll(end,"");
return removedEndParams.replaceAll(oneParam,"");
}
在某些情况下,我的实施遇到了麻烦,因为有时候它没有删除&
,而是通过多个步骤来实现,这似乎更容易理解。
我的版本存在问题,特别是当参数字符串多次出现时(例如param1 = toto&amp; param2 = xxx&amp; param1 = YYY&amp; param3 = ZZZ&amp; param1 ....)
答案 6 :(得分:0)
您可以使用以下正则表达式:
[\?|&](?<name>.*?)=[^&]*&?
如果您想进行完全匹配,可以使用url参数替换(?<name>.*?)
。
e.g:
[\?|&]foo=[^&]*&?
匹配任何网址中的任何变量,例如foo=xxxx
。
答案 7 :(得分:-2)
对于有兴趣替换GET请求参数的任何人:
以下正则表达式适用于更一般的GET方法查询(以?开头),如果要删除的参数是第一个(在?之后),则标记的答案会失败。
这个(JS风格)正则表达式可用于删除参数,无论位置(第一个,最后一个,或之间),使查询处于良好格式状态。
所以只需使用空字符串替换正则表达式。
/&s=[^&]*()|\?s=[^&]*$|s=[^&]*&/
基本上它与上述三种情况中的一种(因此是2个管道)相匹配