解析重复行的特定实例的分隔数据

时间:2013-04-02 17:29:09

标签: c# linq parsing

我有一个以下格式的字符串数组,其中每个字符串以一系列三个字符开头,表示它包含的数据类型。例如:

  

ABC | .....
  DEF | ...
  RHG | 1 ........
  RHG | 2 ........
  RHG | 3 ........
  XDF | ......

我想找到任何重复的行(本例中为RHG)并用特殊字符标记最后一行:

  

> RHG | 3 .........

最好的方法是什么?我当前的解决方案有一种方法来计算行标题并创建一个带有标题计数的字典。

protected Dictionary<string, int> CountHeaders(string[] lines)
{
    Dictionary<string, int> headerCounts = new Dictionary<string, int>();
    for (int i = 0; i < lines.Length; i++)
    {
        string s = lines[i].Substring(0, 3);

        int value;
        if (headerCounts.TryGetValue(s, out value))
            headerCounts[s]++;
        else
            headerCounts.Add(s, 1);
    }
    return headerCounts;
}

在主解析方法中,我选择重复的行。

var repeats = CountHeaders(lines).Where(x => x.Value > 1).Select(x => x.Key);
foreach (string s in repeats)
{
    // Get last instance of line in lines and mark it
}

据我所知。我想我可以用另一个LINQ查询做我想做的事,但我不太确定。此外,我不禁觉得有更优化的解决方案。

3 个答案:

答案 0 :(得分:4)

您可以使用LINQ来实现这一目标。

输入字符串:

var input = @"ABC|.....
DEF|...
RHG|1........
RHG|2........
RHG|3........
XDF|......";

LINQ查询:

var results = input.Split(new[] { Environment.NewLine })
                   .GroupBy(x => x.Substring(0, 3))
                   .Select(g => g.ToList())
                   .SelectMany(g => g.Count > 1 ? g.Take(g.Count - 1).Concat(new[] { string.Format(">{0}", g[g.Count - 1]) }) : g)
                   .ToArray();

我使用Select(g => g.ToList())投影在进一步的查询步骤中进行g.Count O(1)操作。

您可以使用Join方法String.Join将数组生成一个字符串:

var output = String.Join(Environment.NewLine, results);

答案 1 :(得分:1)

或者,您可以找到带有反向引用正则表达式的重复行。我使用您的示例数据编写了这个hacky正则表达式,它匹配以前面的'tag'开头的行,管道分隔值。

^(?<Tag>.+)[|].+[\n\r](\k<Tag>[|].+[\n\r])+

匹配范围从第一条RHG线的开头开始,并选择最后一条RHG线。

答案 2 :(得分:0)

这是一个包含在一个Linq语句中解析和计数的示例 - 如果您愿意,可以随意分解:

string[] data = new string[]
{
    "ABC|.....",
    "DEF|...",
    "RHG|1........",
    "RHG|2........",
    "RHG|3........",
    "XDF|......"
};

data.Select(d=> d.Split('|'))                     // split the strings
    .Select(d=> new { Key = d[0], Value = d[1] }) // select the key and value
    .GroupBy (d => d.Key)                         // group by the key
    .Where(g=>g.Count() > 1 )                     // find duplicates
    .Select(d => d.Skip(1))                       // select the repeating elements
    .SelectMany(g=>g)                             // flatten into a single list
    ;                      

这将为您提供重复的键/值对列表。所以对于样本数据,它将返回

Key Value 
RHG 2........ 
RHG 3........ 

我不确定你用“标记”这条线的意思,但是......