C# 复杂字符串拆分
我有一个字符串,如下所示:C# 复杂字符串拆分,c#,regex,string,parsing,split,C#,Regex,String,Parsing,Split,我有一个字符串,如下所示: [Testing.User]|Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))|Description:([System.String]|This is some description) 您可以将其视为以下树: - [Testing.User] - Info - [Testing.Info] - Name
[Testing.User]|Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))|Description:([System.String]|This is some description)
您可以将其视为以下树:
- [Testing.User]
- Info
- [Testing.Info]
- Name
- [System.String]
- Matt
- Age
- [System.Int32]
- 21
- Description
- [System.String]
- This is some description
如您所见,它是类测试的字符串序列化/表示。User
我希望能够进行拆分,并在生成的数组中获取以下元素:
[0] = [Testing.User]
[1] = Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))
[2] = Description:([System.String]|This is some description)
我不能按|
拆分,因为这样会导致:
[0] = [Testing.User]
[1] = Info:([Testing.Info]
[2] = Name:([System.String]
[3] = Matt)
[4] = Age:([System.Int32]
[5] = 21))
[6] = Description:([System.String]
[7] = This is some description)
我怎样才能得到预期的结果
我对正则表达式不是很在行,但我知道这是一个非常可能的解决方案。这不是一个好的/健壮的解决方案,但如果您知道三个顶级项已修复,则可以将它们硬编码到正则表达式中
(\[Testing\.User\])\|(Info:.*)\|(Description:.*)
正如您所期望的那样,此正则表达式将创建一个包含三个组的匹配项。您可以在此处进行测试:
编辑:下面是一个完整的C#示例
使用系统;
使用System.Text.RegularExpressions;
命名空间控制台应用程序3
{
内部课程计划
{
私有静态void Main(字符串[]args)
{
const string input=@“[Testing.User]| Info:([Testing.Info]| Name:([System.string]| Matt)| Age:([System.Int32]| 21))| Description:([System.string]|这是一些描述)”;
常量字符串模式=@“(\[Testing\.User\])\\\\(信息:.*)\\\(说明:.*)”;
var match=Regex.match(输入,模式);
如果(匹配成功)
{
对于(int i=1;i
假设您的组可以标记为
"(\\[\\w+\\.\\w+\\])\\|(\\w+:.+)\\|(\\w+:.+)";
此捕获组将获得“[Testing.User]”,但不限于“[Testing.User]”(\\[\\w+\.\\w+\\])
此捕获组将在第一个管道之后获取数据,并在最后一个管道之前停止。在本例中,“Info:([Testing.Info]| Name:([System.String]| Matt)| Age:([System.Int32]| 21)),但不限于以“Info:”开头的信息:\\\\\;(\\w+:.+)
与前面的捕获组相同,但捕获最后一个管道之后的内容,在本例中为“描述:([System.String]|这是一些描述)”,但不限于以描述开头:\\\\\\\(\\w+:.+)
| Anything:SomeData
),则说明:
将是组2的一部分,组3现在将是“Anything:SomeData
”
代码如下所示:
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
String text = "[Testing.User]|Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))|Description:([System.String]|This is some description)";
String pattern = "(\\[\\w+\\.\\w+\\])\\|(\\w+:.+)\\|(\\w+:.+)";
Match match = Regex.Match(text, pattern);
if (match.Success)
{
Console.WriteLine(match.Groups[1]);
Console.WriteLine(match.Groups[2]);
Console.WriteLine(match.Groups[3]);
}
}
}
结果:
[Testing.User]
Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))
Description:([System.String]|This is some description)
请参阅此处的工作示例
如果我在这里添加另一个遵循模式格式的字段,请参见工作示例…要做到这一点,您需要使用.net正则表达式引擎独有的正则表达式功能。这是一个计数器系统,当发现一个左括号时,计数器递增,当发现一个右括号时,计数器递减,然后您只需测试计数器为null以了解括号是否平衡。 这是确保您在括号内或括号外的唯一方法:
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string input = @"[Testing.User]|Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))|Description:([System.String]|This is some description)";
string pattern = @"(?:[^|()]+|\((?>[^()]+|(?<Open>[(])|(?<-Open>[)]))*(?(Open)(?!))\))+";
foreach (Match m in Regex.Matches(input, pattern))
Console.WriteLine(m.Value);
}
}
使用系统;
使用System.Text.RegularExpressions;
公开课范例
{
公共静态void Main()
{
字符串输入=@“[Testing.User]| Info:([Testing.Info]| Name:([System.string]| Matt)|年龄:([System.Int32]| 21))|说明:([System.string]|这是一些说明)”;
字符串模式=@“(?:[^ |()]+|\(?>[^()]+|)(?[())(?[)))*(?(打开)(?!)\)+”;
foreach(在正则表达式中匹配m.Matches(输入,模式))
控制台写入线(m值);
}
}
图案详情:
(?:
[^|()]+ # all that is not a parenthesis or a pipe
| # OR
# content between parenthesis (eventually nested)
\( # opening parenthesis
# here is the way to obtain balanced parens
(?> # content between parens
[^()]+ # all that is not parenthesis
| # OR
(?<Open>[(]) # an opening parenthesis (increment the counter)
|
(?<-Open>[)]) # a closing parenthesis (decrement the counter)
)* # repeat as needed
(?(Open)(?!)) # make the pattern fail if the counter is not zero
\)
)+
(?)
[^ |()]+#所有这些都不是括号或管道
|#或
#括号之间的内容(最终嵌套)
\(#左括号)
#下面是获得平衡参数的方法
(?>#双方之间的内容
[^()]+#所有这些都不是括号
|#或
(?[(])#一个圆括号(递增计数器)
|
(?[)]#右括号(减少计数器)
)*#根据需要重复
(?(打开)(?!)#如果计数器不为零,则使模式失败
\)
)+
(?(open)(?!)
是一个条件语句
(?!)
是一个始终为假的子模式(一个空的负前瞻),意思是:后面不跟零
此模式匹配所有非管道和括号之间的字符串。使用regex lookahead
您可以使用这样的正则表达式:
(\[.*?])|(\w+:.*?)\|(?=Description:)|(Description:.*)
(\[.*?])\|(.*)\|(Description:.*)
这个正则表达式背后的思想是按组捕获您想要的内容1
、2
和3
通过此图,您可以很容易地看到:
匹配信息
MATCH 1
1. [0-14] `[Testing.User]`
MATCH 2
2. [15-88] `Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))`
MATCH 3
3. [89-143] `Description:([System.String]|This is some description)`
正则正则表达式
另一方面,如果您不喜欢上面的正则表达式,可以使用另一个这样的正则表达式:
(\[.*?])|(\w+:.*?)\|(?=Description:)|(Description:.*)
(\[.*?])\|(.*)\|(Description:.*)
甚至强制至少一个字符:
(\[.+?])\|(.+)\|(Description:.+)
正则表达式并不是解决此类问题的最佳方法,您可能需要编写一些代码来解析数据,我做了一个简单的示例,实现了您的这种简单情况。这里的基本思想是,只有当
不在括号内时,才需要拆分,因此我会跟踪括号计数。您需要做一些操作例如,在威胁案例中,括号是描述部分的一部分,但正如我所说,这只是一个起点:
static IEnumerable<String> splitSpecial(string input)
{
StringBuilder builder = new StringBuilder();
int openParenthesisCount = 0;
foreach (char c in input)
{
if (openParenthesisCount == 0 && c == '|')
{
yield return builder.ToString();
builder.Clear();
}
else
{
if (c == '(')
openParenthesisCount++;
if (c == ')')
openParenthesisCount--;
builder.Append(c);
}
}
yield return builder.ToString();
}
static void Main(string[] args)
{
string input = "[Testing.User]|Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))|Description:([System.String]|This is some description)";
foreach (String split in splitSpecial(input))
{
Console.WriteLine(split);
}
Console.ReadLine();
}
已经有足够多的拆分答案了,所以这里有另一种方法。如果您的输入表示一个树结构,为什么不将其解析为一个树呢? 以下代码是从VB.NET自动翻译的,但是
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Treeparse
{
class Program
{
static void Main(string[] args)
{
var input = "[Testing.User]|Info:([Testing.Info]|Name:([System.String]|Matt)|Age:([System.Int32]|21))|Description:([System.String]|This is some description)";
var t = StringTree.Parse(input);
Console.WriteLine(t.ToString());
Console.ReadKey();
}
}
public class StringTree
{
//Branching constants
const string BranchOff = "(";
const string BranchBack = ")";
const string NextTwig = "|";
//Content of this twig
public string Text;
//List of Sub-Twigs
public List<StringTree> Twigs;
[System.Diagnostics.DebuggerStepThrough()]
public StringTree()
{
Text = "";
Twigs = new List<StringTree>();
}
private static void ParseRecursive(StringTree Tree, string InputStr, ref int Position)
{
do {
StringTree NewTwig = new StringTree();
do {
NewTwig.Text = NewTwig.Text + InputStr[Position];
Position += 1;
} while (!(Position == InputStr.Length || (new String[] { BranchBack, BranchOff, NextTwig }.ToList().Contains(InputStr[Position].ToString()))));
Tree.Twigs.Add(NewTwig);
if (Position < InputStr.Length && InputStr[Position].ToString() == BranchOff) { Position += 1; ParseRecursive(NewTwig, InputStr, ref Position); Position += 1; }
if (Position < InputStr.Length && InputStr[Position].ToString() == BranchBack)
break; // TODO: might not be correct. Was : Exit Do
Position += 1;
} while (!(Position >= InputStr.Length || InputStr[Position].ToString() == BranchBack));
}
/// <summary>
/// Call this to parse the input into a StringTree objects using recursion
/// </summary>
public static StringTree Parse(string Input)
{
StringTree t = new StringTree();
t.Text = "Root";
int Start = 0;
ParseRecursive(t, Input, ref Start);
return t;
}
private void ToStringRecursive(ref StringBuilder sb, StringTree tree, int Level)
{
for (int i = 1; i <= Level; i++)
{
sb.Append(" ");
}
sb.AppendLine(tree.Text);
int NextLevel = Level + 1;
foreach (StringTree NextTree in tree.Twigs)
{
ToStringRecursive(ref sb, NextTree, NextLevel);
}
}
public override string ToString()
{
var sb = new System.Text.StringBuilder();
ToStringRecursive(ref sb, this, 0);
return sb.ToString();
}
}
}