《白话C++》第10章 Page58 10.3.4 string的武器库②

4.复杂查找

谷歌百度的搜索功能很强,不过再牛的搜索功能也要从基础打起,基础就在母串中搜索指定的子串

根据boost的设计,从一个母串中查找子串返回的结果是两个值开始位置和结束位置

比如母串是“玛丽玛丽我爱你”,而查找的是“我爱”,则返回的(原文母串)子串分别位于8和12的迭代器,这一对迭代器构成一个“迭代范围”,体现为boost中定义的一个模板iterator_range <T>。其中T是所要查找的字符串(也可以其他内容),

如果string,那就是string::iterator类型,如果是wstring,那就是wstring::iterator。

再次强调:返回的是两个迭代器,而不是两个数字。并且两个迭代器都指向母串身上的位置(有可能是无效位置,比如查找不到),因此如果得到具体的偏移位置,需要和母串的起始位置迭代器相减:

boost::format fmt("%s: %d ~ %d");

string s = "玛丽玛丽我爱你"; //一个汉字占用两个字节
boost::iterator_range<string::iterator> result
         = str_algo::find_first(s, "我爱");
if(result)
{
    cout << fmt % result
                %(result.begin() - s.begin())
                %(result.end() - s.begin())  << endl;
}
cout << result << endl;

从代码中可以看到,boost::iterator_range提供了转换为bool值的重载,用与判断是否找到,还提供了到字符串转换的重载,会输出其一对迭代器范围内的内容,如果找到的话,就是子串。

【危险】:iterator_range的有效期

注意,既然结果中的两个迭代器都指向母串身上的位置,所以如果在查找之后,母串内容被修改了,那么这两个迭代器就会失效,不应再访问!

还有以下几个find族函数:

//1 不区分大小写的find_first
iterator_range ifind_first(Range1T& Input
                        , const Range2T& Search);

//2 查找子串在母串中最后一次出现的位置(相当于倒查)
iterator_range find_last(Range1T& Input
                        , const Range2T& Search);

//3 查找子串在母串的第N次出现的位置(N从0开始)
iterator_range find_nth(Range1T& Input
                , const Range2T& Search, int N);

//4 查找母串中的所有指定子串(不区分大小写),
//并存入Result容器中
SequenceSequenceT ifind_all(SequenceSequenceT& Result
                , Range1T& Input, const Range2T& Search);

前缀 i: 表示该算法不区分大小写

后面两个函数也提供了i前缀的版本。另外string_algo也提供了基于正则表达式查找,需自行学习。

现在特别关注在母串中连续查找子串的实现

“find_nth”可以查找母串中第N次(N从0开始)出现的子串的位置,但假设已经找到了第N个,则查找第 N+1 次出现的高效做法,应该是从上次查找的位置之后找起。下面是基于上述思路的一个"find_next"的实现:

/*自定义的find_next */
template <typename Range1T
            , typename Range2T
            , typename IteratorRangeT>
IteratorRangeT find_next(Range1T& Input
                        , Range2T const& Search
                        , IteratorRangeT& LastRange)
{
    if(! LastRange)
    {
        return LastRange;
    }

    //搜索范围:上次找到的结束位置,到母串的结束位置
    IteratorRangeT SearchRange(LastRange.end(), Input.end());
    return boost::algorithm::find_first(SearchRange, Search);
}

使用例子如下:

实测结果例中的查找过程,使用  find_next  比使用  find_nth   快5倍,如果母串更长,出现子串次数更多,速度差距还会更大。

实现  find_next  的另一种做法是使用  stl  的算法,但后者的接口与 boost 此处的算法有较大区别。

最后,提供一个  wstring  的例子,如日常多数程序应使用  wstring  以便更好地支持中文:

//注意:请在 IDE 中,把代码所在源文件的编码,设置为 UTF-8
//并且本测试程序,不要和前面的string版本的个测试代码同时使用
void test_wstring_find()
{
    boost::format fmt("%d ~ %d");

    wstring s = L"玛丽玛丽我爱你";//注意L前缀,表示使用unicode

    boost::iterator_range <wstring::iterator> result
            = str_algo::find_first(s, L"我爱");//注意L前缀

    if(result)
    {
        cout << fmt %(result.begin() - s.begin())
                    %(result.end() - s.begin()) << endl;
    }
}

由于mingw环境的限制,不尝试在屏幕上输出宽字符,但同样输出了位置,这回是 4~6。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值