Подпрограммы без захвата

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

Например, предположим, что я хочу рекурсивно сопоставить и зафиксировать структуру сбалансированной скобки {}, например

{dfsdf{sdfdf{ {dfsdf} }}dfsf}

Я мог бы использовать это регулярное выражение:

(^(?'nest'\{(?>[^{}]|(?&nest))*\}))

первая группа - это то, что я хочу захватить.

Однако мое определение «гнезда»:

(?'nest' ... )

и мой рекурсивный вызов подпрограммы «гнездо»:

(?&nest)

также группы захвата. Я хотел бы сделать свое регулярное выражение более эффективным и сэкономить место, не захватывая эти группы. Есть какой-либо способ сделать это?

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


редактировать2:

Я тестирую это регулярное выражение с помощью boost::regex, а также регулярного выражения notepad++. На самом деле они определяют разные группы захвата, что для меня странно. У меня сложилось впечатление, что они оба используют регулярное выражение Perl по умолчанию.

В любом случае, задав вопрос, у меня было регулярное выражение:

^\w+\s+[^\s]+\s+(?'header'(?'nest'\{(?>[^{}]|(?&nest))*\}))(?>\s+[^\s]+){5}\s+(?'data'(?>\{(?>[^{}]|(?&nest))*\}))\s+(?'class'(?>\{(?>[^{}]|(?&nest))*\}))

который, как я позже понял, содержал ненужные символы, которые уже инкапсулированы «гнездо». А у меня сейчас:

^\w+\s+[^\s]+\s+(?'nest'\{(?>[^{}]|(?&nest))*\})(?>\s+[^\s]+){5}\s+((?&nest))\s+((?&nest))

Notepad++ предоставляет мне 3 группы захвата, когда я делаю оператор замены

\\1: \1 \n \\2: \2 \n 3: \3 \n 4: \4

Он говорит мне, что «1 вхождение было заменено, следующее вхождение не найдено». В замене нет текста после 4:, что заставляет меня поверить, что 4-й группы захвата не существует.

ОДНАКО boost::regex_match возвращает объект с 6 позициями:

0: метаданные матча

1: весь матч

2: весь матч

3: группа1 из блокнота++

4: группа2 из блокнота++

5: группа3 из блокнота++

Я все еще пытаюсь отправить позиции 1 и 2.


редактировать3

Я неправильно понял еще одну часть головоломки...

boost::cmatch.m_subs[i] != boost::cmatch[i]

Я думал, что они равны. После еще некоторой отладки оказывается, что индексация в объект работает именно так, как написано в документации. Но я ошибочно предположил, что объект будет содержать структуру, отражающую то, что возвращает boost::cmatch[i]. Похоже, что boost::cmatch[i] сначала удаляет все записи из m_subs, которые соответствуют == false. Остальные записи совпадают с тем, что возвращает boost::cmatch[i].


person Derek    schedule 15.06.2017    source источник
comment
Если вам нужно сопоставить эту сбалансированную подстроку {...} в начале строки, нет, нет способа использовать вызов подпрограммы без захвата.   -  person Wiktor Stribiżew    schedule 15.06.2017
comment
Есть ли для этого причина? Похоже, что эта функция улучшит функциональность регулярных выражений.   -  person Derek    schedule 15.06.2017
comment
Я бы скорее назвал это преждевременной оптимизацией.   -  person Wiktor Stribiżew    schedule 15.06.2017
comment
Выложил способ как это сделать. Но я вижу, ты признал, что нет способа сделать это, ааа..   -  person    schedule 15.06.2017
comment
@sln: см. свой собственный ответ: Capture Groups = 1. Для механизма регулярных выражений должна существовать группа захвата, чтобы рекурсивно выполнить ее. Будь то блок DEFINE или потребляющий подшаблон, он должен быть определен. До сих пор хранится в памяти. Проблема OP заключается не в результирующей структуре объекта сопоставления, а в возможности рекурсии группы без захвата. Что невозможно.   -  person Wiktor Stribiżew    schedule 15.06.2017
comment
@WiktorStribiżew - Яблоки и апельсины. =› regex101.com/r/aT4TlM/1 Внутри нет группы захвата, только функция. May only be used to define functions. No matching is done in this group.   -  person    schedule 15.06.2017
comment
@sln, точно, яблоки и апельсины. Как я уже упоминал, OP интересует не структура объекта соответствия, а внутреннее устройство. Механизм регулярных выражений по-прежнему хранит группу DEFINEd в памяти, чтобы знать, что рекурсивно.   -  person Wiktor Stribiżew    schedule 15.06.2017
comment
@WiktorStribiżew. Как я уже сказал, это не группа захвата внутри конструкции DEFINE. Вызовы являются точкой перехода в код состояния регулярных выражений, не имеют ничего общего с захватами.   -  person    schedule 15.06.2017
comment
boost::regex_match соответствует полной входной строке. Если вы хотите заменить глобально, используйте функцию boost::regex_replace. Можете ли вы опубликовать используемую целевую строку?   -  person    schedule 15.06.2017
comment
Я бы хотел, но у меня нет на это сил. Но я считаю, что в любом случае это был концептуальный вопрос, и я более чем удовлетворен ответами, данными без просмотра реального текста.   -  person Derek    schedule 15.06.2017


Ответы (3)


Любая подпрограмма, помещенная в конструкцию (?(DEFINE).), ничего не захватит.

Если вы просто хотите избежать каких-либо захватов, это делается так

https://regex101.com/r/aT4TlM/1

Обратите внимание -

Конструкция определения подшаблона (?(DEFINE)(?'nest'\{(?>[^{}]|(?&nest))*\}))
Может использоваться только для определения функций. В этой группе сопоставление не выполняется.

^(?&nest)(?(DEFINE)(?'nest'\{(?>[^{}]|(?&nest))*\}))

И так как у вас есть якорь BOS, ^ это единственный способ.
Т.е. (?R) не вариант.

Расширенный

 ^ 
 (?&nest) 

 (?(DEFINE)

      (?'nest'                      # (1 start)
           \{
           (?>
                [^{}] 
             |  (?&nest) 
           )*
           \}
      )                             # (1 end)
 )

Выход

  **  Grp 0        -  ( pos 0 , len 29 ) 
 {dfsdf{sdfdf{ {dfsdf} }}dfsf}  
  **  Grp 1 [nest] -  NULL 

Метрики

----------------------------------
 * Format Metrics
----------------------------------
Atomic Groups       =   1

Capture Groups      =   1
       Named        =   1

Recursions          =   2

Conditionals        =   1
       DEFINE       =   1

Character Classes   =   1
person Community    schedule 15.06.2017
comment
Спасибо за всю информацию, я отредактировал свой вопрос, чтобы лучше описать, что происходит. - person Derek; 15.06.2017

Вызов подпрограммы — это механизм, который рекурсивно использует подшаблоны. Механизм регулярных выражений должен знать, какую группу рекурсивно использовать, и поэтому ему требуется либо ее идентификатор (если группа нумерована), либо имя (если это именованная группа, как в вашем случае). Группы без захвата НЕ хранят ссылки на шаблоны этих групп, поэтому вы не можете ссылаться на них внутри вызова подпрограммы.

Единственный способ не использовать группу захвата в вызове подпрограммы — использовать ярлык для всего шаблона, (?R). НО это не вариант, когда вам нужно рекурсировать часть шаблона (как в вашем случае, когда вы хотите сопоставить начало строки и рекурсивно только часть шаблона после ^.

person Wiktor Stribiżew    schedule 15.06.2017
comment
Спасибо за быстрый ответ. Я расширил свой вопрос, чтобы отразить, что у меня было более глубокое недопонимание. - person Derek; 15.06.2017
comment
@Derek Как видите, даже в блоке DEFINE группа захвата используется для определения подшаблона. Разница лишь в том, что этот захват не возвращается в результатах матча. Вы не можете избежать определения шаблона в качестве группы захвата, если вам нужно его повторно использовать, вы можете только избежать его включения в результат сопоставления. - person Wiktor Stribiżew; 15.06.2017

Re: Edit2

Это регулярное выражение ^\w+\s+[^\s]+\s+(?'nest'\{(?>[^{}]|(?&nest))*\})(?>\s+[^\s]+){5}\s+((?&nest))\s+((?&nest))

можно увидеть при форматировании, чтобы он содержал только 3 группы.

 ^ \w+ \s+ [^\s]+ \s+ 
 (?'nest'                      # (1 start)
      \{
      (?>
           [^{}] 
        |  (?&nest)
      )*
      \}
 )                             # (1 end)
 (?> \s+ [^\s]+ ){5}
 \s+ 
 ( (?&nest) )                  # (2)
 \s+ 
 ( (?&nest) )                  # (3)

Что ты хочешь с этим сделать?

person Community    schedule 15.06.2017
comment
Он работает ТОЧНО так, как предполагалось... мое исходное регулярное выражение было неверным, но я предположил, что написал его правильно и что неправильная группировка была признаком основного программного обеспечения, а не моего регулярного выражения. Это было усугублено моей неправильной интерпретацией объекта boost::cmatch, как он появляется во время отладки в VS2013. - person Derek; 15.06.2017
comment
Да, из документации видно, что Objects of type sub_match may only be obtained by subscripting an object of type match_results. sub_match, полученный из match_results[I], содержит методы для получения информации о группе. Подобно итераторам first/last ( for string(m[2].first,m[2].second) ), логическим значениям типа matched и другим прямым преобразованиям строк, таким как m[2].basic_string(). А также положение и длина. - person ; 15.06.2017
comment
Когда я использую sub_match, иногда я иду глубже, вплоть до этого уровня (int)_m[ i ].first._Ptr, чтобы напрямую сравнивать с другими длинами и местоположениями или конкретными несвязанными смещениями. - person ; 15.06.2017