2013-07-22 2 views
0

Я читаю txt-файл, как показано ниже. Я пытаюсь разделить эти данные на несколько разных столбцов.Разделение строк C#

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); 

В этой строке, начиная с «Command», я хотел бы разделить ее на 4 столбца. Сначала это будет просто «Command», во-вторых, я хочу поместить все между «от» и «до». Третьим будет информация после «до», а последняя будет иметь значение с «v: ..». Можете ли вы мне как-то помочь или предложить, как я могу это сделать?

+0

Звучит как задание для [RegularExpressions] (http://msdn.microsoft.com/library/system.text.regularexpressions.regex.aspx). – Corak

+1

'@"^(? Command) \ s. *? From \ s (? . *?) \ Sto \ s (? [^ \ s] +) \ s (? . *) $ "' что вы получите большую часть пути, но загляните в «Регулярное» и «Матч». –

+0

Можете ли вы немного объяснить это регулярное выражение, которое вы написали? Я уже использовал перед Regex, но я не продвинутый, и мне все еще сложно. – user2592968

ответ

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 (нулевой столбец), а совпадающее значение группы доступно в объекте Match после того, как было выполнено совпадение.

  2. (?:answer|sent) - группа, не связанная с захватом, которая будет соответствовать либо answer, либо sent, но то, что она соответствует, не фиксируется. Основная часть регулярного выражения также составлена ​​из группы, не связанной с захватом, которая будет соответствовать линии Command или линии Event.

  3. \S+ соответствует одному или нескольким символам без пробелов.

  4. Начиная регулярное выражение с ^ и заканчивая его $, обеспечивается соответствие всей строки.

Чтобы поместить результаты в 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 как случайные имена для столбцов.

+0

Это отличный ответ, теперь я попытаюсь его реализовать. – user2592968

+0

Как я могу написать этот столбец прямо к datatable? – user2592968

+0

@ user2592968: Я обновил свой ответ, чтобы показать, как записать значения в 'DataTable'. –

1

Вы можете попробовать использовать метод string.Split, чтобы разделить строку на массив, используя пробел ('') в качестве вашего символа разделения. Затем, основываясь на ваших примерах, вы можете просто использовать правильные индексы в массиве, чтобы получить нужные вам столбцы.

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(); 
Смежные вопросы