【问题标题】:Good way to parse query string解析查询字符串的好方法
【发布时间】:2011-01-10 11:51:16
【问题描述】:

我有一个String,其中包含以下内容:

?workarea=London+&+Home+Counties+Ltd&sub=fs&&&FASh*5

类似于 URI 查询字符串。解析这个字符串(workareasub)的元素而不搞乱字符串操作的最佳方法是什么?

如果我使用 HttpUtility.ParseQueryString 会卡住,因为这两个元素都包含 &。但是,如果我先对整个事物进行编码,我就会失去元素的分离。理想的输出是:

  • 工作区 = London & Home Counties Ltd
  • sub = fs&&&FASh*5

【问题讨论】:

  • 只需使用Server.URLEncode 对每个值进行编码..
  • 这就是我想要做的 - 但我需要先分离所述值
  • ParseQueryString 是最好的选择。 ?name=black&white 是有效的,但并不意味着你想要它的意思。此外,空间的+ 已经过时了。你从哪里得到这个字符串?
  • @Kobi - 我不同意,谷歌使用 + 表示空格
  • 这是否意味着您无法控制原始字符串,因为我认为这是您的问题所在。

标签: asp.net parsing url uri urlencode


【解决方案1】:

您可以使用此自定义函数...快速测试表明,使用您最初在问题中提供的字符串,它会返回所需的输出,即两项,一项带有键 sub 和值 fs&&&FASh*5,另一个带有键workarea 和价值 London+&Home+Counties+Ltd

public Dictionary<string, string> ParseQueryString(string qs)
{
    Dictionary<string, string> items = new Dictionary<string, string>();
    string valueBuffer = string.Empty;
    string keyBuffer = string.Empty;
    bool lookingForValue = true;
    for (int i = qs.Length - 1; i >= 0; i--)
    {
        char curChar = qs[i];
        if (curChar.Equals('='))
        {
            lookingForValue = false;
            keyBuffer = string.Empty;
        }
        else if (curChar.Equals('&') && !lookingForValue)
        {
            items.Add(keyBuffer, valueBuffer);
            valueBuffer = string.Empty;
            lookingForValue = true;
        }
        else if (curChar.Equals('?'))
        {
            if (keyBuffer.Length > 0)
                items.Add(keyBuffer, valueBuffer);
            break;
        }
        else
        {
            if (lookingForValue)
                valueBuffer = curChar + valueBuffer;
            else
                keyBuffer = curChar + keyBuffer;
        }
    }

    return items;
}

正如我在评论中所说,如果用于真正的查询字符串,请使用 Server.URLEncode 对每个值进行编码。

快速解释:不是根据无法完成的&amp;解析查询字符串,而是寻找=字符,找到后开始寻找之前出现的&amp;

【讨论】:

  • 不错的解决方案。我只是希望键中也没有 & 的可能性。 :)
  • @Chris 哈哈,这太过分了.. 用大红色的不可能标志来渲染整个事情。 ;-)
【解决方案2】:

我认为您需要进行一些编码...您似乎希望 & 既用作分隔符又用作数据而无需转义。一个简单的解析器将无法判断您指的是哪种用法(就像您尝试 ParseQueryString 方法时一样)。

如果您知道可能的元素名称是什么(例如 workarea、sub),那么您可以使用它来更准确地确定哪些 & 是分隔符,哪些是数据,方法是假设任何 & 后跟元素名称是分隔符和任何其他人不是。我认为这已经进入了“搞乱字符串操作”的领域......

不过,我的第一个行动方案是尽可能更改输入字符串的内容,以使其定义更明确且不那么模棱两可。

【讨论】:

  • 我同意这一点,让输入字符串不那么模棱两可
【解决方案3】:

这可以很好地使用正则表达式。当然,这取决于您的确切定义,但这是我采取的:

  • 密钥不能包含&amp;= - 否则会产生歧义。
  • 值不能包含= - 我们也许可以解决这个问题,但这种方式要简单得多。
  • 一个值将被匹配到字符串的末尾,或者直到还有一个 & 符号。如果值的末尾有多个与号,这应该很好用:a=12&amp;&amp;&amp;&amp;b=3 -> a=12&amp;&amp;&amp;, b=3

代码如下:

MatchCollection parameters = Regex.Matches(query, "([^?&=]+)=([^=]+)(?=&|$)");

现在您有了一个键和值的集合,其中每个 Match 上的第二个 Group 是键(索引 1),第三个是值(索引 2)。
例如,您可以将匹配项转换为字典(如果您没有任何重复的键):

var values = parameters.Cast<Match>()
                .ToDictionary(m => m.Groups[1].Value,
                              m => HttpUtility.UrlDecode(m.Groups[2].Value),
                              StringComparer.OrdinalIgnoreCase);
string workAread = values["workarea"];

【讨论】:

    【解决方案4】:

    我最近碰巧写了一个blog post,其中还包含一个用于操作查询字符串参数的小型实用程序类。以下是一些示例用例(摘自我的帖子):

    QueryStringHelper qsh = new QueryStringHelper("?page=5&username=dan&year=2010&enabled=true&email=dan@example.com");
    
    string username = qsh.GetByName("username"); // username = "dan"
    
    qsh.Add("category", "products"); // adds a new key called "category" with the value "products"
    
    qsh.AddOrReplace("year", "1999"); // changes the year value from "2010" to "1999"
    
    int year = qsh.GetByName<int>("year"); // year = 1999
    
    qsh.AddOrReplace("page", 6); // changes the value of "page" to "6"
    
    bool enabled = qsh.GetByName<bool>("enabled"); // enabled = true
    
    qsh.RemoveByName("email"); // removes the "email" key
    
    string qs = qsh.GetQueryString(); // qs = "page=6&username=dan&year=1999&enabled=true&category=products";
    
    int count = qsh.Count(); // count = 5
    

    我希望你觉得它有用。

    【讨论】:

    • 这实际上是处理 & 作为数据而不是分隔符的原始问题吗?我没有看过你的 QSH 类,但我想如果它是针对查询字符串的,它会假设所有 & 都是分隔符。
    • @Chris - 你是对的。我显然没有正确阅读问题。
    猜你喜欢
    • 2012-04-24
    • 2010-11-15
    • 1970-01-01
    • 2019-05-03
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    相关资源
    最近更新 更多