BOOST Regex全局搜索行为

BOOST Regex global Search behavior

本文关键字:全局搜索 Regex BOOST      更新时间:2023-10-16

我的问题是关于boost regex引擎是否可以做"全局搜索"。
我试过了,但我不能让它这么做。

match_results类包含string对象的基指针,因此在
加1之后手动启动位置,然后设置match_flag_typematch_not_bob | match_prev_avail
我本以为增强正则表达式引擎将能够知道它是在字符串的中间。

因为我在我的软件中使用这个引擎,我想知道如果这个引擎实际上可以正确地做到这一点,我做错了什么,或者全局搜索是不可能的这个引擎。

下面是使用BOOST正则表达式的示例代码/输出,以及等效的Perl脚本。

编辑:只是为了澄清,在下面的boost示例中,Start迭代器始终被视为边界。在进行匹配时,引擎似乎不考虑该位置左侧的文本。
至少在这种情况下。

7/22/2014 - 全局搜索的解决方案

发布此更新作为解决方案。这不是一个变通或拼凑。
在谷歌上搜索"regex_iterator"之后,我知道regex_iterator看到的是
左边的文本。当前搜索位置。而且,我遇到了所有相同的源代码。一个站点(和其他站点一样)
有一个简单的解释它是如何工作的,说它调用'regex_search()'
当regex_iterator自增时。

所以在regex_iterator类的内部,我看到它确实调用了regex_search()当
迭代器自增->Next()。

这个'regex_search()'重载没有文档记录,只有一种类型。
它在末尾包含一个名为'base'的BIDI参数。

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放在后面的任何位置。
实际上,这类似于在Perl中设置pos()变量。

并且,为了模拟零长度匹配的全局位置增量,一个简单的条件就是
需要:

Start = ( _M[0].length() == 0) ? _M[0].first + 1 : _M[0].second;(见下文)

BOOST Regex 1.54 regex_search() using 'base' 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
Perl 5.10

use strict;
use warnings;
my $str = "0123456789";
while ( $str =~ /(?<=(..))/g )
{
    print ("$1n");
}
output:**
01
12
23
34
45
56
67
78
89

BOOST Regex 1.54 regex_search() no 'base'

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

更新回应评论Live On Coliru:

#include <boost/regex.hpp>
int main()
{
    using namespace boost;
    std::string str("0123456789");
    std::string::const_iterator start = str.begin();
    std::string::const_iterator end = str.end();
    boost::regex re("(?<=(..))", regex_constants::perl);
    regex_constants::match_flag_type flags = match_default;
    boost::smatch match;  
    while (start<end && 
           boost::regex_search(start, end, match, re, flags))
    {
        std::cout << match[1] << "n";
        start += 1; // NOTE
        //// some smartness that should work for most cases:
        // start = (match.length(0)? match[0] : match.prefix()).first + 1;
        flags |= regex_constants::match_prev_avail;
        flags |= regex_constants::match_not_bob;
        std::cout << "at '" << std::string(start,end) << "'n";
    }
}

打印:

01  at '123456789'
12  at '23456789'
23  at '3456789'
34  at '456789'
45  at '56789'
56  at '6789'
67  at '789'
78  at '89'
89  at '9'