如何在 C# 中拆分 OData 多级扩展查询字符串?

How to Split OData multi-level expand query string in C#?

我有一个URL:Expand=User($select=Firstname,Lastname),Organisation,Contract($Expand=MyOrganisation($select=Name,Status),Organisation),List

我需要按以下格式拆分此字符串:

如何在C#中实现这个功能?

您更有可能必须使用 ODataLib with in-built URI Parser

Uri requestUri = new Uri("Products?$select=ID&$expand=ProductDetail" +
                         "&$filter=Categories/any(d:d/ID%20gt%201)&$orderby=ID%20desc" +
                         "&$top=1&$count=true&$search=tom",
                         UriKind.Relative);
ODataUriParser parser = new ODataUriParser(model, serviceRoot, requestUri);
SelectExpandClause expand = parser.ParseSelectAndExpand(); // parse $select, $expand
FilterClause filter = parser.ParseFilter();                // parse $filter
OrderByClause orderby = parser.ParseOrderBy();             // parse $orderby
SearchClause search = parser.ParseSearch();                // parse $search
long? top = parser.ParseTop();                             // parse $top
long? skip = parser.ParseSkip();                           // parse $skip
bool? count = parser.ParseCount();                         // parse $count

添加 RegExp 选项(Amal 在下面提供的固定版本)

    string url = "User($select=Firstname,Lastname),Organisation,Contract($Expand=MyOrganisation($select=Name,Status),Organisation),List";

    Regex rgx = new Regex(@"(.+?)(?:(\(.*?\)),|,)");

    foreach (var match in rgx.Matches($"{url},"))
    {
        Console.WriteLine(match.ToString()[..^1]);
    }

您不仅需要拆分字符串,还需要在拆分时跟踪括号。这对于普通的旧正则表达式是不可能的。参见 this post。 但是,可以使用一些高级 RegEx 来实现拆分; .NET 幸运地支持 balancing groups using which you can keep track of the parentheses. This answer 对提出解决方案很有帮助。为了可读性,我将正则表达式拆分为多行并使用 RegexOptions.IgnorePatternWhitespace:

string url = "User($select=Firstname,Lastname),Organisation,Contract($Expand=MyOrganisation($select=Name,Status),Organisation),List";
Regex rgx = new Regex(
               @"(.+?)
                (
                    (
                        \(
                            (?:
                                [^()]
                                |
                                (?'open'\()
                                |
                                (?'close-open'\))
                            )+
                            (?(open)(?!))
                        \)
                    )
                    ,
                    |
                    ,
                    |
                    \b$
                )", 
               RegexOptions.IgnorePatternWhitespace);

foreach(var match in rgx.Matches(url))
{
    Console.WriteLine($"{match.Groups[1]} {match.Groups[3]}"); 
}

字段将作为 match.Groups[1] 提供,参数(如果有的话)将作为 match.Groups[3] 提供(如果没有参数,这将是一个空字符串)。您可以访问 match.Groups[0] 以获取整个组。

正则表达式分解

Regex Description
(.+?) Non-greedily match one or more characters
\( and \) Match an actual ( and )
[^()] Match any character that is not a ( or )
(?'open'\() Create a named group with the name "open" and match a ( character
(?'close-open\)) Create a group "close" and assign the interval between "open" and "close" to "close" and delete group "open"
(?(open)(?!)) Assert if the "open" group is not deleted
(?:[^()]|(?'open'\()|(?'close-open'\)))+ Create a non-capturing group and match one or more characters that match one of the expressions between |