如何通过键从 URL 中有效地删除查询字符串?

Posted

技术标签:

【中文标题】如何通过键从 URL 中有效地删除查询字符串?【英文标题】:How to efficiently remove a query string by Key from a Url? 【发布时间】:2012-06-18 15:30:02 【问题描述】:

如何从 URL 中按键删除查询字符串?

我有以下方法可以正常工作,但只是想知道有没有更好/更短的方法?还是可以更有效地执行此操作的内置 .NET 方法?

 public static string RemoveQueryStringByKey(string url, string key)
        
            var indexOfQuestionMark = url.IndexOf("?");
            if (indexOfQuestionMark == -1)
            
                return url;
            

            var result = url.Substring(0, indexOfQuestionMark);
            var queryStrings = url.Substring(indexOfQuestionMark + 1);
            var queryStringParts = queryStrings.Split(new [] '&');
            var isFirstAdded = false;

            for (int index = 0; index <queryStringParts.Length; index++)
            
                var keyValue = queryStringParts[index].Split(new char[]  '=' );
                if (keyValue[0] == key)
                
                    continue;
                

                if (!isFirstAdded)
                
                    result += "?";
                    isFirstAdded = true;
                
                else
                
                    result += "&";
                

                result += queryStringParts[index];
            

            return result;
        

例如我可以这样称呼它:

  Console.WriteLine(RemoveQueryStringByKey(@"http://www.domain.com/uk_pa/PostDetail.aspx?hello=hi&xpid=4578", "xpid"));

希望问题很清楚。

谢谢,

【问题讨论】:

URL Querystring - Find, replace, add, update values?的可能重复 标签:'reinventing-the-wheel' [System.Web.HttpUtility.ParseQueryString] 既没有完整的解决方案,也没有回答所提出的问题。 能举个输入输出的例子吗? 【参考方案1】:
    var queryString = "hello=hi&xpid=4578";
    var qs = System.Web.HttpUtility.ParseQueryString(queryString);
    qs.Remove("xpid");
    var newQuerystring = qs.ToString();

这在 .NET 5 中仍然有效。

【讨论】:

这个解决方案很酷,因为 Remove() 方法确实有效。【参考方案2】:

这个怎么样:

        string RemoveQueryStringByKey(string url, string key)
    
        string ret = string.Empty;

        int index = url.IndexOf(key);
        if (index > -1)
        
            string post = string.Empty;

            // Find end of key's value
            int endIndex = url.IndexOf('&', index);
            if (endIndex != -1) // Last query string value?
            
                post = url.Substring(endIndex, url.Length - endIndex);
            

            // Decrement for ? or & character
            --index;
            ret = url.Substring(0, index) + post;
        

        return ret;
    

【讨论】:

【参考方案3】:

我找到了一种不使用正则表达式的方法:

private string RemoveQueryStringByKey(string sURL, string sKey) 
    string sOutput = string.Empty;

    int iQuestion = sURL.IndexOf('?');
    if (iQuestion == -1) return (sURL);

    int iKey = sURL.Substring(iQuestion).IndexOf(sKey) + iQuestion;
    if (iKey == -1) return (sURL);

    int iNextAnd = sURL.Substring(iKey).IndexOf('&') + iKey + 1;

    if (iNextAnd == -1) 
        sOutput = sURL.Substring(0, iKey - 1);
    
    else 
        sOutput = sURL.Remove(iKey, iNextAnd - iKey);
    

    return (sOutput);

我确实尝试过在最后添加另一个字段,它也可以正常工作。

【讨论】:

【参考方案4】:

我在想最短的方法(我相信在所有情况下都会生成一个有效的 URL,假设 URL 开始是有效的)是使用这个正则表达式(getRidOf 是您尝试删除的变量名)并且替换是零长度字符串""):

(?<=[?&])getRidOf=[^&]*(&|$)

甚至可能

\bgetRidOf=[^&]*(&|$)

虽然可能不是绝对的最漂亮 URL,但我认为它们都是有效的:

         INPUT                                         OUTPUT
      -----------                                   ------------
blah.com/blah.php?getRidOf=d.co&blah=foo        blah.com/blah.php?blah=foo
blah.com/blah.php?f=0&getRidOf=d.co&blah=foo    blah.com/blah.php?f=0&blah=foo
blah.com/blah.php?hello=true&getRidOf=d.co      blah.com/blah.php?hello=true&
blah.com/blah.php?getRidOf=d.co                 blah.com/blah.php?

这是一个简单的正则表达式替换:

Dim RegexObj as Regex = New Regex("(?<=[?&])getRidOf=[^&]*(&|$)")
RegexObj.Replace("source.url.com/find.htm?replace=true&getRidOf=PLEASE!!!", "")

...应该是字符串:

"source.url.com/find.htm?replace=true&"

...这似乎对 ASP.Net 应用程序有效,而 replace 确实等于 true(不是 true&amp; 或类似的东西)

如果您遇到无法使用的情况,我会尝试对其进行调整:)

【讨论】:

【参考方案5】:

这很好用:

public static string RemoveQueryStringByKey(string url, string key)
                   
    var uri = new Uri(url);

    // this gets all the query string key value pairs as a collection
    var newQueryString = HttpUtility.ParseQueryString(uri.Query);

    // this removes the key if exists
    newQueryString.Remove(key);

    // this gets the page path from root without QueryString
    string pagePathWithoutQueryString = uri.GetLeftPart(UriPartial.Path);

    return newQueryString.Count > 0
        ? String.Format("0?1", pagePathWithoutQueryString, newQueryString)
        : pagePathWithoutQueryString;

一个例子:

RemoveQueryStringByKey("https://www.google.co.uk/search?#hl=en&output=search&sclient=psy-ab&q=cookie", "q");

然后返回:

https://www.google.co.uk/search?#hl=en&output=search&sclient=psy-ab

【讨论】:

字符串不包含 FormatWith 方法的定义 有没有办法在不使用 FormatWith 的情况下做到这一点?这在 .NET 4.0 中不可用 如果 url 具有协议,则此方法有效。如果 Uri 构造函数丢失,则抛出它。即 new Uri("***.com") - 有效,但 new Uri("***.com") 无效。 那些提到无效格式问题的人,很可能已经在处理 URI。您可以简单地更改此方法以接受 Uri 而不是字符串 url。然后,您只需从字符串中删除创建一个的行。 这个答案错过了 Uri.Fragment(哈希 #xxx)处理。所以像“google.co.uk/…”这样的URL在处理后会丢失“#xxx”。所以返回值应该加上uri.Fragment【参考方案6】:

删除您的QueryString 之前的代码如下。

 PropertyInfo isreadonly = 
          typeof(System.Collections.Specialized.NameValueCollection).GetProperty(
          "IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
        // make collection editable
        isreadonly.SetValue(this.Request.QueryString, false, null);
        // remove
        this.Request.QueryString.Remove("yourKey");

【讨论】:

【参考方案7】:
public static string RemoveQueryStringByKey(string sURL, string sKey)
    
        string sOutput = string.Empty;
        string sToReplace = string.Empty;

        int iFindTheKey = sURL.IndexOf(sKey);
        if (iFindTheKey == -1) return (sURL);

        int iQuestion = sURL.IndexOf('?');
        if (iQuestion == -1) return (sURL);

        string sEverythingBehindQ = sURL.Substring(iQuestion);
        List<string> everythingBehindQ = new List<string>(sEverythingBehindQ.Split('&'));
        foreach (string OneParamPair in everythingBehindQ)
        
            int iIsKeyInThisParamPair = OneParamPair.IndexOf(sKey);
            if (iIsKeyInThisParamPair != -1)
            
                sToReplace = "&" + OneParamPair;
            
        

        sOutput = sURL.Replace(sToReplace, "");
        return (sOutput);
    

【讨论】:

【参考方案8】:
string url = HttpContext.Current.Request.Url.AbsoluteUri;
string[] separateURL = url.Split('?');

NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(separateURL[1]);
queryString.Remove("param_toremove");

string revisedurl = separateURL[0] + "?" + queryString.ToString();

【讨论】:

无查询时不处理的情况【参考方案9】:

对不起,这有点脏,但应该可以在旧框架中使用

public String RemoveQueryString( String rawUrl  , String keyName)

    var currentURL_Split =  rawUrl.Split('&').ToList();
    currentURL_Split = currentURL_Split.Where(o => !o.ToLower().StartsWith(keyName.ToLower()+"=")).ToList();
    String New_RemovedKey = String.Join("&", currentURL_Split.ToArray()); 
    New_RemovedKey = New_RemovedKey.Replace("&&", "&");
    return New_RemovedKey;

【讨论】:

【参考方案10】:

这是我的解决方案:

我添加了一些额外的输入验证。

public static void TryRemoveQueryStringByKey(ref string url, string key)

    if (string.IsNullOrEmpty(url) ||
        string.IsNullOrEmpty(key) ||
        Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute) == false)
    
        return false;
                

    try
    
        Uri uri = new Uri(url);

        // This gets all the query string key value pairs as a collection
        NameValueCollection queryCollection = HttpUtility.ParseQueryString(uri.Query);
        string keyValue = queryCollection.Get(key);

        if (url.IndexOf("&" + key + "=" + keyValue, StringComparison.OrdinalIgnoreCase) >= 0)
        
            url = url.Replace("&" + key + "=" + keyValue, String.Empty);
            return true;
        
        else if (url.IndexOf("?" + key + "=" + keyValue, StringComparison.OrdinalIgnoreCase) >= 0)
        
            url = url.Replace("?" + key + "=" + keyValue, String.Empty);
            return true;
        
        else
        
            return false;
        
    
    catch
    
        return false;
    

一些单元测试示例:

string url1 = "http://www.gmail.com?a=1&cookie=cookieValue"
Assert.IsTrue(TryRemoveQueryStringByKey(ref url1,"cookie")); //OUTPUT: "http://www.gmail.com?a=1"

string url2 = "http://www.gmail.com?cookie=cookieValue"  
Assert.IsTrue(TryRemoveQueryStringByKey(ref url2,"cookie")); //OUTPUT: "http://www.gmail.com"

string url3 = "http://www.gmail.com?cookie="  
Assert.IsTrue(TryRemoveQueryStringByKey(ref url2,"cookie")); //OUTPUT: "http://www.gmail.com"

【讨论】:

【参考方案11】:

我们也可以用正则表达式来做

string queryString = "Default.aspx?Agent=10&Language=2"; //Request.QueryString.ToString();
string parameterToRemove="Language";   //parameter which we want to remove
string regex=string.Format("(&0=[^&\s]+|(?<=\?)0=[^&\s]+&?)",parameterToRemove);   //this will not work for javascript, for javascript you can do following
string finalQS = Regex.Replace(queryString, regex, "");

//javascript(following is not js syntex, just want to give idea how we can able do it in js)
string regex1 = string.Format("(&0=[^&\s]+)",parameterToRemove);
string regex2 = string.Format("(\?0=[^&\s]+&?)",parameterToRemove);
string finalQS = Regex.Replace(queryString, regex1, "").Replace(queryString, regex2, "");

https://regexr.com/3i9vj

【讨论】:

不幸的是,您的模式也会在第一个项目上选择“结束”匹配(例如,更改 parameterToRemove="ent" 最终会得到 Default.aspx?AgLanguage=2)。如果您不必必须支持 javascript,则以下修正使用正向回溯来解决此问题:(&amp;0=[^&amp;\s]+|(?&lt;=\?)0=[^&amp;\s]+&amp;?)【参考方案12】:

在 System 命名空间中有一个名为 UriBuilder 的有用类。我们可以将它与几个扩展方法一起使用来执行以下操作:

Uri u = new Uri("http://example.com?key1=value1&key2=value2");
u = u.DropQueryItem("key1");

或者像这样:

Uri u = new Uri("http://example.com?key1=value1&key2=value2");
UriBuilder b = new UriBuilder(u);
b.RemoveQueryItem("key1");
u = b.Uri;

扩展方法:

using System;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;

public static class UriExtensions

    public static Uri DropQueryItem(this Uri u, string key)
    
        UriBuilder b = new UriBuilder(u);
        b.RemoveQueryItem(key);
        return b.Uri;
    

public static class UriBuilderExtensions

    private static string _ParseQueryPattern = @"(?<key>[^&=]+)=0,1(?<value>[^&]*)";
    private static Regex _ParseQueryRegex = null;

    private static Regex ParseQueryRegex
    
        get
        
            if (_ParseQueryRegex == null)
            
                _ParseQueryRegex = new Regex(_ParseQueryPattern, RegexOptions.Compiled | RegexOptions.Singleline);
            
            return _ParseQueryRegex;

        
    

    public static void SetQueryItem(this UriBuilder b, string key, string value)
    
        NameValueCollection parms = ParseQueryString(b.Query);
        parms[key] = value;
        b.Query = RenderQuery(parms);
    

    public static void RemoveQueryItem(this UriBuilder b, string key)
    
        NameValueCollection parms = ParseQueryString(b.Query);
        parms.Remove(key);
        b.Query = RenderQuery(parms);
           
    private static string RenderQuery(NameValueCollection parms)
    
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<parms.Count; i++)
        
            string key = parms.Keys[i];
            sb.Append(key + "=" + parms[key]);
            if (i < parms.Count - 1)
            
                sb.Append("&");
            
        
        return sb.ToString();
    
    public static NameValueCollection ParseQueryString(string query, bool caseSensitive = true)
    
        NameValueCollection pairs = new NameValueCollection(caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);

        string q = query.Trim().TrimStart(new char[] '?');
        MatchCollection matches = ParseQueryRegex.Matches(q);

        foreach (Match m in matches)
        
            string key = m.Groups["key"].Value;
            string value = m.Groups["value"].Value;
            if (pairs[key] != null)
            
                pairs[key] = pairs[key] + "," + value;
            
            else
            
                pairs[key] = value;
            

        

        return pairs;

    


【讨论】:

UriBuilder' 不包含“RemoveQueryItem”的定义,并且找不到接受“UriBuilder”类型的第一个参数的可访问扩展方法“RemoveQueryItem”(您是否缺少 using 指令或程序集引用?) 在 4.6 dotnet 版本上 @TommyHolman 对此感到抱歉。原来 RemoveQueryItem 是我自己在 UriBuilder 上的扩展方法。我已经更新了我的答案以包含它。【参考方案13】:

这是一个完整的解决方案,可以使用 >= 0 指定的参数和任何形式的 URL:

    /// <summary>
    /// Given a URL in any format, return URL with specified query string param removed if it exists
    /// </summary>
    public static string StripQueryStringParam(string url, string paramToRemove)
    
        return StripQueryStringParams(url, new List<string> paramToRemove);
    

    /// <summary>
    /// Given a URL in any format, return URL with specified query string params removed if it exists
    /// </summary>
    public static string StripQueryStringParams(string url, List<string> paramsToRemove)
    
        if (paramsToRemove == null || !paramsToRemove.Any()) return url;

        var splitUrl = url.Split('?');
        if (splitUrl.Length == 1) return url;

        var urlFirstPart = splitUrl[0];
        var urlSecondPart = splitUrl[1];

        // Even though in most cases # isn't available to context,
        // we may be passing it in explicitly for helper urls
        var secondPartSplit = urlSecondPart.Split('#');
        var querystring = secondPartSplit[0];
        var hashUrlPart = string.Empty;
        if (secondPartSplit.Length > 1)
        
            hashUrlPart = "#" + secondPartSplit[1];
        
        var nvc = HttpUtility.ParseQueryString(querystring);
        if (!nvc.HasKeys()) return url;

        // Remove any matches
        foreach (var key in nvc.AllKeys)
        
            if (paramsToRemove.Contains(key))
            
                nvc.Remove(key);
            
        

        if (!nvc.HasKeys()) return urlFirstPart;
        return urlFirstPart + 
               "?" + string.Join("&", nvc.AllKeys.Select(c => c.ToString() + "=" + nvc[c.ToString()])) + 
               hashUrlPart;
    

【讨论】:

【参考方案14】:

这个老问题的更现代的答案,以防其他人像我一样偶然发现它。

这是使用 Uri 类来解析 URL(如果你的 URL 已经在 Uri 对象中,可以跳过)和 LINQ 来过滤查询字符串。

public static string RemoveQueryStringByKey(string url, string key)

    var uri = new Uri(url, UriKind.Absolute);
    var queryParts = uri.Query
        .TrimStart('?')
        .Split('&')
        .Where(item => string.CompareOrdinal(item, key) != 0);
    return uri.Scheme + Uri.SchemeDelimiter
        + uri.Authority
        + uri.AbsolutePath
        + "?" + string.Join("&", queryParts);

【讨论】:

【参考方案15】:

我知道这是一个相当老的问题,但我读到的所有内容都感觉有点复杂。

public Uri GetUriWithoutQueryParam( Uri originalUri, string paramKey ) 
  NameValueCollection newQuery = HttpUtility.ParseQueryString( originalUri.Query );
  newQuery.Remove( paramKey );
  return new UriBuilder( originalUri )  Query = newQuery.ToString() .Uri;

【讨论】:

以上是关于如何通过键从 URL 中有效地删除查询字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Firebase 存储下载 URL 中删除查询字符串

如何有效地从另一个字符串中找到的字符串中删除重复字符?

如何有效地从 ArrayList 或字符串数​​组中删除所有空元素?

node.js 与 express 如何从 url 中删除查询字符串

如何将带有查询字符串的 url 作为 api 参数传递?

如何通过键从 GAE 数据存储中删除多个实体