【问题标题】:Regex to parse querystring values to named groups正则表达式将查询字符串值解析为命名组
【发布时间】:2025-12-09 11:50:01
【问题描述】:

我有一个包含以下内容的 HTML:

... some text ...
<a href="file.aspx?userId=123&section=2">link</a> ... some text ...
... some text ...
<a href="file.aspx?section=5&user=678">link</a> ... some text ...
... some text ...

我想解析它并与命名组匹配:

匹配 1

组[“用户”]=123

组[“部分”]=2

匹配 2

组[“用户”]=678

组[“部分”]=5

如果参数总是按顺序排列,首先是用户,然后是部分,我可以这样做,但如果顺序不同,我不知道该怎么做。

谢谢!

【问题讨论】:

  • 'user' 和 'userId' 一样吗?

标签: regex query-string groupname


【解决方案1】:

在我的例子中,我必须解析一个 Url,因为实用程序 HttpUtility.ParseQueryString 在 WP7 中不可用。所以,我创建了一个这样的扩展方法:

public static class UriExtensions
{
    private static readonly Regex queryStringRegex;
    static UriExtensions()
    {
        queryStringRegex = new Regex(@"[\?&](?<name>[^&=]+)=(?<value>[^&=]+)");
    }

    public static IEnumerable<KeyValuePair<string, string>> ParseQueryString(this Uri uri)
    {
        if (uri == null)
            throw new ArgumentException("uri");

        var matches = queryStringRegex.Matches(uri.OriginalString);
        for (int i = 0; i < matches.Count; i++)
        {
            var match = matches[i];
            yield return new KeyValuePair<string, string>(match.Groups["name"].Value, match.Groups["value"].Value);
        }
    }
}

那么就是使用它的问题,例如

        var uri = new Uri(HttpUtility.UrlDecode(@"file.aspx?userId=123&section=2"),UriKind.RelativeOrAbsolute);
        var parameters = uri.ParseQueryString().ToDictionary( kvp => kvp.Key, kvp => kvp.Value);
        var userId = parameters["userId"];
        var section = parameters["section"];

注意:我直接返回 IEnumerable 而不是字典,只是因为我假设可能存在重复的参数名称。如果有重复的名字,那么字典会抛出异常。

【讨论】:

  • 用于查询字符串解析的良好正则表达式:[\?&amp;](?&lt;name&gt;[^&amp;=]+)=(?&lt;value&gt;[^&amp;=]+) 或稍作修改,仅用于查询字符串:[^&amp;](?&lt;name&gt;[^=]+)=(?&lt;value&gt;[^&amp;=]*)
【解决方案2】:

为什么要使用正则表达式来拆分它?

您可以先提取查询字符串。在 & 上拆分结果,然后通过从 = 上拆分结果来创建地图

【讨论】:

  • query.Split('&').ToDictionary((s) => s.Substring(0, s.IndexOf('=')), (s) => s.Substring(s .IndexOf('=') + 1));
【解决方案3】:

您没有指定您正在使用哪种语言,但这应该可以在 C# 中解决问题:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace RegexTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string subjectString = @"... some text ...
                <a href=""file.aspx?userId=123&section=2"">link</a> ... some text ...
... some text ...
<a href=""file.aspx?section=5&user=678"">link</a> ... some text ...
... some text ...";
            Regex regexObj = 
               new Regex(@"<a href=""file.aspx\?(?:(?:userId=(?<user>.+?)&section=(?<section>.+?)"")|(?:section=(?<section>.+?)&user=(?<user>.+?)""))");
            Match matchResults = regexObj.Match(subjectString);
            while (matchResults.Success)
            {
                string user = matchResults.Groups["user"].Value;
                string section = matchResults.Groups["section"].Value;
                Console.WriteLine(string.Format("User = {0}, Section = {1}", user, section));
                matchResults = matchResults.NextMatch();
            }
            Console.ReadKey();
        }
    }
}

【讨论】:

    【解决方案4】:

    使用正则表达式首先找到键值对然后进行拆分...似乎不对。

    我对完整的正则表达式解决方案感兴趣。

    有人吗?

    【讨论】:

      【解决方案5】:

      看看这个

      \<a\s+href\s*=\s*["'](?<baseUri>.+?)\?(?:(?<key>.+?)=(?<value>.+?)[&"'])*\s*\>
      

      您可以通过 Groups["key"].Captures[i] & Groups["value"].Captures[i] 之类的方式获得对

      【讨论】:

        【解决方案6】:

        也许是这样的(我对正则表达式很生疏,而且一开始并不擅长它们。未经测试):

        /href="[^?]*([?&](userId=(?<user>\d+))|section=(?<section>\d+))*"/
        

        (顺便说一句,XHTML 格式不正确;属性中的 & 应该是 &。)

        【讨论】:

          【解决方案7】:

          另一种方法是将捕获组放在前瞻中:

          Regex r = new Regex(@"<a href=""file\.aspx\?" +
                              @"(?=[^""<>]*?user=(?<user>\w+))" +
                              @"(?=[^""<>]*?section=(?<section>\w+))";
          

          如果只有两个参数,那么没有理由比 Mike 和 strager 建议的基于交替的方法更喜欢这种方法。但如果您需要匹配 三个 参数,其他正则表达式将增长到其当前长度的几倍,而这个正则表达式只需要另一个前瞻,就像现有的两个一样。

          顺便说一句,与您对 Claus 的回答相反,您使用哪种语言非常重要。从一种语言到另一种语言,功能、语法和 API 存在巨大差异。

          【讨论】:

            【解决方案8】:

            您没有说您使用的是哪种正则表达式。由于您的示例 URL 链接到一个 .aspx 文件,我将假设 .NET。在 .NET 中,一个正则表达式可以有多个具有相同名称的命名捕获组,并且 .NET 会将它们视为一个组。因此您可以使用正则表达式

            userID=(?<user>\d+)&section=(?<section>\d+)|section=(?<section>\d+)&userID=(?<user>\d+)
            

            这个带有交替的简单正则表达式将比任何环视技巧更有效。如果您的要求包括仅在链接中匹配参数时,您可以轻松扩展它。

            【讨论】:

              【解决方案9】:

              一个克服排序问题的简单python实现

              In [2]: x = re.compile('(?:(userId|section)=(\d+))+')
              
              In [3]: t = 'href="file.aspx?section=2&userId=123"'
              
              In [4]: x.findall(t)
              Out[4]: [('section', '2'), ('userId', '123')]
              
              In [5]: t = 'href="file.aspx?userId=123&section=2"'
              
              In [6]: x.findall(t)
              Out[6]: [('userId', '123'), ('section', '2')]
              

              【讨论】: