Regex, чтобы повторить захват через CDL? - PullRequest
1 голос
/ 26 мая 2010

У меня есть некоторые данные в этой форме:

@"Managers Alice, Bob, Charlie
Supervisors Don, Edward, Francis"

Мне нужен плоский вывод, подобный этому:

@"Managers Alice
Managers Bob
Managers Charlie
Supervisors Don
Supervisors Edward
Supervisors Francis"

Фактическим «названием должности», приведенным выше, может быть любое отдельное слово, нет отдельного списка для работы.

Замена , на \r\n достаточно проста, как и первая замена:

Replace (^|\r\n)(\S+\s)([^,\r\n]*),\s
With $1$2$3\r\n$2

Но захватить другие имена и применить тот же префикс - вот что ускользает от меня сегодня. Есть предложения?

Я ищу серию из одного или нескольких вызовов RegEx.Replace(), без каких-либо LINQ или процедурного кода в C #, что, конечно, было бы тривиально. Реализация не напрямую в C # код Я настраиваю универсальный инструмент синтаксического анализа, который использует серию регулярных выражений .NET для преобразования входящих данных из различных источников для нескольких целей.

Ответы [ 4 ]

1 голос
/ 27 мая 2010

Вот решение для чистой замены:

string s = @"Managers Alice, Bob, Charlie
Supervisors Don, Edward, Francis";
Regex r = new Regex(@"(?:^\w+)?( \w+)(?<=^(\w+)\b.*)[,\r\n]*",
    RegexOptions.Multiline);
string s1 = r.Replace(s0, "$2$1\r\n");

После того, как каждое имя сопоставлено, просмотр назад возвращается к началу текущей строки, чтобы захватить заголовок. (?:^\w+)? и [,\r\n]* используются только для тех частей строки, которые вы не хотите хранить.

0 голосов
/ 26 мая 2010

Поскольку вы подчеркнули необходимость регулярных выражений, вот решение, которое должно работать для вас.

string input = @"Managers Alice, Bob, Charlie
Supervisors Don, Edward, Francis";
string pattern = @"(?<Title>\w+)\s+(?:(?<Names>\w+)(?:,\s+)?)+";

foreach (Match m in Regex.Matches(input, pattern))
{
    Console.WriteLine("Title: {0}", m.Groups["Title"].Value);
    foreach (Capture c in m.Groups["Names"].Captures)
    {
        Console.WriteLine(c.Value);
    }

    Console.WriteLine();
}

Основная концепция состоит в том, чтобы использовать именованную группу «Заголовок» для хранения названий должностей и ссылки на них позже.Имена хранятся в коллекции захвата.Шаблон будет работать только в том случае, если данные, конечно, правильно отформатированы, как указано в данных образца.

Структура шаблона выглядит следующим образом: (?<Title>\w+)\s+(?:(?<Names>\w+)(?:,\s+)?)+

  • (?<Title>\w+)\s+ -соответствует заголовку перед первым пробелом и помещает его в именованную группу Title.Должен быть хотя бы один пробел.
  • (?: (? \ W +) (?:, \ S +)?) + - имя сохраняется в группе Names через часть (?<Names>\w+), изапятая и хотя бы один пробел совпадают (но не фиксируются, поскольку используется (?:...)) через часть (?:,\s+)?, и это необязательно, так как после нее ставится ?.Наконец, вся часть шаблона заключена в группу, которая должна быть сопоставлена ​​хотя бы один раз (?:...)+, но не захвачена, поскольку мы собираем только те части, которые нам интересны.
0 голосов
/ 26 мая 2010

Вы можете искать

^(\w+)[ \t]+(\w+),[ \t]+(.+)$

и заменить все на

\1 \2\r\n\1 \3

Вам нужно применить его дважды к вашему примеру, три раза, если список менеджеров увеличится до четырех и т. Д.

Итак, в C #:

resultString = Regex.Replace(subjectString, @"^(\w+)[ \t]+(\w+),[ \t]+(.+)$", @"$1 $2\r\n$1 $3", RegexOptions.Multiline);

Пояснение:

^: соответствует началу строки

(\w+)[ \t]+: сопоставить любое количество символов alnum, зафиксировать совпадение; соответствует следующему пробелу

(\w+): сопоставить следующее «слово», затем

,[ \t]+(.+)$ соответствует запятой, пробелам и тому, что следует до конца строки. Это будет совпадать, только если строка все еще содержит контент, который нужно разделить.

0 голосов
/ 26 мая 2010

Зачем использовать регулярное выражение, если вы можете сделать это с помощью LINQ?

string s = "Managers Alice, Bob, Charlie\r\nSupervisors Don, Edward, Francis";

var result =
    from line in s.Split(new string[] { "\r\n" }, StringSplitOptions.None)
    let parts = line.Split(new char[] { ' ' }, 2)
    let title = parts[0]
    let names = parts[1]
    from name in names.Split(new char[] { ',' })
    select title.Trim() + " " + name.Trim();

string.Join("\r\n", result) - это

Managers Alice
Managers Bob
Managers Charlie
Supervisors Don
Supervisors Edward
Supervisors Francis
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...