Cara mengurai string kueri ke dalam NameValueCollection di .NET

186

Saya ingin mengurai string seperti p1=6&p2=7&p3=8menjadi NameValueCollection.

Apa cara paling elegan untuk melakukan ini ketika Anda tidak memiliki akses ke Page.Requestobjek?

Nathan Smith
sumber

Jawaban:

356

Ada utilitas .NET bawaan untuk ini: HttpUtility.ParseQueryString

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

Anda mungkin perlu mengganti querystringdengan new Uri(fullUrl).Query.

Guy Starbuck
sumber
26
Omar, itu tidak bekerja untuk saya di ASP.NET 4, itu mengembalikan kunci " stackoverflow.com?para " bukan "para". Jadi saya menggunakan HttpUtility.ParseQueryString (Uri baru (fullUrl) .Query) yang berfungsi dengan baik untuk saya.
Michael
2
qscoll ["p1"], qscoll ["p2"] dan qscoll ["p3"]
SMUsamaShah
5
ParseQueryString adalah ide yang sangat buruk untuk digunakan dalam aplikasi desktop, karena itu tidak termasuk dalam Profil Klien; mengapa menginstal 100 M perpustakaan tambahan di komputer klien untuk hanya menggunakan satu metode sederhana? Namun, sepertinya Microsoft tidak memiliki ide yang lebih baik. Satu-satunya cara adalah menerapkan metode sendiri atau menggunakan implementasi open source.
Vitalii
2
VASoftOnline: Dalam hal ini Anda dapat menggunakan implementasi Mono dari ParseQueryString: github.com/mono/mono/blob/master/mcs/class/System.Web/… lisensi untuk itu adalah MIT X11: github.com/mono/mono / blob / master / LICENSE
sw.
3
HttpUtility.ParseQueryStringakan menjadi rekomendasi saya kecuali bahwa dalam kasus HttpUtility.ParseQueryString("&X=1&X=2&X=3")hasilnya adalah ....X=1,2,3...Memiliki beberapa params dengan nama yang sama tidak umum tetapi diperlukan untuk mendukung parameter pengontrol seperti int [], IEnumerable <int> dll (param tersebut dapat digunakan untuk mendukung beberapa kotak centang) lihat "Beberapa kemunculan variabel string kueri yang sama dikonsolidasikan dalam satu entri" sesuai situs MS . Versi buatan tangan dari metode ini mungkin satu-satunya pilihan Anda
dunxz
43

HttpUtility.ParseQueryString akan bekerja selama Anda berada di aplikasi web atau tidak keberatan termasuk ketergantungan pada System.Web. Cara lain untuk melakukan ini adalah:

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);
   }
}
Scott Dorman
sumber
5
Anda harus memeriksa apakah bagian. Panjang> 1, untuk memastikan Anda dapat memanggil bagian [1]
Alexandru Pupsa
2
Bagaimana jika tidak ada nilai? misal string kueri dapat terlihat seperti ?foo=1&bar. HttpUtilityakan menguraikannya sebagai{ key = null, value = "bar" }
Thomas Levesque
Ini bagus dibandingkan dengan HttpUtility.ParseQueryString karena tidak memecahkan kode nilai (jadi nilai base64 yang dikodekan dipertahankan)
CRice
1
Sebenarnya, Anda masih perlu mengizinkan nilai '=' misalnya & kode = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = akan menghapus karakter '=' terakhir dihapus. Saya menulis ulang bagian dari kode Anda untuk mendapatkan indeks pertama '=' dan substring kunci dan nilai untuk memperbaikinya (alih-alih menggunakan split).
CRice
28

Banyak jawaban yang memberikan contoh khusus karena ketergantungan jawaban yang diterima pada System.Web . Dari paket NuGet Microsoft.AspNet.WebApi.Client ada UriExtensions.ParseQueryString , metode yang juga dapat digunakan:

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

Jadi, jika Anda ingin menghindari ketergantungan System.Web dan tidak ingin menjalankannya sendiri, ini adalah opsi yang baik.

James Skimming
sumber
3
Fungsi yang sama ada sebagai ekstensi dalam namespace System.Net.Http (lihat jawaban saya di bawah), tidak perlu untuk seluruh dependensi lain ...
jvenema
@jvenema Dari mana Anda menambahkan dependensi System.Net.Http.Formatting, saya percaya itu hanya disediakan dengan menambahkan paket NuGet Microsoft.AspNet.WebApi.Client.
James Skimming
19

Saya ingin menghapus ketergantungan pada System.Web sehingga saya dapat mengurai string kueri penyebaran ClickOnce, sementara prasyaratnya terbatas pada "Subset Kerangka Kerja Khusus Klien".

Saya menyukai jawaban rp. Saya menambahkan beberapa logika tambahan.

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;
    }
densom
sumber
ini sangat membantu untuk windows phone, Anda hanya perlu mengganti "NameValueCollection" dengan "SortedDictionnary <string, string>"
Mike Bryant
4
Hati-hati saat mengganti NameValueCollection untuk Kamus - keduanya tidak sama! String kueri mendukung beberapa kunci dengan nilai yang sama, dan begitu pula NameValueCollection.
Matt DeKrey
7

Saya membutuhkan fungsi yang sedikit lebih fleksibel daripada apa yang sudah disediakan saat bekerja dengan permintaan OLSC.

  • Nilai dapat berisi beberapa tanda sama dengan
  • Dekode karakter yang disandikan dalam nama dan nilai
  • Mampu berjalan pada Kerangka Klien
  • Mampu berjalan pada Kerangka Seluler.

Ini solusinya:

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

Mungkin bukan ide yang buruk <Extension()>untuk memperbaikinya juga untuk menambah kemampuan Uri itu sendiri.

Josh Brown
sumber
7

Untuk melakukannya tanpa System.Web, tanpa menulis sendiri, dan tanpa paket NuGet tambahan:

  1. Tambahkan referensi ke System.Net.Http.Formatting
  2. Menambahkan using System.Net.Http;
  3. Gunakan kode ini:

    new Uri(uri).ParseQueryString()

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

jvenema
sumber
3
Dari mana Anda menambahkan dependensi System.Net.Http.Formatting, saya yakin itu hanya disediakan dengan menambahkan paket NuGet Microsoft.AspNet.WebApi.Client.
James Skimming
Hah, salahku. Saya kira itu datang dengan kerangka kerja MVC yang diinstal secara otomatis, jadi saya tidak perlu menambahkan paket add'l (File Program (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net. Http.Formatting.dll)
jvenema
System.Net.Formatting EXTENSION VS2019 adalah daftar atau tab terpisah dari dari referensi kerangka kerja tradisional
Sql Surfer
3

Jika Anda ingin menghindari ketergantungan pada System.Web yang diperlukan untuk menggunakan HttpUtility.ParseQueryString , Anda bisa menggunakan Urimetode ekstensi yang ParseQueryStringditemukan diSystem.Net.Http .

Pastikan untuk menambahkan referensi (jika Anda belum) ke System.Net.Http dalam proyek Anda.

Perhatikan bahwa Anda harus mengonversi badan respons ke valid Uriagar ParseQueryString(in System.Net.Http) berfungsi.

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();
Amadeus Sánchez
sumber
System.Net.Formatting EXTENSION VS2019 menempatkan referensi ekstensi terpisah dari referensi kerangka kerja tradisional.
Sql Surfer
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 ] );    
            }    
        }
    }
rp.
sumber
5
titik koma juga diperbolehkan sebagai pemisah parameter dalam http, lebih baik tidak menemukan kembali roda
Matthew Lock
2

Saya baru menyadari bahwa Web API Client memiliki ParseQueryStringmetode ekstensi yang berfungsi pada Uridan mengembalikan HttpValueCollection:

var parameters = uri.ParseQueryString();
string foo = parameters["foo"];
Thomas Levesque
sumber
1

Cukup akses Request.QueryString. AllKeys disebut sebagai jawaban lain hanya memberi Anda berbagai kunci.

Anjing polisi
sumber
1

HttpUtility.ParseQueryString(Request.Url.Query)return adalah HttpValueCollection(kelas internal). Itu mewarisi dari 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); 
alex1kirch
sumber
1

Jika Anda tidak menginginkan ketergantungan System.Web, cukup tempel kode sumber ini dari kelas HttpUtility.

Saya baru saja mencabut ini bersama-sama dari kode sumber Mono . Ini berisi HttpUtility dan semua dependensinya (seperti IHtmlString, Helpers, HttpEncoder, HttpQSCollection).

Lalu gunakanHttpUtility.ParseQueryString .

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


sumber
1

Karena semua orang sepertinya menempelkan solusinya .. ini milik saya :-) Saya membutuhkan ini dari dalam perpustakaan kelas tanpa System.Web mengambil parameter id dari hyperlink yang tersimpan.

Saya pikir saya akan berbagi karena saya menemukan solusi ini lebih cepat dan lebih tampan.

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

Pemakaian:

Statics.QueryGet(url, "id")
Tiele Declercq
sumber
1
Hanya satu masalah dengan metode ini: string kueri dapat memiliki lebih dari satu nilai untuk parameter yang diberikan. Dalam hal ini, metode Anda akan melempar kesalahan kunci duplikat.
Thomas Levesque
ya, setidaknya gunakan NameValueCollection, querystrings dengan kunci duplikat sangat legal.
Chad Grant
Juga, kamus Anda peka terhadap huruf besar-kecil, jadi X = 1 dan x = 1 akan menjadi kunci yang berbeda. Perlu Kamus baru <string, string> (StringComparer.OrdinalIgnoreCase);
Chad Grant
0

Tekan Request.QueryString.Keys untuk NameValueCollection dari semua parameter string kueri.

Mark Glorie
sumber
0

Untuk mendapatkan semua nilai Querystring coba ini:

    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
mirko cro 1234
sumber
0
        var q = Request.QueryString;
        NameValueCollection qscoll = HttpUtility.ParseQueryString(q.ToString());
Hamit YILDIRIM
sumber
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;
}
Nahom Haile
sumber
-1

Saya menerjemahkan ke versi C # josh-brown di VB

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;
}
elgoya
sumber
-2

Ini kode saya, saya pikir ini sangat berguna:

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