在C#中使用正则表达式来分割字符串

4
我需要从另一个系统中拆分一个字符串,该字符串表示一个序列化对象。该对象本身可能有另一个相同类型的嵌套对象作为属性。我需要一种将字符串序列化为字符串数组的方法。例如: "{1,Dave,2}" 应该创建一个具有3个元素的字符串数组 "1", "Dave", "2""{1,{Cat,Yellow},2}" 应变成一个具有3个元素的数组 "1", "{Cat,Yellow}", "2""{1,{Cat,{Blue,1}},2}" 应该变成一个具有3个元素的数组 "1", "{Cat,{Blue,1}}", "2"
基本上,嵌套可以是N层深度,因此潜在地,我可以有像“{{Cat,{Blue,1}},{Dog,White}}”这样的东西,我的结果数组应该有2个元素:“{Cat,{Blue,1}}”和“{Dog,White}”。
我的想法是编写自定义解析器手动解析字符串。但这似乎是正则表达式旨在解决的问题,然而,我不太擅长使用正则表达式,因此希望得到来自RegEx专家的指导。谢谢。

这是使用正则表达式平衡组的完美任务。 - Konrad Kokosa
必须使用正则表达式吗? - Shai
1
你需要解析嵌套元素吗? - insomnium_
@insomnium_ 不,它需要看起来像“1”,“{Cat,Yellow}”,“2”。然后我将运行相同的逻辑将“{Cat,Yellow}”反序列化为表示嵌套对象的单独数组。 - Kiwik
4
一般而言,正则表达式并不适合用于解析嵌套结构。虽然在.NET中可以使用某些扩展的正则表达式功能实现,但通常更倾向于使用解析算法。你可以在这里找到一个简单的解析算法,可以根据你的问题进行调整:http://stackoverflow.com/a/5477921/87698 - Heinzi
显示剩余3条评论
2个回答

4
好的,这段话可以翻译为:“你可以使用这种利用平衡组的分割方式:”。
,(?=[^{}]*(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))$)

它将匹配没有{}前面的逗号,或者在{}内部的组。
在代码中:
string msg= "{1,{Cat,{Blue,1}},2}";
msg = msg.Substring(1, msg.Length - 2);
string[] charSetOccurences = Regex.Split(msg, @",(?=[^{}]*(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))$)");
foreach (string s in charSetOccurences)
{
    Console.WriteLine(s);
}

输出:

1
{Cat,{Blue,1}}
2

ideone演示


简要说明:
(?=[^{}]*(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))$)

这是一段英文文本,大意为:

这是一个很大的前瞻...

[^{}]*将匹配除了{}之外的任何字符,出现次数不限。

(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))将匹配带有任何嵌套层级的{}组。

首先它会捕获一个开放的{并将其命名为O(我选择的含义是“opening”):

(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))
           ^

然后是除花括号以外的任何字符:
(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))
             ^^^^^^

并重复该组以适应嵌套:
(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))
                    ^

这部分平衡了开括号:
(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))
                        ^^^^^^^^

使用其他非 {} 的符号并重复以适应嵌套:
(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))
                                ^^^^^^^ ^

所有这些,至少0次:
(?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)*(?(O)(?!))
                                          ^

最后一个条件负向先行断言只是一个闭包,并确保没有不平衡的大括号。

非常接近,但无法解析像“{1,{Cat,{Blue,1}},2,{Dog,5}}”这样的字符串。仍然有帮助。谢谢。 - Kiwik
@Kiwik哦,那是因为Trim(删除末尾的所有})而不是正则表达式的原因。我把它改成了Substring - Jerry
是的,这就解决了。谢谢。标记为已接受。非常感谢你提供如此详细的解释。 - Kiwik

3

虽然不是 Split,但如果您使用以下表达式与 Match 结合使用,您将得到一个失败的匹配或者一个带有个体值的匹配结果,存储在 m.Groups[1].Captures 中:

^\{(?:((?:[^{}]|\{(?<Depth>)|\}(?<-Depth>))*?)(?:,(?(Depth)(?!))|\}$))*$

m.Groups[1].Captures 提供了我所需的内容。非常感谢。然而 @Jerrys 的答案是更完整的解决方案。因此将其标记为已接受。 - Kiwik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接