c++11 boost - 字符串(2) - string_ref、string_algo

2018-07-11 16:51:44

string_ref 是一种轻量级的字符串,顾名思义,它只支持字符串的引用,没有内存拷贝,可以提高性能。

实现原理是标记字符串其实位置和长度,它只能观测字符串,可以像 std::string 一样使用它,但是无法改变字符串。

string_ref 是弱引用,必须保证被引用的字符串可用,在需要持有或修改是可以调用 to_string() 来生成一份拷贝。

// Copyright (c) 2015
// Author: Chrono Law
#include <cstring>
#include <iostream>
#include <cassert>
using namespace std;

#include <boost/core/ignore_unused.hpp>
#include <boost/utility/string_ref.hpp>
using namespace boost;


void case1()
{
    const char* ch = "Days of Future Past";
    string str(ch);

    string_ref s1(ch);  //字符数组构造,0拷贝
    string_ref s2(str); //标准字符串构造,0拷贝
    assert(s1 == s2 && s1 == ch && s2 == str);

    string_ref s3(ch, 4); //截取前4个字符
    assert(s3 == str.substr(0, 4));

    string_ref s4, s5;
    s4  = ch;
    s5 = str;
    assert(s4 == s5);

    //boost::ignore_unused(s4, s5);

}

void case2()
{
    const char* ch = "Apple iPhone iPad";

    string_ref str(ch);

    assert(!str.empty());
    assert(str.size() == strlen(ch));

    for(auto& x : str)
    {
        cout << x ;
    }
    cout << endl;

    assert(str.front() == 'A');
    assert(str[1] == 'p');
    assert(str.find('i') == 6);

    auto substr = str.substr(6, 6);  //获取子串,仍然是引用
    assert(substr == "iPhone");

    string s = str.to_string();  //在需要的时候转换成标准字符串来使用
    assert(str == s);
    assert(str == ch);

    str.clear();
    assert(str.empty());
}

void case3()
{
    //const char* ch = "Apple iPhone iPad";

    string_ref str("Apple iPhone iPad");

	//只是指针移动,没有修改原来的字符串
    str.remove_prefix(6);
    assert(str.starts_with("iP"));

    str.remove_suffix(5);
    assert(str.ends_with("one"));
}

void case4()
{
    auto trunk = []
    (string_ref str)->string_ref
    {
        return str.substr(0, 5);
    };

    cout << trunk("abcdefg") << endl;
}


int main()
{
    case1();
    case2();
    case3();
    case4();
}
[root@192 c++]# g++ -std=c++11 main.cpp 
[root@192 c++]# ./a.out 
Apple iPhone iPad
abcde


string_algo 库提供了大量的字符串处理操作函数,如比较、裁剪、子串查找等。命名规则如下:

前缀:大小写不敏感。
后缀_copy:不变动输入,返回处理结果的拷贝。
后缀_if:需要一个作为判断式的谓词函数对象,否则使用默认的判断准则。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
using namespace std;

#include <boost/utility/string_ref.hpp>
#include <boost/algorithm/string.hpp>
using namespace boost;

void case1()
{
    string str("readme.txt");

    if (ends_with(str, "txt"))  //判断后缀
    {
        cout << to_upper_copy(str) + " UPPER" << endl;  //大写
        assert(ends_with(str, "txt"));
    }

    replace_first(str, "readme", "followme");  //替换
    cout << str << endl;

    vector<char> v(str.begin(), str.end());
    vector<char> v2 = to_upper_copy(
            erase_first_copy(v, "txt"));
    for (auto ch : v2)
    {   cout << ch; }
}

void case2()
{
    string str("FireEmblem Heroes\n");
    cout << to_upper_copy(str);
    cout << str;
    to_lower(str);
    cout << str;
}

void case3()
{
    string str("Power Bomb");

    assert(iends_with(str, "bomb"));
    assert(!ends_with(str, "bomb"));

    assert(starts_with(str, "Pow"));

    assert(contains(str, "er"));

    string str2 = to_lower_copy(str);
    assert(iequals(str, str2));

    string str3("power suit");
    assert(ilexicographical_compare(str, str3));  //根据字典顺序是否小于

    assert(all(str2.substr(0, 5), is_lower()));  //是否满足指定判断式
}

void case4()
{
    string str1("Samus"), str2("samus");

    assert(!is_equal()(str1, str2));
    assert( is_less()(str1, str2));

	cout << "case4" << endl;
    cout << (to_upper_copy(str1) == to_upper_copy(str2)) << endl;
    cout << is_equal()(str1, str2) << endl;
    assert(!is_equal()(str1, string_ref(str2)));  //使用string_ref
}

#include <boost/format.hpp>

struct is_zero_or_one
{
    bool operator()(char x)
    {   return x == '0' || x == '1';}
};

auto is01 = [](char x)
    {   return x == '0' || x == '1';};

void case5()
{
    format fmt("|%s|\n");

    string str = "  samus aran   ";
    cout << fmt % trim_copy(str);
    cout << fmt % trim_left_copy(str);

    trim_right(str);
    cout << fmt % str;

    string str2 = "2015 Happy new Year!!!";
    cout << fmt % trim_left_copy_if(str2, is_digit());  //裁剪左边数字
    cout << fmt % trim_right_copy_if(str2, is_punct()); //裁剪右边标点符号
    cout << fmt % trim_copy_if(str2,
            is_punct() || is_digit() || is_space());
}

//字符串查找
void case6()
{
    format fmt("|%s|. pos = %d\n");

    string str = "Long long ago, there was a king.";

    iterator_range<string::iterator> rge;

    rge = find_first(str, "long");
    cout << fmt % rge % (rge.begin() - str.begin());

    rge = ifind_first(str, "long");
    cout << fmt % rge % (rge.begin() - str.begin());

    rge = find_nth(str, "ng", 2);
    cout << fmt % rge % (rge.begin() - str.begin());

    rge = find_head(str, 4);
    cout << fmt % rge % (rge.begin() - str.begin());

    rge = find_tail(str, 5);
    cout << fmt % rge % (rge.begin() - str.begin());

    rge = find_first(str, "samus");
    assert(rge.empty() && !rge);
}

//字符串替换
void case7()
{
    string str = "Samus beat the monster.\n";

    cout << replace_first_copy(str, "Samus", "samus");

    replace_last(str, "beat", "kill");
    cout << str;

    replace_tail(str, 9, "ridley.\n");
    cout << str;

    cout << ierase_all_copy(str, "samus");
    cout << replace_nth_copy(str, "l", 1, "L");
    cout << erase_tail_copy(str, 8);
}


void case8()
{
	cout << endl <<endl;
    string str = "Samus,Link.Zelda::Mario-Luigi+zelda";

	//搜索到所有匹配字符串并放入容器
    deque<string> d;
    ifind_all(d, str, "zELDA");
    assert(d.size() == 2);
    for (auto x : d)
    {   cout << "["<< x << "] ";    }
    cout << endl;

    list<iterator_range<string::iterator> > l;
    split(l, str, is_any_of(",.:-+"));
    for (auto x : l)
    {   cout << "["<< x << "]"; }
    cout << endl;

    l.clear();
    split(l, str, is_any_of(".:-"), token_compress_on);  //相邻的::压缩成一个:
    for (auto x : l)
    {   cout << "["<< x << "]"; }
    cout << endl;
    cout << endl;
}


//合并
#include <boost/assign.hpp>
void case9()
{
    using namespace boost::assign;
    vector<string> v = list_of("Samus")("Link")("Zelda")("Mario");
    cout << join(v, "+") << endl;

    //cout << join_if(v, "**", is_contains_a());
    cout << join_if(v, "**",
                    [](string_ref s)
                    { return contains(s, "a"); }
                    );
    cout << endl;
}

//查找分割迭代器
//分割迭代器支持任意长度字符,而split只支持单个字符
void case10()
{
    string str("Samus||samus||mario||||Link");

    //typedef find_iterator<string::iterator> string_find_iterator;

    //string_find_iterator pos, end;
    //for (pos = make_find_iterator(str, first_finder("samus", is_iequal()));
    //        pos != end; ++pos)
    //{   cout << "[" << *pos << "]" ;    }

	//查找
    auto pos = make_find_iterator(str, first_finder("samus", is_iequal()));  //
    decltype(pos) end;  //利用decltype推导类型
    for(; pos != end; ++pos)
    {   cout << "[" << *pos << "]" ;    }

    cout << endl;

	//任意长度字符分割
    typedef split_iterator<string::iterator> string_split_iterator;

    string_split_iterator p, endp;
    for (p = make_split_iterator(str, first_finder("||", is_iequal()));
            p != endp;  ++p)
    {   cout << "[" << *p << "]" ;  }
    cout << endl;
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
    case8();
    case9();
    case10();
}
[root@192 c++]# g++ -std=c++11 main.cpp 
[root@192 c++]# ./a.out 
README.TXT UPPER
followme.txt
FOLLOWME.FIREEMBLEM HEROES
FireEmblem Heroes
fireemblem heroes
case4
1
0
|samus aran|
|samus aran   |
|  samus aran|
| Happy new Year!!!|
|2015 Happy new Year|
|Happy new Year|
|long|. pos = 5
|Long|. pos = 0
|ng|. pos = 29
|Long|. pos = 0
|king.|. pos = 27
samus beat the monster.
Samus kill the monster.
Samus kill the ridley.
 kill the ridley.
Samus kilL the ridley.
Samus kill the 

[Zelda] [zelda] 
[Samus][Link][Zelda][][Mario][Luigi][zelda]
[Samus,Link][Zelda][Mario][Luigi+zelda]

Samus+Link+Zelda+Mario
Samus**Zelda**Mario
[Samus][samus]
[Samus][samus][mario][][Link]


 备注

1.编译器版本gcc4.8.5,运行环境centos7 64位
2.本文只做简单记录用,详细用法请参考 Boost Library,或者是罗剑锋的 boost程序库完全开发指南 书本
3..原文地址http://www.freecls.com/a/2712/a2


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。