字符串分离C#

时间:2013-07-22 13:57:56

标签: c# winforms visual-studio-2010

我在下面的txt文件中读到了。我试图将这些数据分成几个不同的列。

Command sent from hmi(0).ctq[0] to calh(1).ctq[0] v:1,
Command sent from ptov(21) to bo(1).ctq[10] v:0,
Command answer from bo(1) to ptov(21) code:15 - complete,
Event ptof(1).sgn[7] v:0 s:0601,
Command sent from ptuf(1) to bo(1).ctq[5] v:0,

我能够以“事件”开头的行。我是这样做的。它很容易,因为它在每个重要部分之后都有空白字符。

List<string> description = list.Select(x => x.System_Description).ToList<string>();
        DataTable dt = new DataTable();
        dt.Columns.Add("values");

        foreach(string items in description)
        {
            if (items[0] == 'E')
            {
                string[] _columns = items.Split(" ".ToCharArray());
            }
            else
            {

            }
            DataRow row = dt.NewRow();
            dt.Rows.Add(items);

在从“命令”开始的这一行中,我想将它分成4列。第一个将是“命令”,第二个我想把所有东西放在“从”和“到”之间。第三个将是“to”之后的数据,最后一个将是“v:..”的值。你能以某种方式帮助我,或建议我该怎么做?

3 个答案:

答案 0 :(得分:4)

我建议使用正则表达式来解析这些行。这是一些有效的代码:

var text = @"Command sent from hmi(0).ctq[0] to calh(1).ctq[0] v:1,
Command sent from ptov(21) to bo(1).ctq[10] v:0,
Command answer from bo(1) to ptov(21) code:15 - complete,
Event ptof(1).sgn[7] v:0 s:0601,
Command sent from ptuf(1) to bo(1).ctq[5] v:0,";

var lines = text.Split(
  Environment.NewLine.ToCharArray(),
  StringSplitOptions.RemoveEmptyEntries
);
var regex = new Regex(@"^(?:(?<C0>Event) (?<C1>\S+) (?<C2>\S+) (?<C3>\S+)|(?<C0>Command) (?:answer|sent) from (?<C1>\S+) to (?<C2>\S+) (?<C3>.+)),$");
var result = lines
  .Select(line => regex.Match(line))
  .Select(
    match => new {
      C0 = match.Groups["C0"].Value,
      C1 = match.Groups["C1"].Value,
      C2 = match.Groups["C2"].Value,
      C3 = match.Groups["C3"].Value
    }
  );

结果是:

C0      | C1             | C2             | C3                 |
--------+----------------+----------------+--------------------+
Command | hmi(0).ctq[0]  | calh(1).ctq[0] | v:1                |
Command | ptov(21)       | bo(1).ctq[10]  | v:0                |
Command | bo(1)          | ptov(21)       | code:15 - complete |
Event   | ptof(1).sgn[7] | v:0            | s:0601             |
Command | ptuf(1)        | bo(1).ctq[5]   | v:0                |

您没有指定如何解析Command answer from行,因此我冒昧地自己做出一些决定。此外,我刚刚创建了一个LINQ查询,它将行解析为一系列匿名对象。请参阅下文,了解如何将结果填入DataTable(稍微嘈杂的代码)。

以下是正则表达式的一些亮点:

  1. (?<C0>Event)是与Event匹配的命名组。名称为C0(第0列),并且在执行匹配后,Match对象中可以访问该组的匹配值。

  2. (?:answer|sent)是一个与answersent匹配的非捕获组,但未捕获匹配的内容。正则表达式的大部分也由非捕获组组成,该组将匹配Command行或Event行。

  3. \S+匹配一个或多个非空白字符。

  4. 使用^启动正则表达式并以$结束正确表达式可确保整行匹配。

  5. 要将结果放在DataTable中,您可以删除匿名类型,而是使用此代码(替换var result = lines代码行):

    var matches = lines.Select(line => regex.Match(line));
    var dataTable = new DataTable();
    foreach (var columnName in new[] { "A", "B", "C", "D" })
      dataTable.Columns.Add(columnName);
    foreach (var match in matches)
      dataTable.Rows.Add(
        match.Groups.Cast<Group>().Skip(1).Select(group => group.Value).ToArray()
      );
    

    唯一棘手的部分是Skip(1),其中跳过了匹配中的第一个组。第一组是整场比赛。通过跳过我知道其余四个组是C0到C3,然后使用这些值来创建具有行的列值的数组。

    由于我不使用组名,因此实际上可以从正则表达式中删除它们。例如。 (?<C1>\S+)可以替换为(\S+)等。

    我刚刚选择了A,B,C和D作为列的随机名称。

答案 1 :(得分:1)

您可以尝试使用string.Split方法将字符串拆分为数组,使用空格('')作为拆分字符。然后,根据您的示例文件,您可以简单地使用数组中的正确索引来获取所需的列。

答案 2 :(得分:0)

var li = s.Split(',')
    .ToList()
    .Where(
        x=>
        x.Split(' ')[0].Trim() == "Command"
        )
    .Select(
        x => new 
        {
            Command = x.Split(' ')[0],
            Direction = x.Split(' ')[1],
            From = x.Split(' ')[3],
            To = x.Split(' ')[5] ,
            v = x.Split(' ')[6]
        })
    .ToList();