Регулярное соответствие RegEx несколько раз в строке
Я пытаюсь извлечь значения из строки, которые находятся между < < и → . Но они могут произойти несколько раз.
Может ли кто-нибудь помочь с регулярным выражением, чтобы соответствовать этим,
this is a test for <<bob>> who like <<books>>
test 2 <<frank>> likes nothing
test 3 <<what>> <<on>> <<earth>> <<this>> <<is>> <<too>> <<much>>.
Затем я хочу, чтобы GroupCollection получил все значения.
Любая помощь очень получена.
Спасибо.
Ответы
Ответ 1
Используйте положительный взгляд вперед и посмотрите за утверждением, чтобы соответствовать угловым скобкам, используйте .*?
чтобы найти максимально короткую последовательность символов между этими скобками. Найдите все значения, MatchCollection
итерацию MatchCollection
возвращенную методом Matches()
.
Regex regex = new Regex("(?<=<<).*?(?=>>)");
foreach (Match match in regex.Matches(
"this is a test for <<bob>> who like <<books>>"))
{
Console.WriteLine(match.Value);
}
LiveDemo в DotNetFiddle
Ответ 2
Вы можете попробовать один из них:
(?<=<<)[^>]+(?=>>)
(?<=<<)\w+(?=>>)
Однако вам придется перебирать возвращенный MatchCollection.
Ответ 3
Что-то вроде этого:
(<<(?<element>[^>]*)>>)*
Эта программа может быть полезна:
http://sourceforge.net/projects/regulator/
Ответ 4
Хотя ответ Питера является хорошим примером использования обходных путей для проверки контекста левой и правой стороны, я бы также хотел добавить LINQ (лямбда) способ доступа к матчам/группам и показать использование простых числовых групп захвата, которые пригодятся, когда вы хочу извлечь только часть шаблона:
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
// ...
var results = Regex.Matches(s, @"<<(.*?)>>", RegexOptions.Singleline)
.Cast<Match>()
.Select(x => x.Groups[1].Value);
Тот же подход с regex
Питера:
var results = regex.Matches(s).Cast<Match>().Select(x => x.Value);
Примечание:
-
<<(.*?)>>
является регулярным выражением, совпадающим с <<
, затем фиксирует любые 0 или более символов как можно меньше (из-за не жадного квантификатора *?
) в группу 1 и затем сопоставляет >>
-
RegexOptions.Singleline
делает .
соответствует символам новой строки (LF) (по умолчанию они не совпадают) -
Cast<Match>()
преобразует коллекцию совпадений в IEnumerable<Match>
которому вы можете получить дальнейший доступ с помощью лямбды. -
Select(x => x.Groups[1].Value)
возвращает только значение группы 1 из текущего объекта совпадения x
- Обратите внимание, что вы можете создать список массивов полученных значений, добавив
.ToList()
или .ToArray()
после Select
.
В демонстрационном коде С# string.Join(", ", results)
генерирует разделенную запятыми строку значений группы 1:
var strs = new List<string> { "this is a test for <<bob>> who like <<books>>",
"test 2 <<frank>> likes nothing",
"test 3 <<what>> <<on>> <<earth>> <<this>> <<is>> <<too>> <<much>>." };
foreach (var s in strs)
{
var results = Regex.Matches(s, @"<<(.*?)>>", RegexOptions.Singleline)
.Cast<Match>()
.Select(x => x.Groups[1].Value);
Console.WriteLine(string.Join(", ", results));
}
Выход:
bob, books
frank
what, on, earth, this, is, too, much