2016-12-09 2 views
1

У меня есть данные в файле журнала, и я хочу извлечь строки, которые находятся между двумя фразами «Процесс начался» и «Выполнено», включая начало строки и конца линия.RegEx для извлечения строк между двумя строками в C#

2016-11-28 12:18:59.5286 | 14 | Info | Process Started -ABC ***** 
.... 
.. 
2016-11-28 12:18:59.5286 | 14 | Info | Process Completed -ABC, Status: Failed*** 



2016-11-28 13:18:59.5286 | 14 | Info | Process Started -DEF 
.... 
.. 
2016-11-28 13:18:59.5286 | 14 | Info | Process Completed -DEF Status: Passed*** 

Используя ниже RegEx, я могу извлечь строки, но не начинаются и не заканчиваются линии с заданным совпадением.

Regex r = new Regex("^*?Process Started -"+process.Name+"(.*?)Process Completed: "+process.Name+".*?", RegexOptions.Singleline); 

Выше регулярное выражение возвращение как этот

Process Started -ABC ***** 
.... 
.. 
2016-11-28 12:18:59.5286 | 14 | Info | Process Completed 

Но мне нужно, как это

2016-11-28 12:18:59.5286 | 14 | Info | Process Started -ABC ***** 
.... 
.. 
2016-11-28 12:18:59.5286 | 14 | Info | Process Completed -ABC, Status: Failed*** 
+3

Я лично не буду использовать регулярное выражение для этого случая. Я бы читал строки за строкой и оценивал, содержит ли строка «Process Started» и «Process name». Если да, то я бы начал добавлять строки в список , пока не появляюсь по строке, содержащей «Выполненный процесс» и «Имя процесса». –

+0

@ blaze_125, если я не найду решения, я оставлю только эту опцию. Я думал, что RegEx может быть проще и проще. – raj

ответ

2

Вы близки, но проблема заключается в ленивом кванторе в конце: он будет соответствовать наименьшему значению, которое в этом случае не будет.

Вот пересмотр вашего регулярное выражение, которое работает:

Regex r = new Regex("[^\n]*?Process Started -" 
     + process.Name + "(.*?)Process Completed -" 
     + process.Name + "[^\n]*", RegexOptions.Singleline); 

Изменения я сделал:

  • Вы имели двоеточие вместо тире после "процесса Completed"
  • Самое главное:[^\n]* в начале и в конце предотвращает совпадение строк новой строки, но получает остальную часть строки

Extra Info:

Я не знаю, как вы планируете использовать это в контексте вашего кода, но если вам нужно извлечь все такие разделы, а не для одного конкретного имени процесса, вы можете захватить их все сразу с этим изменением:

Regex r = new Regex("[^\n]*?Process Started -(\w+)(.*?)Process Completed -\1[^\n]*", RegexOptions.Singleline); 

\1 является обратная ссылка на то, что процесс имя было подобрано (\w+). Вы получите набор совпадений, по одному для каждого имени процесса.

+0

Спасибо @Brian Stephens, это отлично работает для записи «Process Started -ABC», но для «Process Started -DEF» вывод начинается с «Process Started -ABC» до «Process Completed -DEF». Это всегда возвращается с начала файла. – raj

+0

@raj: Да, вы правы. Я установил начало регулярного выражения, чтобы оно не соответствовало символам новой строки. –

+0

он работает, как шарм, теперь спасибо! – raj

0

Вы должны были бы использовать опцию Multiline, а затем вы могли сделать что-то вроде этого :

var reg = new Regex(@"^.*Process Started -ABC(.*)$(\n^.*$)*?\n(^.*Process Completed -ABC.*)$", 
        RegexOptions.Multiline); 

Но это отвратительно. Как @ blaze_125 предложил в комментариях, что вы лучше всего, вероятно, разделить на на линии и перебирать ищет StartedCompleted и строк, а затем захватывая все линии в промежутке между

Вы могли бы сделать что-то вроде:

var lines = str.Split('\n'); 

var q = new Queue<string>(); 

foreach (var l in lines) 
{ 
    q.Enqueue(l); 
    if (l.Contains("Process Completed")) // you could use a regex here if you want more 
              // complex matching 
    { 
     string output; 
     while (q.Count > 0) 
     { 
      // your queue here would contain exactly one entry 
      output = q.Dequeue(); 
      Console.WriteLine(output); 
     } 
    } 
} 
Смежные вопросы