如何将查询字符串解析为 .NET 中的 NameValueCollection

Posted

技术标签:

【中文标题】如何将查询字符串解析为 .NET 中的 NameValueCollection【英文标题】:How to parse a query string into a NameValueCollection in .NET 【发布时间】:2010-09-09 06:39:50 【问题描述】:

我想将p1=6&p2=7&p3=8 等字符串解析为NameValueCollection

当您无法访问 Page.Request 对象时,最优雅的方法是什么?

【问题讨论】:

【参考方案1】:

为此有一个内置的 .NET 实用程序:HttpUtility.ParseQueryString

// C#
NameValueCollection qscoll = HttpUtility.ParseQueryString(querystring);
' VB.NET
Dim qscoll As NameValueCollection = HttpUtility.ParseQueryString(querystring)

您可能需要将querystring 替换为new Uri(fullUrl).Query

【讨论】:

Omar,它在 ASP.NET 4 上对我不起作用,它返回的键是“***.com?para”而不是“para”。所以我正在使用 HttpUtility.ParseQueryString(new Uri(fullUrl).Query) 这对我来说是正确的。 qscoll["p1"] , qscoll["p2"] 和 qscoll["p3"] ParseQueryString 在桌面应用程序中使用真的很糟糕,因为它不包含在客户端配置文件中;为什么要在客户端计算机上安装 100 M 的附加库以仅使用一种简单的方法?但是,微软似乎没有更好的主意。唯一的方法是实现自己的方法或使用开源实现。 VASoftOnline:在这种情况下,您可以使用 ParseQueryString 的 Mono 实现:github.com/mono/mono/blob/master/mcs/class/System.Web/… 的许可证是 MIT X11:github.com/mono/mono/blob/master/LICENSE HttpUtility.ParseQueryString 是我的建议,但在 HttpUtility.ParseQueryString("&X=1&X=2&X=3") 的情况下,结果是 ....X=1,2,3... 具有多个同名参数并不常见,但需要支持控制器参数,例如 int[] , IEnumerable 等(此类参数可能用于支持多个复选框)请参阅MS site 中的“同一查询字符串变量的多次出现被合并到一个条目中”。该方法的手工版本可能是您唯一的选择【参考方案2】:

HttpUtility.ParseQueryString 只要您在 Web 应用程序中或不介意包含对 System.Web 的依赖项,就可以工作。另一种方法是:

NameValueCollection queryParameters = new NameValueCollection();
string[] querySegments = queryString.Split('&');
foreach(string segment in querySegments)

   string[] parts = segment.Split('=');
   if (parts.Length > 0)
   
      string key = parts[0].Trim(new char[]  '?', ' ' );
      string val = parts[1].Trim();

      queryParameters.Add(key, val);
   

【讨论】:

你应该检查parts.Length > 1,以确保你可以调用parts[1] 如果没有价值怎么办?例如查询字符串可能类似于?foo=1&barHttpUtility 会将其解析为 key = null, value = "bar" 与 HttpUtility.ParseQueryString 相比,这很棒,因为它不解码值(因此保留了 base64 编码值) 实际上,您仍然需要允许值 '=' 例如 &code=A0SYw34Hj/m++lH0s7r0l/yg6GWdymzSCbI2zOn3V4o= 将删除最后一个 '=' 字符。我重写了您的部分代码以获取“=”的第一个索引并将键和值子串化以解决此问题(而不是使用拆分)。 还有很多极端情况,这里没有介绍。【参考方案3】:

由于接受的答案依赖于System.Web,许多答案都提供了自定义示例。从Microsoft.AspNet.WebApi.Client NuGet 包中有一个UriExtensions.ParseQueryString,也可以使用该方法:

var uri = new Uri("https://***.com/a/22167748?p1=6&p2=7&p3=8");
NameValueCollection query = uri.ParseQueryString();

因此,如果您想避免 System.Web 依赖并且不想自己滚动,这是一个不错的选择。

【讨论】:

相同的函数作为扩展存在于 System.Net.Http 命名空间中(见下面我的回答),不需要另一个完整的依赖... @jvenema 从哪里添加 System.Net.Http.Formatting 依赖项,我相信它只是通过添加 Microsoft.AspNet.WebApi.Client NuGet 包提供的。 必须添加一个全新的 nuget 包作为依赖项有点疯狂,尤其是一个名称中包含 AspNet 的包,它闻起来只打算部署在服务器中(在我的情况下我需要这个用于移动/桌面 Xamarin 应用程序...)【参考方案4】:

我想删除对 System.Web 的依赖,以便我可以解析 ClickOnce 部署的查询字符串,同时将先决条件限制为“仅限客户端的框架子集”。

我喜欢 rp 的回答。我添加了一些额外的逻辑。

public static NameValueCollection ParseQueryString(string s)
    
        NameValueCollection nvc = new NameValueCollection();

        // remove anything other than query string from url
        if(s.Contains("?"))
        
            s = s.Substring(s.IndexOf('?') + 1);
        

        foreach (string vp in Regex.Split(s, "&"))
        
            string[] singlePair = Regex.Split(vp, "=");
            if (singlePair.Length == 2)
            
                nvc.Add(singlePair[0], singlePair[1]);
            
            else
            
                // only one key with no value specified in query string
                nvc.Add(singlePair[0], string.Empty);
            
        

        return nvc;
    

【讨论】:

这对windows phone 真的很有帮助,你只需要将“NameValueCollection”替换为“SortedDictionnary 在为字典切换 NameValueCollection 时要小心——它们不一样!查询字符串支持具有相同值的多个键,NameValueCollection 也是如此。【参考方案5】:

我需要一个比处理 OLSC 查询时已经提供的功能更通用的函数。

值可能包含多个等号 解码名称和值中的编码字符 能够在客户端框架上运行 能够在 Mobile Framework 上运行。

这是我的解决方案:

Public Shared Function ParseQueryString(ByVal uri As Uri) As System.Collections.Specialized.NameValueCollection
    Dim result = New System.Collections.Specialized.NameValueCollection(4)
    Dim query = uri.Query
    If Not String.IsNullOrEmpty(query) Then
        Dim pairs = query.Substring(1).Split("&"c)
        For Each pair In pairs
            Dim parts = pair.Split("="c, 2)

            Dim name = System.Uri.UnescapeDataString(parts(0))
            Dim value = If(parts.Length = 1, String.Empty,
                System.Uri.UnescapeDataString(parts(1)))

            result.Add(name, value)
        Next
    End If
    Return result
End Function

添加<Extension()> 以将功能添加到 Uri 本身可能不是一个坏主意。

【讨论】:

【参考方案6】:

要在没有System.Web 的情况下执行此操作,无需自己编写,也无需额外的 NuGet 包:

    添加对System.Net.Http.Formatting的引用 添加using System.Net.Http;

    使用此代码:

    new Uri(uri).ParseQueryString()
    

https://msdn.microsoft.com/en-us/library/system.net.http.uriextensions(v=vs.118).aspx

【讨论】:

你从哪里添加System.Net.Http.Formatting依赖,我相信只有添加Microsoft.AspNet.WebApi.Client NuGet包才能提供。 嗯,我的错。我猜它带有自动安装的 MVC 框架,所以我不必添加任何附加包(Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Net。 Http.Formatting.dll) System.Net.Formatting EXTENSION VS2019 是来自传统框架参考的单独列表或选项卡【参考方案7】:

如果您想避免使用HttpUtility.ParseQueryString 所需的对System.Web 的依赖,您可以使用System.Net.Http 中的ParseQueryString 扩展方法ParseQueryString

确保在您的项目中添加对System.Net.Http 的引用(如果您还没有)。

请注意,您必须将响应正文转换为有效的Uri,以便ParseQueryString(在System.Net.Http 中)有效。

string body = "value1=randomvalue1&value2=randomValue2";

// "http://localhost/query?" is added to the string "body" in order to create a valid Uri.
string urlBody = "http://localhost/query?" + body;
NameValueCollection coll = new Uri(urlBody).ParseQueryString();

【讨论】:

System.Net.Formatting EXTENSION VS2019 将扩展引用与传统框架引用分开。【参考方案8】:

我刚刚意识到Web API Client 有一个ParseQueryString 扩展方法,它适用于Uri 并返回一个HttpValueCollection

var parameters = uri.ParseQueryString();
string foo = parameters["foo"];

【讨论】:

System.Web.HttpUtility.ParseQueryString 还返回一个HttpValueCollection(内部派生自NameValueCollection)。两者都有相同的问题:它们不能正确解析裸键。【参考方案9】:

如果您不想要 System.Web 依赖项,只需从 HttpUtility 类中粘贴此源代码即可。

我只是从Mono 的源代码中将其组合在一起。它包含 HttpUtility 及其所有依赖项(如 IhtmlString、Helpers、HttpEncoder、HttpQSCollection)。

然后使用HttpUtility.ParseQueryString

https://gist.github.com/bjorn-ali-goransson/b04a7c44808bb2de8cca3fc9a3762f9c

【讨论】:

【参考方案10】:
    private void button1_Click( object sender, EventArgs e )
    
        string s = @"p1=6&p2=7&p3=8";
        NameValueCollection nvc = new NameValueCollection();

        foreach ( string vp in Regex.Split( s, "&" ) )
        
            string[] singlePair = Regex.Split( vp, "=" );
            if ( singlePair.Length == 2 )
            
                nvc.Add( singlePair[ 0 ], singlePair[ 1 ] );    
                
        
    

【讨论】:

http中也允许分号作为参数分隔符,最好不要重复造*** 当车轮坏了,最好更换它。 我的一个可悲的天真反应让我想在一个洞里爬行!完美的定义:我用正则表达式解决问题,现在我有两个问题。【参考方案11】:

只需访问 Request.QueryString。作为另一个答案提到的 AllKeys 只会为您提供一组键。

【讨论】:

【参考方案12】:

HttpUtility.ParseQueryString(Request.Url.Query) 返回是HttpValueCollection(内部类)。它继承自NameValueCollection

    var qs = HttpUtility.ParseQueryString(Request.Url.Query);
    qs.Remove("foo"); 

    string url = "~/Default.aspx"; 
    if (qs.Count > 0)
       url = url + "?" + qs.ToString();

    Response.Redirect(url); 

【讨论】:

【参考方案13】:

因为每个人似乎都在粘贴他的解决方案.. 这是我的 :-) 我需要在没有 System.Web 的类库中使用它来从存储的超链接中获取 id 参数。

我想分享一下,因为我发现这个解决方案更快更好看。

public static class Statics
    public static Dictionary<string, string> QueryParse(string url)
    
        Dictionary<string, string> qDict = new Dictionary<string, string>();
        foreach (string qPair in url.Substring(url.IndexOf('?') + 1).Split('&'))
        
            string[] qVal = qPair.Split('=');
            qDict.Add(qVal[0], Uri.UnescapeDataString(qVal[1]));
        
        return qDict;
    

    public static string QueryGet(string url, string param)
    
        var qDict = QueryParse(url);
        return qDict[param];
    

用法:

Statics.QueryGet(url, "id")

【讨论】:

这种方法只有一个问题:一个查询字符串对于一个给定的参数可以有多个值。在这种情况下,您的方法将引发重复键错误。 是的,至少使用 NameValueCollection,带有重复键的查询字符串是完全合法的。 另外,您的字典区分大小写,因此 X=1 和 x=1 将是不同的键。需要新字典(StringComparer.OrdinalIgnoreCase);【参考方案14】:

点击 Request.QueryString.Keys 获取所有查询字符串参数的 NameValueCollection。

【讨论】:

【参考方案15】:

要获取所有 Querystring 值,请尝试以下操作:

    Dim qscoll As NameValueCollection = HttpUtility.ParseQueryString(querystring)

Dim sb As New StringBuilder("<br />")
For Each s As String In qscoll.AllKeys

  Response.Write(s & " - " & qscoll(s) & "<br />")

Next s

【讨论】:

【参考方案16】:
        var q = Request.QueryString;
        NameValueCollection qscoll = HttpUtility.ParseQueryString(q.ToString());

【讨论】:

Request 仅适用于您使用 ASP.Net。【参考方案17】:

我在 VB 中翻译成 C# 版本的 josh-brown

private System.Collections.Specialized.NameValueCollection ParseQueryString(Uri uri)

    var result = new System.Collections.Specialized.NameValueCollection(4);
    var query = uri.Query;
    if (!String.IsNullOrEmpty(query))
    
        var pairs = query.Substring(1).Split("&".ToCharArray());
        foreach (var pair in pairs)
        
            var parts = pair.Split("=".ToCharArray(), 2);
            var name = System.Uri.UnescapeDataString(parts[0]);
            var value = (parts.Length == 1) ? String.Empty : System.Uri.UnescapeDataString(parts[1]);
            result.Add(name, value);
        
    
    return result;

【讨论】:

【参考方案18】:
let search = window.location.search;

console.log(search);

let qString = search.substring(1);

while(qString.indexOf("+") !== -1)

   qString  = qString.replace("+", "");

let qArray = qString.split("&");

let values = [];

for(let i = 0; i < qArray.length; i++)
   let pos = qArray[i].search("=");
   let keyVal = qArray[i].substring(0, pos);
   let dataVal = qArray[i].substring(pos + 1);
   dataVal = decodeURIComponent(dataVal);
   values[keyVal] = dataVal;

【讨论】:

【参考方案19】:

这是我的代码,我觉得很有用:

public String GetQueryString(string ItemToRemoveOrInsert = null, string InsertValue = null )

    System.Collections.Specialized.NameValueCollection filtered = new System.Collections.Specialized.NameValueCollection(Request.QueryString);
    if (ItemToRemoveOrInsert != null)
    
        filtered.Remove(ItemToRemoveOrInsert);
        if (!string.IsNullOrWhiteSpace(InsertValue))
        
            filtered.Add(ItemToRemoveOrInsert, InsertValue);
        
    

    string StrQr = string.Join("&", filtered.AllKeys.Select(key => key + "=" + filtered[key]).ToArray());
    if (!string.IsNullOrWhiteSpace(StrQr))
        StrQr="?" + StrQr;
    

    return StrQr;

【讨论】:

以上是关于如何将查询字符串解析为 .NET 中的 NameValueCollection的主要内容,如果未能解决你的问题,请参考以下文章

.NET Socket.Connect 将主机名解析为 IP 地址

如何使用查询将列数据解析为谷歌表格中的行

将查询字符串解析为数组

如何使用 ASP.NET Core 将查询字符串参数转换为看起来像目录部分?

如何解析 DateTime 并将其转换为 RFC 822 日期时间格式?

如何将数组中的真假字符串解析为布尔值