Мой вопрос о том, может ли механизм регулярных выражений boost выполнять "глобальный поиск".
Я пробовал, но не могу заставить его это сделать.
Класс match_results содержит базовый указатель строки, поэтому после увеличения
начальной позиции вручную и установки match_flag_type
на match_not_bob | match_prev_avail
,
я думал, что обработчик регулярных выражений Boost сможет узнать, что он находится в середине строка.
Поскольку я использую этот движок в своем программном обеспечении, я хотел бы знать, может ли этот движок сделать это правильно, и я делаю что-то неправильно, или глобальный поиск невозможен с этим движком.
Ниже приведен пример кода/вывода с использованием регулярного выражения BOOST и эквивалентного сценария Perl.
Изменить. Чтобы уточнить, в приведенном ниже примере повышения итератор Start
всегда рассматривается как граница. Кажется, что движок не учитывает текст слева от этой позиции при поиске соответствия.
По крайней мере, в этом случае.
22.07.2014 – Решение для глобального поиска
Публикация этого обновления в качестве решения. Это не обходной путь и не кладж.
Погуглив 'regex_iterator', я понял, что regex_iterator видит текст слева от текущей
позиции поиска. Причем, мне попадались все те же исходники. На одном сайте (как и на других)
было краткое простое объяснение того, как это работает, в котором говорилось, что он вызывает 'regex_search()'
при увеличении regex_iterator.
Итак, в недрах класса regex_iterator я увидел, что он действительно вызывал regex_search(), когда
итератор увеличивался ->Next().
Эта перегруженная версия regex_search() не была задокументирована и существует только в одном типе.
Она включает в конце параметр BIDI с именем base.
bool regex_search(BidiIterator first, BidiIterator last,
match_results<BidiIterator, Allocator>& m,
const basic_regex<charT, traits>& e,
match_flag_type flags,
BidiIterator base)
{
if(e.flags() & regex_constants::failbit)
return false;
re_detail::perl_matcher<BidiIterator, Allocator, traits> matcher(first, last, m, e, flags, base);
return matcher.find();
}
Похоже, что база — это стена слева от начала BIDI, откуда начальный просмотр назад может использоваться для проверки условий.
Итак, я протестировал его, и он, похоже, сработал.
Суть в том, чтобы установить базовый BIDI в начале ввода, а начальный BIDI поставить где угодно после.
По сути, это похоже на настройку pos( ) переменная в Perl.
А чтобы эмулировать глобальное позиционное приращение при совпадении нулевой длины,
достаточно простого условного оператора:
Start = ( _M[0].length() == 0) ? _M[0].first + 1 : _M[0].second;
(см. ниже)
Регулярное выражение BOOST 1.54 regex_search() с использованием «базового» BIDI
Примечание. В этом примере Start always = _M[0].second;
Регулярное выражение намеренно отличается от двух других примеров ( под ним), чтобы продемонстрировать на самом деле
текст от 'Base' до 'Start' учитывается каждый раз при сопоставлении этого регулярного выражения.
#typedef std::string::const_iterator SITR;
boost::regex Rx( "(?<=(.)).", regex_constants::perl );
regex_constants::match_flag_type Flags = match_default;
string str("0123456789");
SITR Start = str.begin();
SITR End = str.end();
SITR Base = Start;
boost::smatch _M;
while ( boost::regex_search( Start, End, _M, Rx, Flags, Base) )
{
string str1(_M[1].first, _M[1].second );
string str0(_M[0].first, _M[0].second );
cout << str1 << str0 << endl;
// This line implements the Perl global match flag m//g ->
Start = ( _M[0].length() == 0) ? _M[0].first + 1 : _M[0].second;
}
output:
01
12
23
34
45
56
67
78
89
Перл 5.10
use strict;
use warnings;
my $str = "0123456789";
while ( $str =~ /(?<=(..))/g )
{
print ("$1\n");
}
output:**
01
12
23
34
45
56
67
78
89
Регулярное выражение BOOST 1.54 regex_search() без «базы»
string str("0123456789");
std::string::const_iterator Start = str.begin();
std::string::const_iterator End = str.end();
boost::regex Rx("(?<=(..))", regex_constants::perl);
regex_constants::match_flag_type Flags = match_default;
boost::smatch _M;
while ( boost::regex_search( Start, End, _M, Rx, Flags) )
{
string str(_M[1].first, _M[1].second );
cout << str << "\n";
Flags |= regex_constants::match_prev_avail;
Flags |= regex_constants::match_not_bob;
Start = _M[0].second;
}
output:
01
23
45
67
89
Start = (_M[0].length() == 0) ? _M[0].first + 1 : _M[0].second;
прерывается с помощью регулярного выражения(?<=.).
Даже(?=.)
отправляет его в бесконечный цикл с использованиемStart = _M[0].second;
Я мог бы написать обходной путь в этом случае, но невозможность увидеть текст в местах ‹ Start делает его калекой. 16.07.2014start = (match.length(0)? match[0] : match.prefix()).first + 1;
. Но, честно говоря, единственное, что я вижу, работает в общем, это простоstart += 1
, но это может быть дорого для производительности в простых случаях. 16.07.2014match.prefix()
я знаю, что он есть, но с чего начать? 16.07.2014regex_search
не может выполнять глобальный поиск. Но я как-то узнал, чтоregex_iterator
делает это. Спасибо за вашу помощь/предложение. 16.07.2014