我有一个由管道字符分隔的字符串。这是一个可重复的序列:
AutoDeltaSettings
但是,如果您看到items标记,则还会通过其间的管道字符分隔itemnumbers。好吧,它的'不是一个智能格式,但我必须解决它,我想在C#中使用正则表达式。所以假设上面的格式让我们有一个真实的例子:
<machinenr>|<controldone>|<nrofitems|<items>
理论上注意,管道之间不需要是一个值,内容也不受长度的限制。项目ID可以是111或877333,但即使是混合的字母数字ID XB111。所以我们这里有两台没有物品的机器:
446408|0|2|111|6847|446408||0||
这里有一些没有或有些物品的机器。注意,管道字符也用于分隔项目,因此管道内有管道:
446408|0|0||447400||0||
这台机器有三个项目: 446408 | 0 | 3 | 99884 | 111 | 73732 |
项目ID:
446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||
正则表达式应该是什么样的?我已尝试使用以下命名的群组(更易于阅读),但它不起作用:
99884|111|73732
以下是对@Atterson @sln和@的澄清。注意,项目数量可以是0-n,金额没有限制。让我们举个例子,一个带机器的长字符串及其项目:446408 | 0 | 1 | 111 | 446408 | 0 | 3 | 99884 | 111 | 73732 | 446408 | 0 | 0 ||我期望正则表达式做的是将这个字符串分成三个匹配/部分及其值,第一个匹配是:446408 | 0 | 1 | 111 |第二场比赛:446408 | 0 | 3 | 99884 | 111 | 73732 |和第三场比赛:446408 | 0 | 0 ||好的,为了举例说明每个部分应分成的值,让我们使用第二个匹配/部分。它是一台nr 446408的机器,它没有被控制0,它有3个项目,项目ID:99884 | 111 | 73732。在这些项目之后,出现了一个新序列:
^(?P<machinenr>.*?)\|
(?P<controldone>.*?)\|
(?P<nrofitems>.*?)\|
(?P<items>.*?)\|
可以跟随。 @Sanxofon请在这里检查你的正则表达式:[link] https://regex101.com/r/kC3gH0/87并且你很遗憾地看到它不匹配。
答案 0 :(得分:1)
这不能用正则表达式解决,没有办法告诉正则表达式如下:“匹配.*?\|
与特定捕获组相同的次数......恰好包含一个数字。 “这是使用普通旧C#的直接解决方案。
string items = "446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0|";
var fields = items.Split('|');
for (int i = 0; i < fields.Length;) {
Console.WriteLine("machinenr:" + fields[i++]);
Console.WriteLine("controldone:" + fields[i++]);
int numSubItems = Int32.Parse(fields[i++]);
Console.WriteLine("num subitems:" + numSubItems);
if (numSubItems == 0) {
i++;
continue;
}
for (int subItemIndex = 0; subItemIndex < numSubItems; subItemIndex++) {
Console.WriteLine("\tItem:" + (subItemIndex + 1) + ": " + fields[i++]);
}
}
仅供参考,我修剪了尾随的“|”原来的字符串有,所以
string items = "446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0|";
而不是
string items = "446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||";
答案 1 :(得分:0)
C#中的命名捕获组为(?<nam>...)
而非(?P<name>...)
。此外,你表达了重复匹配的愿望(所以我将你的正则表达式包裹在重复的(?<grp>..)
中。
您需要弄清楚如何区分项目与计算机。例如,如果您可以说所有机器编号都是6位数,而项目是0-5位数,您可以执行类似的操作......您仍然需要拆分items
集合。
^(?<grp>(?<machinenr>[^\|]{6})\|
(?<controldone>[^\|]*)\|
(?<nrofitems>[^\|]*)\|
(?<items>(?:[^\|]{0,5}\|){1,}))*$
class Program
{
static void Main(string[] args)
{
string strRegex =
@"^(?<grp>(?<machinenr>[^\|]{6})\|
(?<controldone>[^\|]*)\|
(?<nrofitems>[^\|]*)\|
(?<items>(?:[^\|]{0,5}\|){1,}))*$";
Regex myRegex = new Regex(strRegex, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
string strTargetString = @"446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||";
MatchCollection matches = myRegex.Matches(strTargetString);
foreach (Match m in matches)
{
for (int idx = 0; idx < m.Groups["grp"].Captures.Count; idx++)
{
Console.WriteLine("Group:");
Console.WriteLine($"\tmachinenr={m.Group["machinenr"].Captures[idx]}");
Console.WriteLine($"\tcontroldone={m.Groups["controldone"].Captures[idx]}");
Console.WriteLine($"\tnrofitems={m.Groups["nrofitems"].Captures[idx]}");
Console.WriteLine($"\titems={m.Groups["items"].Captures[idx]}");
}
}
}
}
分割字符串并解析后续数组似乎更容易。但是,如果您担心处理大字符串或者不想使用String.Split()
,则可以使用IEnumerable<T>
方法。这是一种方法......
class Program
{
public class Entry
{
public string MachineNr { get; set; }
public string ControlDone { get; set; }
public int Count { get; set; }
public List<string> Items { get; set; }
private static IEnumerable<string> fields(string list)
{
int idx = 0;
do
{
int ndx = list.IndexOf('|', idx);
if (ndx == 1)
yield return list.Substring(idx);
else
yield return list.Substring(idx, ndx - idx);
idx = ++ndx;
}
while (idx > 0 && idx < list.Length-1) ;
}
public static IEnumerable<Entry> parseList(string list)
{
int idx =0;
var fields = Entry.fields(list).GetEnumerator();
while (fields.MoveNext())
{
var e = new Entry();
e.MachineNr = fields.Current;
if (fields.MoveNext())
{
e.ControlDone = fields.Current;
if (fields.MoveNext())
{
int val = 0;
e.Count = int.TryParse(fields.Current, out val) ? val : 0;
e.Items = new List<string>();
for (int x=e.Count;x>0;x--)
{
if (fields.MoveNext())
e.Items.Add(fields.Current);
}
}
}
yield return e;
}
}
}
static void Main(string[] args)
{
string strTargetString = @"446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||";
foreach (var entry in Entry.parseList(strTargetString))
{
Console.WriteLine(
$@"Group:
Machine: {entry.MachineNr}
ControlDone: {entry.ControlDone}
Count: {entry.Count}
Items: {string.Join(", ",entry.Items)}");
}
}
}