2015-10-01 1 views
1

Я новичок в .NET и не столь велик с RegEx, но с тем, что у меня есть следующие code-Удалить дубликаты Captures из списка

var p = GetAllMatches(lines, @"^\s+?([A-Z]{1,2}[0-9]{2}) : |: ([A-Z]{1,2}[0-9]{2})") 
         .SelectMany(m => m.Groups[1].Captures.Cast<Capture>().Select(c => c.Value).ToList()) 
         .ToList(); 


    private static List<Match> GetAllMatches(List<string> lines, string pattern, RegexOptions options=RegexOptions.None) 
    { 
     return lines 
      .Select(l => Regex.Match(l, pattern, options)) 
      .Where(m => m.Success) 
      .ToList(); 
    } 

... который, я считаю, захватывает порции строка, начинающаяся с «:», за которой следуют 1 или 2 альфа-символа и 2 цифры или части строки, заканчивающиеся на «:», и им предшествуют 1 или 2 альфа-символа и 2 цифры.

Так, например, он должен захватить "C61, C62, C61" в следующем блоке текст-

blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345

Главная Хранение: C61
C62: 1215
C61: 1785

blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345blablablabla12345

До сих пор так хорошо. Мой вопрос таков: как я могу это сделать, чтобы он только фиксировал конкретный матч ОДИН РАЗ? Поэтому в приведенном выше примере мне бы хотелось, чтобы он в конечном счете выплюнул «C61, C62», а не «C61, C62, C61». Возможно ли это с RegEx или я должен манипулировать списком после того, как RegEx будет сделан с его захватом? В любом случае, как бы я подошел к нему?

Заранее благодарим за предоставленную помощь.

ответ

3

@Nefarrii ответил, как удалить дубликаты из списка, который, безусловно, то, что должно быть сделано здесь! Это быстрее, проще, дешевле, лучше.

Я буду вносить вклад в часть регулярного выражения на случай, если вам интересно. Да, это можно сделать.

Вы уже фиксируете каждый токен, поэтому все, что вам нужно сделать, это использовать lookahead, чтобы проверить, не следует ли «за ним не следовать тот же текст» (с использованием backreference).

Regex:

(?: : (?<portion>[A-Z]{1,2}[0-9]{2})|^\s*(?<portion>[A-Z]{1,2}[0-9]{2}) :)(?!.*(?: : \k<portion>|^\s*\k<portion> :)) 
     ^^^^^^^^^^               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
(same group, with a name)   (negative lookahead: it's not followed by the text captured in group <portion>) 
  • Использование RegexOptions.Singleline | RegexOptions.Multiline
  • Примечание Я использую named groups.


Код:

string input = "blablablabla12345b\nMain Storage : C61\nC62 : 1215\nC61 : 1785\nblablablabla12345blablablabla"; 

string pattern = @"(?: : (?<portion>[A-Z]{1,2}[0-9]{2})|^\s*(?<portion>[A-Z]{1,2}[0-9]{2}) :)(?!.*(?: : \k<portion>|^\s*\k<portion> :))"; 
MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.Singleline | RegexOptions.Multiline); 

foreach (Match match in matches) 
{ 
    GroupCollection groups = match.Groups; 
    Console.WriteLine(groups["portion"].Value); 
} 

ideone Demo

+1

приятно, не знаю, что было возможно, как это +1 – Nefariis

+0

Amazing! Открывает совершенно новую область возможностей! Спасибо, что показал мне это. – Brady

+0

Рад, что вам понравилось – Mariano