Список именованных захватов/групп в регулярном выражении boost

Я хочу знать, как я могу получить имена групп захвата в регулярном выражении в boost.

Например, если пользователь вводит строку, которая должна быть допустимым регулярным выражением с именованными группами захвата, как можно выполнить итерацию по списку определенных групп в регулярном выражении и получить имена этих групп. Предоставляет ли boost средства для этого, или я должен написать свой собственный синтаксический анализатор для извлечения этих имен?

Например, если входная строка:

(?<year>[0-9]{4}).*(?<month>[0-9]{2}).*(?<day>[0-9]{2})

Я хочу иметь возможность извлекать «год», «месяц» и «день» из регулярного выражения.


person Arash    schedule 11.04.2016    source источник
comment
Возможно, вы могли бы скомпилировать регулярное выражение в регулярное выражение повышения, а затем получить от него имена захвата. Вы могли бы сделать это, но есть проблема с именованными подвыражениями. Технически, когда регулярное выражение анализируется, каждое имя превращается в хэш и помещается в вектор, где дальнейшая ссылка осуществляется через идентификатор. Взгляните на class named_subexpressions в boost_regex.hpp. Его можно изменить, чтобы создать карту фактических имен строк. Где вы можете добавить вызов, чтобы вернуть проиндексированное имя группы.   -  person    schedule 11.04.2016
comment
(Извините, источник должен быть basic_regex.hpp) Я могу опубликовать несколько строк, которые это делают, но вам придется перекомпилировать движок. И я не уверен, что это законно.   -  person    schedule 11.04.2016
comment
Было бы примерно так classnamed_subexpressions{public:...voidset_name(constcharT*i,constcharT*j,intindex){...std::stringstmp(i,j);intalen=(int)stmp.length();if(alen>0){longest_name=alen>longest_name?alen:longest_name;m_sub_sNames[index]=stmp;}}std::stringget_name(intndx)const{if(longest_name>0){autogroupName=m_sub_sNames.find(ndx);if(groupName!=m_sub_sNames.end())returngroupName->second;}return"";}intget_longest_namelen(){returnlongest_name;}private:intlongest_name;std::map<int,std::string>m_sub_sNames;...};   -  person    schedule 11.04.2016
comment
Вы бы перебирали группы. Получите количество групп захвата из объекта регулярного выражения. номер группы = 0 - число_групп std::string grpname = rxobj.get_named_subs()->get_name( grpnum ); if (grpname.length() > 0) { ...}   -  person    schedule 11.04.2016
comment
@sln Спасибо! хорошее решение, но я сомневаюсь, что получу разрешение на изменение кода повышения в репозитории... по крайней мере, я знаю, почему изначально я не мог найти средство! Его просто не было! :-)   -  person Arash    schedule 12.04.2016
comment
Не нужно менять библиотеку boost. Единственный способ использовать регулярное выражение boost — это связать с библиотекой. Однако вам не нужно этого делать. Распакуйте boost zip локально на вашем компьютере. Скопируйте исходные файлы регулярных выражений отсюда (root)\boost\regex\v4 (все файлы hpp) в каталог вашего приложения. Задайте в качестве пути включения (root). Установите эти препроцессоры, определяющие BOOST_ALL_NO_LIB\nBOOST_REGEX_NON_RECURSIVE\nBOOST_REGEX_BLOCKSIZE=32768\nBOOST_REGEX_MAX_BLOCKS=8192\nBOOST_REGEX_MAX_CACHE_BLOCKS=4096\n. Тогда все готово, просто перекомпилируйте. Мгновенное регулярное выражение, не нужно ссылаться, чтобы увеличить библиотеки. Добавляет дополнительные 300 000 к приложению.   -  person    schedule 13.04.2016


Ответы (1)


Вы можете использовать следующее регулярное выражение:

"\?<([^<>]+)>"

Я не думаю, что механизмы регулярных выражений предоставляют такую ​​​​возможность давать вам имена захваченных групп перед компиляцией регулярного выражения, потому что ему нужно пройти входное регулярное выражение один раз перед синтаксическим анализом (и компиляцией) регулярного выражения, что не является оптимальным методом, если только он компилирует регулярное выражение один раз и выполняет всю работу вместе.

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

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

Например, вы можете использовать вышеупомянутое регулярное выражение в скобках для захвата всех групп, в которых нет другой группы захвата ([^()]* гарантирует, что):

`\((\?<([^<>]+)>)[^()]*\)`

А для других случаев вы должны написать еще один.

person kasravnd    schedule 11.04.2016
comment
Спасибо за ответ. Мне было более любопытно узнать, обеспечивается ли это механизмами регулярных выражений или нет. Я пытался найти такое средство, но тщетно. Вы знаете, как узнать, к какой группе захвата принадлежит извлеченное имя? предположим, что вторая группа захвата не названа во входном регулярном выражении... (?<year>[0-9]{4}).*([0-9]{2}).*(?<day>[0-9]{2}) можем ли мы узнать, что день на самом деле относится к третьей группе захвата? - person Arash; 11.04.2016