C# 解析 URL URI 中的参数

这段代码是一个用于处理URL查询参数的C#工具类,主要提供解析和构建URL的功能。

 
namespace System
{
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Text;
 
    public static class UrlHelper
    {
        /// <summary>
        /// 解析URL中的参数。<br />
        /// 注意:在<see cref="Dictionary{TKey, TValue}"/>中,直接读取不存在的键值对时,会抛出异常。<br />
        /// <br />
        /// 支持解析示例:<br />
        /// https://www.google.com/index?page=1&lang=eng <br />
        /// https://www.google.com/ <br />
        /// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
        /// https://www.google.com/index? <br />
        /// </summary>
        /// <param name="url"></param>
        /// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
        /// <param name="ignoreCase"></param>
        /// <returns></returns>
        public static Dictionary<string, string> GetQueryDictionary(string url, string baseUrlKey = null, bool ignoreCase = false)
        {
            StringComparer comparer;
            if (ignoreCase)
                comparer = StringComparer.InvariantCultureIgnoreCase;
            else
                comparer = StringComparer.InvariantCulture;
            return GetQueryDictionary(url, baseUrlKey, comparer);
        }

        /// <summary>
        /// 解析URL中的参数。<br />
        /// 注意:在<see cref="Dictionary{TKey, TValue}"/>中,直接读取不存在的键值对时,会抛出异常。<br />
        /// <br />
        /// 支持解析示例:<br />
        /// https://www.google.com/index?page=1&lang=eng <br />
        /// https://www.google.com/ <br />
        /// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
        /// https://www.google.com/index? <br />
        /// </summary>
        /// <param name="url"></param>
        /// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public static Dictionary<string, string> GetQueryDictionary(string url, string baseUrlKey, StringComparer comparer)
        {

            // 第一个“?”符号的下标。
            // 用于支持,参数中包括“?”符号的URL。
            int indexQuestionMark = url.IndexOf('?');
            int countQuery = url.Length - indexQuestionMark - 1;

            Dictionary<string, string> info = null;

            // 如果URL中包括有效的参数。
            if (indexQuestionMark > -1 && countQuery > 0)
            {
                string queryString = url.Substring(indexQuestionMark + 1, countQuery);

                // 为空的键值对没有意义,所以,舍弃为空的键值对。
                string[] keyAndValuePairs = queryString.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
                info = new Dictionary<string, string>(keyAndValuePairs.Length + 1, comparer);
                foreach (var pair in keyAndValuePairs)
                {
                    // 第一个“=”符号的下标。
                    // 用于支持,value中包括“=”符号的参数。
                    int indexEquals = pair.IndexOf('=');

                    // 如果包含“=”符号。
                    if (indexEquals > -1)
                    {
                        string key = pair.Substring(0, indexEquals);
                        key = Uri.UnescapeDataString(key);

                        int countValue = pair.Length - indexEquals - 1;
                        // 避免“=”符号后面没有内容时,indexEquals + 1超出数组的有效索引。
                        string value = (countValue == 0) ? string.Empty : pair.Substring(indexEquals + 1, countValue);
                        value = Uri.UnescapeDataString(value);

                        info[key] = value;
                    }
                    // 用关键字保存特殊参数。
                    else
                    {
                        info[pair] = null;
                    }
                }
            }
            info = info ?? new Dictionary<string, string>(comparer);

            if (baseUrlKey != null)
            {
                if (indexQuestionMark < 0 || indexQuestionMark > url.Length)
                {
                    indexQuestionMark = url.Length;
                }
                // URL中符号“?”的前面部分。
                string baseUrlValue = url.Substring(0, indexQuestionMark);
                info[baseUrlKey] = baseUrlValue;
            }
            return info;
        }

        /// <summary>
        /// 解析URL中的参数。<br />
        /// 注意:在<see cref="NameValueCollection"/>中,直接读取不存在的键值对时,返回null,不会抛出异常。<br />
        /// <br />
        /// 支持解析示例:<br />
        /// https://www.google.com/index?page=1&lang=eng <br />
        /// https://www.google.com/ <br />
        /// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
        /// https://www.google.com/index? <br />
        /// </summary>
        /// <param name="url"></param>
        /// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
        /// <param name="ignoreCase"></param>
        /// <returns></returns>
        public static NameValueCollection GetQueryCollection(string url, string baseUrlKey = null, bool ignoreCase = false)
        {
            StringComparer comparer;
            if (ignoreCase)
                comparer = StringComparer.InvariantCultureIgnoreCase;
            else
                comparer = StringComparer.InvariantCulture;
            return GetQueryCollection(url, baseUrlKey, comparer);
        }

        /// <summary>
        /// 解析URL中的参数。<br />
        /// 注意:在<see cref="NameValueCollection"/>中,直接读取不存在的键值对时,返回null,不会抛出异常。<br />
        /// <br />
        /// 支持解析示例:<br />
        /// https://www.google.com/index?page=1&lang=eng <br />
        /// https://www.google.com/ <br />
        /// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
        /// https://www.google.com/index? <br />
        /// </summary>
        /// <param name="url"></param>
        /// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public static NameValueCollection GetQueryCollection(string url, string baseUrlKey, StringComparer comparer)
        {

            // 第一个“?”符号的下标。
            // 用于支持,参数中包括“?”符号的URL。
            int indexQuestionMark = url.IndexOf('?');
            int countQuery = url.Length - indexQuestionMark - 1;

            NameValueCollection info = null;

            // 如果URL中包括有效的参数。
            if (indexQuestionMark > -1 && countQuery > 0)
            {
                string queryString = url.Substring(indexQuestionMark + 1, countQuery);

                // 为空的键值对没有意义,所以,舍弃为空的键值对。
                string[] keyAndValuePairs = queryString.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
                info = new NameValueCollection(keyAndValuePairs.Length + 1, comparer);
                foreach (var pair in keyAndValuePairs)
                {
                    // 第一个“=”符号的下标。
                    // 用于支持,value中包括“=”符号的参数。
                    int indexEquals = pair.IndexOf('=');

                    // 如果包含“=”符号。
                    if (indexEquals > -1)
                    {
                        string key = pair.Substring(0, indexEquals);
                        key = Uri.UnescapeDataString(key);

                        int countValue = pair.Length - indexEquals - 1;
                        // 避免“=”符号后面没有内容时,indexEquals + 1超出数组的有效索引。
                        string value = (countValue == 0) ? string.Empty : pair.Substring(indexEquals + 1, countValue);
                        value = Uri.UnescapeDataString(value);

                        info.Add(key, value);
                    }
                    // 用关键字保存特殊参数。
                    else
                    {
                        info.Add(pair, null);
                    }
                }
            }
            info = info ?? new NameValueCollection(comparer);

            if (baseUrlKey != null)
            {
                if (indexQuestionMark < 0 || indexQuestionMark > url.Length)
                {
                    indexQuestionMark = url.Length;
                }
                // URL中符号“?”的前面部分。
                string baseUrlValue = url.Substring(0, indexQuestionMark);
                info.Add(baseUrlKey, baseUrlValue);
            }
            return info;
        }

        public static string GetUrlQueryString(ICollection<KeyValuePair<string, string>> parameters)
        {
            List<string> pairs = new List<string>(parameters.Count);
            foreach (KeyValuePair<string, string> item in parameters)
            {
                if (!string.IsNullOrEmpty(item.Value))
                {
                    pairs.Add(string.Format("{0}={1}", Uri.EscapeDataString(item.Key), Uri.EscapeDataString(item.Value)));
                }
            }
            return string.Join("&", pairs.ToArray());
        }
 
        public static string GetUrlQueryString(NameValueCollection parameters)
        {
            List<string> pairs = new List<string>(parameters.Count * 2);
            foreach (object itemKeyObj in parameters.Keys)
            {
                string itemKey = itemKeyObj?.ToString();
                if (itemKey != null)
                {
                    var itemValues = parameters.GetValues(itemKey);
                    if (itemValues != null)
                    {
                        foreach (var itemValue in itemValues)
                        {
                            if (!string.IsNullOrEmpty(itemValue))
                            {
                                pairs.Add(string.Format("{0}={1}", Uri.EscapeDataString(itemKey), Uri.EscapeDataString(itemValue)));
                            }
                        }
                    }
                }
            }
            return string.Join("&", pairs.ToArray());
        }
 
        public static string GetUrlString(string baseUrl, ICollection<KeyValuePair<string, string>> parameters)
        {
            if (parameters != null && parameters.Count > 0)
            {
                string queryString = GetUrlQueryString(parameters);
                if (!string.IsNullOrEmpty(queryString))
                {
                    StringBuilder builder = new StringBuilder(baseUrl.Length + queryString.Length + 1);
                    builder.Append(baseUrl);
                    builder.Append("?");
                    builder.Append(queryString);
                    return builder.ToString();
                }
            }
            return baseUrl;
        }
 
        public static string GetUrlString(string baseUrl, NameValueCollection parameters)
        {
            if (parameters != null && parameters.Count > 0)
            {
                string queryString = GetUrlQueryString(parameters);
                if (!string.IsNullOrEmpty(queryString))
                {
                    StringBuilder builder = new StringBuilder(baseUrl.Length + queryString.Length + 1);
                    builder.Append(baseUrl);
                    builder.Append("?");
                    builder.Append(queryString);
                    return builder.ToString();
                }
            }
            return baseUrl;
        }
    }
}

这段代码是一个用于处理URL查询参数的C#工具类,主要提供解析和构建URL的功能。以下是其核心内容的详细介绍:

---

### **主要功能**
1. **解析URL参数**  
   - **`GetQueryDictionary`**: 将URL的查询参数解析为`Dictionary<string, string>`,处理重复键时会覆盖,支持大小写敏感/不敏感。
   - **`GetQueryCollection`**: 将URL的查询参数解析为`NameValueCollection`,允许重复键和多个值,适合需要保留多值参数的场景。

2. **构建URL查询字符串**  
   - **`GetUrlQueryString`**: 从键值对集合或`NameValueCollection`生成URL编码的查询字符串(如`key1=val1&key2=val2`)。
   - **`GetUrlString`**: 将基础URL与参数拼接成完整的URL(如`http://example.com?key=val`)。

---

### **关键实现细节**
1. **参数解析逻辑**  
   - 通过定位第一个`?`分割URL的基地址和查询参数。
   - 使用`Split('&')`分割键值对,处理值中包含的`=`符号(如`key=a=b`解析为`key="a=b"`)。
   - 对键和值进行URL解码(`Uri.UnescapeDataString`)。

2. **特殊处理**  
   - **空值处理**:形如`key=`的参数解析为`key: ""`,构建时若值为空则跳过。
   - **无值键处理**:形如`key`的参数解析为`key: null`。
   - **基地址存储**:通过`baseUrlKey`参数将`?`前的URL部分存入结果(如`baseUrlKey: "url"`会添加`url: "http://example.com"`)。

3. **大小写控制**  
   - 通过`StringComparer`实现键的大小写敏感/不敏感比较。

---

### **潜在问题与注意事项**
1. **URL拼接限制**  
   - 若`baseUrl`已包含查询参数或哈希(`#`),拼接时可能出错(如`http://example.com?old=1`拼接后变为`http://example.com?old=1?new=2`)。

2. **空值不一致性**  
   - 解析时接受空值(`key=`),但构建时忽略空值,可能导致数据丢失。

3. **分隔符支持**  
   - 仅支持`&`作为参数分隔符,不处理`;`等其他分隔符。

4. **重复键处理**  
   - `Dictionary`会覆盖重复键,`NameValueCollection`会合并多个值为逗号分隔的字符串。

---

### **示例用法**
```csharp
// 解析URL参数
var url = "https://example.com/path?name=Alice&age=30";
var dict = UrlHelper.GetQueryDictionary(url, "baseUrl", ignoreCase: true);
// dict包含:["baseUrl": "https://example.com/path", "name": "Alice", "age": "30"]

// 构建URL
var parameters = new NameValueCollection { { "q", "test" }, { "page", "2" } };
string fullUrl = UrlHelper.GetUrlString("https://example.com", parameters);
// 输出:https://example.com?q=test&page=2
```

---

### **总结**
该代码提供了一套便捷的URL参数解析与构建工具,适用于需要操作查询字符串的场景,需根据需求选择`Dictionary`或`NameValueCollection`以应对重复键问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值