Bir sorgu dizesini .NET'te bir NameValueCollection içine ayrıştırma


186

Ben gibi bir dize ayrıştırmak istiyoruz p1=6&p2=7&p3=8a içine NameValueCollection.

Page.RequestNesneye erişiminiz olmadığında bunu yapmanın en zarif yolu nedir ?

Yanıtlar:


356

Bunun için yerleşik bir .NET yardımcı programı vardır: HttpUtility.ParseQueryString

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

Sen değiştirmeniz gerekebilir querystringile new Uri(fullUrl).Query.


26
Ömer, ASP.NET 4'te benim için çalışmadı , "para" yerine " stackoverflow.com?para " anahtarını döndürdü . Bu yüzden doğru benim için çalışan HttpUtility.ParseQueryString (yeni Uri (fullUrl) .Query) kullanıyorum.
Michael

2
qscoll ["p1"], qscoll ["p2"] ve qscoll ["p3"]
SMUsamaShah

5
ParseQueryString, İstemci Profiline dahil edilmediğinden masaüstü uygulamasında kullanmak için gerçekten kötü bir fikirdir; neden tek bir basit yöntem kullanmak için istemci bilgisayara 100 M ek kitaplıklar yüklemek için? Ancak, Microsoft'un daha iyi bir fikri yok gibi görünüyor. Tek yol kendi yöntemini uygulamak veya açık kaynak uygulamasını kullanmaktır.
Vitalii

2
VASoftOnline: Bu durumda ParseQueryString'in Mono uygulamasını kullanabilirsiniz: github.com/mono/mono/blob/master/mcs/class/System.Web/… bunun için lisans MIT X11: github.com/mono/mono / blob / master / LİSANS
sw.

3
HttpUtility.ParseQueryStringHttpUtility.ParseQueryString("&X=1&X=2&X=3")sonuç durumunda ....X=1,2,3...aynı adda birden fazla parametre olması nadir olmakla birlikte int [], IEnumerable <int> vb. MS sitesine göre bkz. "Aynı sorgu dizesi değişkeninin birden çok örneği bir girişte birleştirilir" . Yöntemin el işi bir versiyonu tek seçeneğiniz olabilir
dunxz

43

HttpUtility.ParseQueryString, bir web uygulamasında olduğunuz sürece veya System.Web'e bağımlılık eklemenin bir sakıncası yoksa çalışacaktır. Bunu yapmanın başka bir yolu:

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
parçaları> 1, uzunluğu arayabildiğinizden emin olmak için [1]
Alexandru Pupsa

2
Değer yoksa ne olur? örneğin bir sorgu dizesi gibi görünebilir ?foo=1&bar. HttpUtilityayrıştırmak istiyorum{ key = null, value = "bar" }
Thomas Levesque

Bu, HttpUtility.ParseQueryString ile karşılaştırıldığında harika bir değerdir, çünkü değerlerin kodunu
çözmez

1
Aslında, hala '=' değerine izin vermeniz gerekiyor, örneğin & code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = son '=' karakteri kaldırılacak. Kodunuzun bir kısmını '=' ilk dizinini almak için yeniden yazdım ve bunu düzeltmek için anahtar ve değeri düzeltin (split kullanmak yerine).
CRice

28

Yanıtların çoğu, kabul edilen yanıtın System.Web'e bağımlılığı nedeniyle özel örnekler vermektedir . Gönderen Microsoft.AspNet.WebApi.Client Nuget paketinin bir var UriExtensions.ParseQueryString da kullanılabilir, yöntem:

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

System.Web bağımlılığından kaçınmak ve kendi başınızı döndürmek istemiyorsanız, bu iyi bir seçenektir.


3
Aynı işlev System.Net.Http ad alanında bir uzantı olarak da var (aşağıdaki
cevabıma

@jvenema System.Net.Http.Formatting bağımlılığını nereden ekliyorsunuz, yalnızca Microsoft.AspNet.WebApi.Client NuGet paketini ekleyerek sağlandığına inanıyorum.
James Skimming

19

Önkoşullar "Yalnızca istemci Framework Alt Kümesi" ile sınırlıyken, bir ClickOnce dağıtımının sorgu dizesini ayrıştırmak böylece System.Web bağımlılığını kaldırmak istedim.

RP'nin cevabını beğendim. Biraz ek mantık ekledim.

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

Bu windows telefon için gerçekten yararlı, sadece "NameValueCollection" yerine "SortedDictionnary <string, string>" ile değiştirmek zorunda
Mike Bryant

4
Bir Sözlük için NameValueCollection öğesini değiştirirken dikkatli olun - bunlar aynı değildir! Sorgu dizeleri aynı değere sahip birden çok anahtarı destekler ve NameValueCollection da destekler.
Matt DeKrey

7

OLSC sorguları ile çalışırken sağlanandan biraz daha yönlü bir fonksiyona ihtiyacım vardı.

  • Değerler birden çok eşit işaret içerebilir
  • Kodlanmış karakterleri hem ad hem de değer olarak deşifre edin
  • Client Framework üzerinde çalışabilir
  • Mobile Framework üzerinde çalışabilir.

İşte benim çözümüm:

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()>Yeteneği Uri'nin kendisine eklemek için bunun üstesinden gelmek kötü bir fikir olmayabilir .


7

Bunu System.Webkendiniz yazmadan ve ek NuGet paketleri olmadan yapmak için:

  1. Referans ekleyin System.Net.Http.Formatting
  2. Ekle using System.Net.Http;
  3. Bu kodu kullanın:

    new Uri(uri).ParseQueryString()

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


3
System.Net.Http.Formatting bağımlılığını nereden ekliyorsunuz, yalnızca Microsoft.AspNet.WebApi.Client NuGet paketini ekleyerek sağlandığına inanıyorum.
James Skimming

Ha, benim hatam. Sanırım otomatik olarak yüklenen MVC çerçevesi ile geldi, bu yüzden herhangi bir add'l paketi (Program Dosyaları (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net eklemek zorunda kalmadım. Http.Formatting.dll)
jvenema

System.Net.Formatting EXTENSION VS2019, geleneksel çerçeve referanslarından ayrı bir liste veya sekmedir
Sql Surfer

3

Kullanmak için gereklidir System.Web bağımlılığını önlemek istiyorsanız HttpUtility.ParseQueryString şunu kullanabilirsiniz Uriuzatma yöntemi ParseQueryStringbulundu System.Net.Http.

System.Net.HttpProjenize bir referans (daha önce yapmadıysanız) eklediğinizden emin olun .

Yanıt gövdesini (in ) çalışacak Urişekilde geçerli bir biçime dönüştürmeniz gerektiğini unutmayın .ParseQueryStringSystem.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, uzantı referanslarını geleneksel çerçeve referanslarından ayırır.
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 ] );    
            }    
        }
    }

5
noktalı virgül, http'de parametre ayırıcı olarak da kullanılabilir, tekerleği yeniden icat etmemek daha iyidir
Matthew Lock

2

Sadece fark Web API Müşteri bir sahip ParseQueryStringuzatma yöntemi bir üzerinde çalışır Urive getiri a HttpValueCollection:

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

1

Request.QueryString'e erişmeniz yeterlidir. Başka bir cevap olarak bahsedilen AllKeys sadece bir dizi anahtar alır.


1

HttpUtility.ParseQueryString(Request.Url.Query)dönüş HttpValueCollection(iç sınıf). Oradan miras alır 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

Herkes onun çözüm yapıştırma gibi görünüyor .. İşte benim :-) Ben System.Websaklanan köprüler id parametreleri getirmeden bir sınıf kitaplığı içinde bu gerekli .

Paylaşacağımı düşündüm çünkü bu çözümü daha hızlı ve daha iyi buluyorum.

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

Kullanımı:

Statics.QueryGet(url, "id")

1
Bu yöntemle ilgili tek bir sorun var: Bir sorgu dizesi belirli bir parametre için birden fazla değere sahip olabilir. Bu durumda, yönteminiz yinelenen bir anahtar hatası atar.
Thomas Levesque

Evet, en azından bir NameValueCollection kullanın, yinelenen anahtarlara sahip sorgu dizeleri tamamen yasaldır.
Chad Grant

Ayrıca, sözlüğünüz büyük / küçük harfe duyarlıdır, bu nedenle X = 1 ve x = 1 farklı anahtarlar olacaktır. Yeni Sözlük Gerekiyor <string, string> (StringComparer.OrdinalIgnoreCase);
Chad Grant

0

Tüm sorgu dizesi parametrelerinin NameValueCollection için Request.QueryString.Keys tuşuna basın.


0

Tüm Querystring değerlerini almak için şunu deneyin:

    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
        var q = Request.QueryString;
        NameValueCollection qscoll = HttpUtility.ParseQueryString(q.ToString());

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

Ben VB josh-brown C # sürümüne çevirmek

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

Bu benim kod, çok yararlı olduğunu düşünüyorum:

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.