RegEx捕获重复字段?

时间:2013-07-12 16:58:57

标签: c# regex

我有一个缓冲区,我正试图用正则表达式解析。

以下是缓冲区的示例:

DATA#ALPHAONE;BETATWO.CHARLIETHREE!

格式为:缓冲区始终以“DATA#”开头,​​作为文字标题。 之后,它将有一个或多个文本字段,以分号,句号或感叹号分隔。

到目前为止,

我的正则表达式模式(在C#中)是:

string singleFieldPattern = "(?'Field'.*?)(?'Separator'[;.!])";
string fullBufferPattern = "(?'Header'DATA#)(" + singleFieldPattern + ")+";

当我尝试转储匹配的数据时出现问题:

Regex response = new Regex(fullBufferPattern);
string example = "DATA#ALPHAONE;BETATWO.CHARLIETHREE!";

Debug.WriteLine("RegEx Matches?: {0}", response.IsMatch(example));  
foreach (Match m in response.Matches(example))
{
    foreach(string s in new string[]{"Header", "Field", "Separator"}) 
    {
        Debug.WriteLine("{0} : {1}", s, m.Groups[s]);
    }
}

唯一的输出是:

RegEx Matches?: True
Header : DATA#
Field : CHARLIETHREE
Separator : !

我打算输出为:

RegEx Matches?: True
Header : DATA#
Field : ALPHAONE
Separator : ;
Field : BETATWO
Separator : .
Field : CHARLIETHREE
Separator : !

我的表达式没有按照我的意图获得早期字段ALPHAONEBETATWO(以及;.的分隔符)。它只捕获了最后一个字段(CHARLIETHREE)。

如何获得与singleFieldPattern匹配的所有部分?

<小时/> 为了问题的目的,我在上面简化了我的数据格式,但由于有些人想要真实数据,所以这里更接近实际数据:

(注意: [] 中的值是不可打印的单字节,空格仅为清晰起见。)

示例:

[SYN] % SYSNAMScanner[ACK]; BAUDRATE57600[ACK]; CTRLMODEXON[ACK];

翻译
   系统名称(SYSNAM)是“扫描仪”
   波特率为57,600
   流量控制是XON

4 个答案:

答案 0 :(得分:3)

如果您不介意LINQ,可以这样做:

string data = "DATA#ALPHAONE;BETATWO.CHARLIETHREE!";
var fullBufferPattern = @"(?<header>DATA#)(?<fields>.+)[;.!]";
var fieldPattern = @"(?<field>[^;.!]+)[;.!]?";

var fields = Regex.Matches(data, fullBufferPattern)
                    .OfType<Match>()
                    .SelectMany(
                        m =>
                        Regex.Matches(m.Groups["fields"].Value, fieldPattern)
                             .OfType<Match>())
                    .Select(m => m.Groups["field"].Value).ToArray();

变量fields将具有:

ALPHAONE    
BETATWO
CHARLIETHREE

修改:要重现Debug输出,请使用:

string data = "DATA#ALPHAONE;BETATWO.CHARLIETHREE!";
var fullBufferPattern = @"(?<header>DATA#)(?<fields>([^;.!]+[;.!])+)";
var fieldPattern = @"(?<field>[^;.!]+)(?<separator>[;.!])";

var groups = Regex.Matches(data, fullBufferPattern)
                  .OfType<Match>()
                  .Select(
                      m =>
                      new
                      {
                          Header = m.Groups["header"],
                          Fields = Regex.Matches(m.Groups["fields"].Value, fieldPattern)
                                        .OfType<Match>()
                                        .Select(f => new
                                            {
                                                Field = f.Groups["field"],
                                                Separator = f.Groups["separator"]
                                            })
                      });

foreach (var element in groups)
{
    Debug.WriteLine("Header : {0}", element.Header);
    foreach (var field in element.Fields)
    {
        Debug.WriteLine("Field : {0}", field.Field);
        Debug.WriteLine("Separator : {0}", field.Separator);
    }
}

输出是:

Header : DATA#
Field : ALPHAONE
Separator : ;
Field : BETATWO
Separator : .
Field : CHARLIETHREE
Separator : !

答案 1 :(得分:3)

这一点LINQ会将你的正则表达式中的字段和分隔符组合在一起:

var ms = response.Matches(example);
foreach (Match m in ms)
{
    string header = m.Groups["Header"].Value;
    Debug.WriteLine("Header : " + header);
    var pairs = m.Groups["Field"].Captures.Cast<Capture>().Zip(
                    m.Groups["Separator"].Captures.Cast<Capture>(),
                    (f, s) => new { Field = f.Value, Separator = s.Value });
    foreach (var pair in pairs)
    {
        Debug.WriteLine(pair.ToString());
    }
}

输出:

Header : DATA#
{ Field = ALPHAONE, Separator = ; }
{ Field = BETATWO, Separator = . }
{ Field = CHARLIETHREE, Separator = ! }

答案 2 :(得分:1)

我在VB中尝试这个(因为这是我打开的),但考虑为群组迭代Capture:

  For Each m As Capture In response.Match(example).Groups("Field").Captures
     Debug.WriteLine(m.Value)
  Next

给了我

ALPHAONE
BETATWO
CHARLIETHREE

答案 3 :(得分:1)

所以你想获得标题模式或单个字段模式之后的所有值吗?

"(?'Header'^DATA#)|(?'Field'.*?)(?'Separator'[;.!])"

应该做得很好,不知道你还有什么你正在解析的。