regex 用于从查询字符串中删除一个参数正则表达式

gmxoilav  于 2022-12-01  发布在  其他
关注(0)|答案(9)|浏览(157)

我正在寻找一个正则表达式来从查询字符串中删除单个参数,如果可能的话,我希望在单个正则表达式中完成此操作。
假设我想删除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(\=[^&]*)?(&|$)/

这是根据马克·拜尔斯的回答修改的,这就是为什么我接受这个答案,但罗杰·佩特的意见也有很大帮助。
下面是我正在使用的一整套测试用例,以及测试它们的Javascript片段:
第一个

bxpogfeg

bxpogfeg1#

如果您只想在一个正则表达式中执行此操作,则可以执行以下操作:

/&foo(=[^&]*)?|^foo(=[^&]*)?&?/

这是因为您需要在foo=...之前匹配一个&符号,或者在foo=...之后匹配一个&符号,或者两者都不匹配,但不能同时匹配两者。
老实说,我觉得你这样做更好:在单独的步骤中移除尾部的“与”符号。

xoefb8l8

xoefb8l82#

/(?<=&|\?)foo(=[^&]*)?(&|$)/

使用lookbehind和最后一个组来“锚定”匹配,并允许缺少值。如果已经从查询字符串中去掉问号,请将\?更改为^
但是,Regex仍然不能替代查询字符串的真正解析器。

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"

它显示了我的方法失败的地方,马克有它的权利-这应该显示为什么你不应该这样做与regex..:P
问题是将查询参数与恰好一个“与”符号相关联,并且-如果必须使用regex(如果您还没有学会它:P,我将使用单独的解析器,它可能在内部使用regex,但实际上仍然理解该格式)-一种解决方案是确保每个参数恰好有一个“与”符号:将前导的?替换为&
这样就得到了/&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"
qvk1mo1f

qvk1mo1f3#

&开头的查询字符串是无害的--为什么不保持这种方式呢?无论如何,我建议您搜索尾部的“与”符号,并使用\b来匹配foo的开头,而不接受前面的字符:

/\bfoo\=[^&]+&?/
mpgws1up

mpgws1up4#

这有点傻,但我开始尝试用正则表达式解决这个问题,并希望最终让它工作:)

$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等。

xfb7svmp

xfb7svmp5#

谢谢。是的,它使用反斜杠来转义,你是对的,我不需要/。
这似乎是可行的,尽管它没有像原始问题中要求的那样在一行中完成。

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;
    }
c9qzyr3d

c9qzyr3d6#

我以您的实现为基础,得到了一个看起来可以工作的Java实现:

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&param2=xxx&param1=YYY&param3= ZZZ &param1 ....)

edqdpe6u

edqdpe6u7#

永远都不会太晚对吧
我使用条件lookbehind来确保它不会弄乱&

/(?(?<=\?)(foo=[^&]+)&*|&(?1))/g

如果?在后面,则捕获foo=bar,如果存在,则跟踪&
如果not ?落后,我们就赶上&foo=bar
(?1)表示第1个导管组,在本例中与(foo=[^&]+)相同
实际上我需要一个oneliner为两个类似的参数每页
所以我稍微改变了一下这个表达式

/(?(?<=\?)((per-)?page=[^&]+)&*|&(?1))/g

工作起来很有魅力

a14dhokn

a14dhokn8#

您可以使用以下正则表达式:

[\?|&](?<name>.*?)=[^&]*&?

如果你想做完全匹配,你可以用url参数替换(?<name>.*?)。例如:

[\?|&]foo=[^&]*&?

以匹配任何URL中任何变量(如foo=xxxx)。

7kqas0il

7kqas0il9#

对于任何对替换GET请求参数感兴趣的人:
下面的正则表达式也适用于更一般的GET方法查询(以?开头),如果要删除的参数是第一个(在?之后),则标记的答案将失败
这个(JS风格)正则表达式可以用来删除参数,而不考虑位置(第一个、最后一个或两者之间),从而使查询处于格式良好的状态。
所以只需要用一个正则表达式替换一个空字符串。

/&s=[^&]*()|\?s=[^&]*$|s=[^&]*&/

基本上,它与上述三种情况之一相匹配(因此有2个管道)

相关问题