.NETでクエリ文字列を解析してNameValueCollectionにする方法


186

私は、次のような文字列を解析したいp1=6&p2=7&p3=8AにNameValueCollection

Page.Requestオブジェクトにアクセスできないときにこれを行う最もエレガントな方法は何ですか?

回答:


356

これには組み込みの.NETユーティリティがあります: HttpUtility.ParseQueryString

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

あなたは交換する必要があるかもしれませんquerystringnew Uri(fullUrl).Query


26
Omar、ASP.NET 4では動作しませんでした。「para」の代わりに「stackoverflow.com?para」のキーを返しました。したがって、私は正しく機能するHttpUtility.ParseQueryString(new Uri(fullUrl).Query)を使用しています。
マイケル

2
qscoll ["p1"]、qscoll ["p2"]およびqscoll ["p3"]
SMUsamaShah

5
ParseQueryStringはクライアントプロファイルに含まれていないため、デスクトップアプリケーションでの使用は非常に不適切です。クライアントコンピュータに100 Mの追加ライブラリをインストールして、1つの簡単な方法を使用する理由 ただし、Microsoftにはこれ以上のアイデアはないようです。唯一の方法は、独自のメソッドを実装するか、オープンソースの実装を使用することです。
Vitalii

2
VASoftOnline:その場合、ParseQueryStringのMono実装を使用できます:github.com/mono/mono/blob/master/mcs/class/System.Web/…そのためのライセンスはMIT X11です:github.com/mono/mono / blob / master / LICENSE
sw。

3
HttpUtility.ParseQueryString以下の場合にことを除いて、私の推薦になりHttpUtility.ParseQueryString("&X=1&X=2&X=3")、結果され....X=1,2,3...、同じ名前の複数のparamsを持つことはまれであるが、そのようなint型[]としてサポートコントローラパラメータに必要な、IEnumerableを<整数>など(などのparamsは、複数のチェックボックスをサポートするために使用される可能性があります)MSサイトの「同じクエリ文字列変数の複数のオカレンスが1つのエントリに統合される」を参照してください。メソッドの手作りバージョンが唯一の選択肢となる場合があります
dunxz

43

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

5
parts.Length> 1かどうかを確認して、parts [1]を呼び出せることを確認してください
Alexandru Pupsa

2
価値がない場合はどうなりますか?たとえば、クエリ文字列は次のようになり?foo=1&barます。HttpUtilityそれを次のように構文解析します{ key = null, value = "bar" }
Thomas Levesque

これはHttpUtility.ParseQueryStringと比較して優れています。これは、値をデコードしないため(base64でエンコードされた値が保持されるため)
CRice

1
実際には、値「=」を許可する必要があります。たとえば、&code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o =では、最後の「=」文字が削除されます。私はコードの一部を書き直して、 '='の最初のインデックスを取得し、キーと値をサブストリング化してこれを修正しました(分割を使用する代わりに)。
17

28

受け入れられた回答はSystem.Webに依存しているため、多くの回答はカスタム例を提供しています。Microsoft.AspNet.WebApi.Client NuGetパッケージがありUriExtensions.ParseQueryStringも使用することができ、この方法は:

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

したがって、System.Webへの依存を避け、独自のロールを行いたくない場合は、これが適切なオプションです。


3
同じ関数がSystem.Net.Http名前空間の拡張として存在します(以下の私の回答を参照)。別の完全な依存関係は必要ありません...
jvenema

@jvenema System.Net.Http.Formatting依存関係をどこから追加すると、Microsoft.AspNet.WebApi.Client NuGetパッケージを追加することによってのみ提供されると思います。
Jamesスキミング

19

「クライアントのみのフレームワークサブセット」に限定された前提条件を維持しながら、ClickOnce配置のクエリ文字列を解析できるように、System.Webへの依存関係を削除したかったのです。

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 <string、string>」に置き換えるだけです
Mike Bryant

4
辞書のNameValueCollectionを切り替えるときは注意してください-同じではありません!クエリ文字列は、同じ値を持つ複数のキーをサポートし、NameValueCollectionもサポートします。
Matt DeKrey、2014年

7

OLSCクエリを操作するときにすでに提供されているものよりも少し多機能な関数が必要でした。

  • 値には複数の等号を含めることができます
  • 名前と値の両方でエンコードされた文字をデコードする
  • クライアントフレームワークで実行可能
  • モバイルフレームワークで実行できます。

これが私の解決策です:

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自体に機能を追加するために、これにも取り組むのは悪い考えではないかもしれません。


7

System.Web自分で作成せずに、追加のNuGetパッケージなしでこれを行うには:

  1. への参照を追加 System.Net.Http.Formatting
  2. 追加 using System.Net.Http;
  3. このコードを使用してください:

    new Uri(uri).ParseQueryString()

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


3
System.Net.Http.Formatting依存関係をどこから追加するのかは、Microsoft.AspNet.WebApi.Client NuGetパッケージを追加することによってのみ提供されると思います。
Jamesスキミング

ええと、私の悪い。自動インストールされるMVCフレームワークに付属していると思うので、追加パッケージ(Program Files(x86)\ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net。)を追加する必要はありませんでした。 Http.Formatting.dll)
jvenema

System.Net.Formatting EXTENSION VS2019は、従来のフレームワーク参照からの別のリストまたはタブです
Sql Surfer

3

あなたが使用するために必要なのSystem.Webへの依存を回避したい場合はHttpUtility.ParseQueryStringを、あなたが使用できるUri拡張メソッドがParseQueryStringでましたSystem.Net.Http

参照を追加してください(まだ追加していない場合)。 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では、拡張参照を従来のフレームワーク参照とは別に配置します。
SQLサーファー2018

2
    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 ] );    
            }    
        }
    }

5
セミコロンは、httpのパラメータ区切り文字としても使用できます。ホイールを再発明しない方がよい
Matthew Lock


1

Request.QueryStringにアクセスするだけです。別の答えとして言及されているAllKeysは、キーの配列を取得するだけです。


1

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); 

1

System.Web依存関係が必要ない場合は、HttpUtilityクラスからこのソースコードを貼り付けます。

私はこれをMonoのソースコードから一緒にホイップしました。HttpUtilityとそのすべての依存関係(IHtmlString、Helpers、HttpEncoder、HttpQSCollectionなど)が含まれています。

次にを使用しますHttpUtility.ParseQueryString

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


1

誰もが彼の解決策を貼り付けているようです..これが私のものです:-)私はクラスライブラリ内から 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")

1
このメソッドの1つの問題:クエリ文字列は、特定のパラメーターに対して複数の値を持つことができます。この場合、メソッドは重複キーエラーをスローします。
Thomas Levesque 14

はい、少なくともNameValueCollectionを使用してください。重複するキーを持つクエリ文字列は完全に合法です。
チャドグラント

また、辞書では大文字と小文字が区別されるため、X = 1とx = 1は異なるキーになります。新しいDictionary <string、string>(StringComparer.OrdinalIgnoreCase);が必要です。
チャドグラント


0

すべての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


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

-1

VBでjosh-brownのC#バージョンに変換します

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

-2

これは私のコードです、それは非常に便利だと思います:

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.