Как разбить строку с текстом в список?

177
13 сентября 2018, 12:20

Есть текст вида:

"1) первый вопрос 2) второй вопрос 3)вопрос и тд"

Как наименее трудозатратно (наименьшим кодом) его можно распарсить в массив строк по номерам. Понятно что можно посимвольно считывать, запоминать позицию, вырезать подстроку, но может есть более простое решение, м.б. регулярки?

Answer 1

Можно и регуляркой:

var text = "1) первый вопрос 2) второй вопрос 3)вопрос и тд";
var pattern = @"\s*\d+\)\s*";
var result = Regex.Split(text, pattern)
                  .Where(s => !string.IsNullOrWhiteSpace(s)) // Выбросим пустые куски (первый точно будет пустым)
                  .ToList();

Здесь:

\s*  Любое количество пробельных символов
\d+  Одна или более цифр
\)   Закрывающая скобка
\s*  Любое количество пробельных символов

Результат:

Если вы хотите запомнить также и номер вопроса, то можно сделать это в 2 этапа: сначала разбиваем строку на куски по \d+\) не включая само совпадение, а потом из каждого куска выбрать отдельно номер и тело вопроса:

var text = "1) первый вопрос 2) второй вопрос 3)вопрос и тд";
var splitPattern = @"(?<!^)(?=\d+\))";
var result = Regex.Split(text, splitPattern);
var selectPattern = @"(\d+)\s*\)\s*(.+)";
var questions = result.Select(r => Regex.Match(r, selectPattern).Groups)
                      .ToDictionary(g => g[1].Value, g => g[2].Value);

Здесь:

В выражении для разбиения:
(?<!...)  Негативный просмотр назад, т.е. находим (не)совпадение перед тем местом, по которому нужно разрезать строку, но само совпадение не включаем в результат
^         Начало строки
(?=...)   Позитивный просмотр вперед, т.е. находим совпадение после того места, по которому нужно разрезать строку, но само совпадение не включаем в результат
\d+       Одна или более цифр
\)        Закрывающая скобка
В выражении для выбора номера и тела вопроса:
(\d+)     Одна или более цифр, помещаем в первую группу (потом будем использовать в качестве ключа словаря: g[1]
\s*       Любое количество пробельных символов (вне групп, т.к. они нам не нужны)
\)        Закрывающая скобка (вне групп)
\s*       Любое количество пробельных символов (вне групп)
(.+)      Все символы до конца строки, помещаем во вторую группу

Результат:

Либо в один этап:

var text = "1) первый вопрос 2) второй вопрос 3)вопрос и тд";
var pattern = @"(\d+)\s*\)\s*(.+?)(?=\s*(\d+\)|$))";
var questions = Regex.Matches(text, pattern)
                     .OfType<Match>()
                     .ToDictionary(m => m.Groups[1].Value, m => m.Groups[2].Value);

Здесь:

(\d+)      Одна или более цифр, помещаем в первую группу
\s*        Любое количество пробельных символов, вне групп
\)         Закрывающая скобка, вне групп
\s*        Любое количество пробельных символов, вне групп
(.+?)      Любые символы, здесь ленивый выбор, иначе будет захвачена вся строка за один раз
(?=...)    Позитивный просмотр вперед
\s*        Любое количество пробельных символов
(...|...)  Или то или то
\d+\)      Одна или более цифр + зарывающая скобка
$          Конец строки

Результат:

READ ALSO
Asterisk. Список абонентов в отдельном файле

Asterisk. Список абонентов в отдельном файле

Изучаю asterisk и на данный момент уже поднял сервер на Ubuntu и совершаю звонки с/на устройствахИнтересует вопрос: можно ли каким-нибудь образом...

163
Оптимизация скрипта-парсера xml

Оптимизация скрипта-парсера xml

очень прошу помочь мне оптимизировать скрипт (xml парсер) по памяти

185
Поиск слов в базе данных

Поиск слов в базе данных

В базе есть строка такого вида a:3:{i:0;s:16:"Женщинам";i:1;s:12:"одежда";i:2;s:14:"Пиджаки";} те функция php serialize нужно осуществить поиск по словам: Женщинам...

197
Как скрыть записи в блоге от неавторизованных?

Как скрыть записи в блоге от неавторизованных?

Вот простое требованиеЗаходишь на сайт как гость и видишь сообщение типа "авторизуйтесь для просмотра записей", войдя на сайта видны все...

169