Разделение строки с помощью регулярного выражения, игнорирование разделителей в фигурных скобках

Предположим, у меня есть строка

Max and Bob and Merry and {Jack and Co.} and Lisa.

Мне нужно разделить его так, чтобы and был разделителем, , но только если он не находится в фигурных скобках.

Итак, из приведенной выше строки я должен получить 5 строк:
Max, Bob, Merry, Jack and Co., Lisa.

Я пробовал что-то вроде этого шаблона:

[^\\\{.+]\\band\\b[^.+\\\}]

Но это не работает - Jack и Co. тоже разделены (я использую C ++, поэтому мне приходится дважды экранировать специальные символы).


person Maximko    schedule 11.12.2016    source источник
comment
Поддерживает ли qregexp прогнозирование вперед? Если да, попробуйте \\band\\b(?![^{]*}), возможно, потребуется больше экранирования.   -  person bobble bubble    schedule 11.12.2016
comment
В C ++ для регулярных выражений можно использовать необработанный строковый литерал, заключенный в R"( и )". Таким образом, можно использовать обратную косую черту напрямую, т.е. R"(\d*)"   -  person Meyer    schedule 11.12.2016
comment
Вы хотите разделить со слишком большим количеством условий, похоже, что соответствие с двумя шагами может оказаться лучше: 1) извлечь то, что находится внутри фигурных скобок, с помощью QRegExp("\\{([^{}]*)\\}") и 2) разделить с помощью "\\{[^{}]*\\}|\\s*\\band\\b\\s*"   -  person Wiktor Stribiżew    schedule 11.12.2016
comment
bobble bubble, спасибо, похоже, работает именно так, как ожидалось. (Да, предварительный просмотр поддерживается в QRegExp, а QRegularExpression также поддерживает предварительный просмотр).   -  person Maximko    schedule 11.12.2016


Ответы (3)


Если QRegExp поддерживает опережающий просмотр, вы можете проверить наличие фигурных скобок, посмотрев вперед на последняя граница слова, если между ними есть закрывающий } без открытия {.

\band\b(?![^{]*})

См. эту демонстрацию на regex101

Необходимо экранировать по желанию или попробовать необработанный строковый литерал, как прокомментировал @SMeyer.

person bobble bubble    schedule 11.12.2016

Вот возможное решение, частично основанное на комментарии bobble-bubble. Он выдаст пять строк по запросу, без окружающих пробелов или фигурных скобок.

std::string text = "Max and Bob and Merry and {Jack and Co.} and Lisa";
std::regex re(R"(\}? +and +(?![^{]*\})\{?)");

std::sregex_token_iterator it(text.begin(), text.end(), re, -1);
std::sregex_token_iterator end;

while (it != end)
    std::cout << *it++ << std::endl;

Я старался не усложнять, возможно, вы захотите заменить пробелы вокруг and на полное определение пробелов. Интерактивная версия доступна здесь.

person Meyer    schedule 11.12.2016

Пусть сначала совпадет часть {...}. То есть поместите его слева от |.

\{.*?\}|and

Если возможно, это будет соответствовать {foo and bar}, но если нет, то оно будет пытаться сопоставить and.

person Waxrat    schedule 11.12.2016
comment
Он разделится на {...}, удалив его. - person Nicolas; 11.12.2016
comment
да. Таким образом, вы, вероятно, захотите использовать функцию разделения, которая возвращает то, что было найдено. - person Waxrat; 11.12.2016
comment
Не знаю, о каком языке мы говорим, но в Python вы можете вернуть разделители, используя скобки в регулярном выражении: m=re.split(r'(\{.*?\}|and)',s) - person Waxrat; 11.12.2016
comment
Даже в этом случае он будет соответствовать скобкам, а не только тому, что внутри. - person Nicolas; 11.12.2016
comment
Правда. Вы хотите сказать, что думаете, что это проблема? - person Waxrat; 11.12.2016