regex 正则表达式在逗号上分割,但不在任何括号内分割,并考虑递归

lxkprmvk  于 2023-04-13  发布在  其他
关注(0)|答案(2)|浏览(396)

我有一个示例字符串:

string myString = "value,value,(value,(value, value, value, (value), value),value)";

目标是遍历它并将其反序列化为类对象的层次结构。
为什么大多数其他例子在这里问类似的问题都不起作用的原因是由于递归,向前(或向后)寻找偶数个括号都不起作用。
我曾考虑将其存储为JSON,但值的对象类型会在没有通知的情况下发生变化,这在过去甚至被证明是令人困惑json.net的,特别是因为类型可能都是通过继承相关的。
因此,给定示例字符串,目标是在逗号“,”上进行拆分,但忽略括号中的所有内容,直到我的递归循环深入到该子集,然后使用相同的正则表达式来拆分其内容。
我还没有代码,因为我仍然在头脑 Storm 这个方法。
还要注意的是,子列表不一定是父列表中的最后一个元素,在我的例子中,最后有几个延迟的value
不要标记为重复没有充分阅读的问题,并理解为什么它是不一样的问题,如this

ohtdti5x

ohtdti5x1#

虽然C#正则表达式有一个功能,可以让你递归地匹配带括号的组(参见this Q&A for an example),但是定义这样的正则表达式对于正的情况(即“匹配一个单词或整个带括号的组”)要容易得多,而对于拆分所需的负的情况(即“匹配逗号 * 除非 * 它在一个带括号的组内”)。
此外,当您希望递归地应用相同的正则表达式时,构建简单的Recursive Descent Parser有一个优势。
解析器的核心是split逻辑,它在搜索逗号时对括号进行计数,并在括号级别为零时进行拆分:

var parts = new List<string>();
var parenLevel = 0;
var lastPos = 0;
for (var i = 0 ; i != s.Length ; i++) {
    switch (s[i]) {
        case '(':
            parenLevel++;
            break;
        case ')':
            parenLevel--;
            if (parenLevel < 0) {
                throw new ArgumentException();
            }
            break;
        case ',':
            if (parenLevel == 0) {
                parts.Add(s.Substring(lastPos, i-lastPos));
                lastPos = i + 1;
            }
            break;
    }
}
if (lastPos != s.Length) {
    parts.Add(s.Substring(lastPos, s.Length - lastPos));
}

Demo.

xqk2d5yq

xqk2d5yq2#

试试这个模式:

,(?<!\((?>(?:[^()]|(?<p>\))|(?<-p>\())*))

请注意,这只适用于C#/. NET。
Java/JavaScript/Python/Perl等的正则表达式引擎不支持balancing groups特性,该特性允许此模式处理嵌套括号。
在这里测试一下:
http://regexstorm.net/tester?p=%2c%28%3f%3c!%5c%28%28%3f%3e%28%3f%3a%5b%5e%28%29%5d%7c%28%3f%3cp%3e%5c%29%29%7c%28%3f%3c-p%3e%5c%28%29%29*%29%29&i=value%2cvalue%2c%28value%2c%28value%2c+value%2c+value%2c+%28value%29%2c+value%29%2cvalue%29
下面是对该模式的解释(由.NET 7的正则表达式源代码生成器生成):

/// <remarks>
/// Pattern explanation:<br/>
/// <code>
/// ○ Match ','.<br/>
/// ○ Zero-width negative lookbehind.<br/>
///     ○ Loop greedily and atomically any number of times right-to-left.<br/>
///         ○ Match with 3 alternative expressions.<br/>
///             ○ Match a character in the set [^()] right-to-left.<br/>
///             ○ "p" capture group.<br/>
///                 ○ Match ')' right-to-left.<br/>
///             ○ Non-capturing balancing group. Uncaptures the "p" capture group.<br/>
///                 ○ Match '(' right-to-left.<br/>
///     ○ Match '(' right-to-left.<br/>
/// </code>
/// </remarks>

相关问题