正则表达式将查询字符串值解析为命名组

时间:2008-11-23 21:31:32

标签: regex query-string groupname

我有一个包含以下内容的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,然后是Section,但如果订单不同,我不知道该怎么做。

谢谢!

9 个答案:

答案 0 :(得分:8)

在我的情况下,我必须解析一个Url,因为WP7中没有实用程序HttpUtility.ParseQueryString。所以,我创建了一个这样的扩展方法:

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而不是字典,因为我假设可能存在重复参数的名称。如果有重复的名称,那么字典将抛出异常。

答案 1 :(得分:5)

为什么要使用正则表达式将其拆分出来?

您可以先提取查询字符串。将结果拆分为&amp;然后通过从<= p>上分割结果来创建地图

答案 2 :(得分:1)

您没有指定您正在使用的语言,但这应该在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();
        }
    }
}

答案 3 :(得分:0)

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

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

任何?

答案 4 :(得分:0)

检查出来

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

您可以使用群组[“key”]获得对。捕获[i]&amp;基团[ “值”]。捕获[I]

答案 5 :(得分:0)

也许是这样的事情(我在正则表达式上生锈了,反正他们一开始并不擅长。未经测试):

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

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

答案 6 :(得分:0)

另一种方法是将捕获组放在预测中:

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

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

顺便说一句,与你对Claus的回应相反,你所使用的语言非常重要。从一种语言到下一种语言的功能,语法和API都有很大差异。

答案 7 :(得分:0)

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

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

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

答案 8 :(得分:0)

克服排序问题的简单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')]