• boost-字符文本处理


    1、lexical_cast

      一些常见的数值,字符互转函数:

    整型int:
    itoa()、_itoa_s
    atoi()、_ttoi

    无符号整型unsigned int:
    _ultoa_s()、_ultot_s
    strtoul()、_tcstoul

    长整型long long:
    _i64toa_s()、_i64tot_s
    _atoi64()、_ttoi64,strtoll(C99/C++11)

    无符号长整型unsigned long long:
    _ui64toa_s()、_ui64tot_s
    _strtoui64()、_tcstoui64,strtoull(C99/C++11)

    浮点型double:
    atof()、_ttof,strtod
    char buf[10] = {0};
    _gcvt_s(buf, 10, 12.345, 5);//最后一个参数为要转换的位数

      boost的lexical_cast提供数字、字符串之间的相互转换,可以用来替代上面的atoi、itoa、strtol等,使用需要包含boostlexical_cast.hpp:

        int x = lexical_cast<int>("100");
        double d = lexical_cast<double>("3.14");
        string str = lexical_cast<string>(100);
        string str2 = lexical_cast<string>(3.14);

      需要注意的是当浮点数float、double转化为字符串的时候会将不精确的数字也转换,如上面的3.14转换成了"3.1400000000000001",而且小数位不会进行四舍五入,比如2.99会转换为"2.9990000000000001",如果需要指定小数位数的转换的话可以使用后面的format,而且format会对指定小数位数的浮点型转换取四舍五入(同sprintf_s()以及使用ostringstream将浮点型转换为指定小数位数的字符串),如后面所示。

      如果输入的是非法值导致lexical_cast无法执行转换操作时会抛出bad_lexical_cast异常,它是std::bad_cast的派生类,我们可以实现一个模板函数来判断用户输入的是否是有效的数值:

    template<typename T>
    bool num_valid(const char* pStr)
    {
        try
        {
            lexical_cast<T>(pStr);
            return true;
        }
        catch (bad_lexical_cast)
        {
            return false;
        }
    }
    
    bool bRet;
    char* pInputStr = "123";
    bRet = num_valid<int>(pInputStr); //输入有效
    pInputStr = "123test";
    bRet = num_valid<int>(pInputStr); //输入无效

      lexcical_cast对于转换对象有三个要求:转换起点对象是可流输出的,即定义了operator<<;转换终点对象是可流输入的,即定义了operator>>;转换终点对象必须是可缺省构造和拷贝构造的。C++中的内建类型int、double等以及std::string都满足前面的可转换条件,而STL中的容器则不可转换,对于用户自定义类型需要满足前面三个条件可以进行转换。

    2、format

      format可以把参数格式化到一个字符串中,而且是类型安全的,使用format需要包含头文件"boostformat.hpp",使用示例:

        string str = "value";
        int num = 100;
    
        cout << boost::format("%s: %d 
    ") % str % num; //format支持流输出,可以直接向输出流cout输出内部保存的字符串,输出value: 100
    
        boost::format fmt("%s: %d, %s: %d 
    ");
        fmt % str % num;
        fmt % str % num; //可以多次输入参数
        string strFmt = fmt.str();
        cout << strFmt; //输出为value: 100, value: 100
    
        fmt.clear();
        fmt % "test" % 99 % "test2" % 100;
        cout << fmt; //输出为test: 99, test2: 100
    
        boost::format fot("%1%: %2%, %1%: %2% 
    "); // %n%用来指定使用的参数
        fot % str % num;
        cout << fot; //输出 value: 100, value: 100
    
        fot.parse("%f 
    ");
        fot % 3.14;
        cout << fot; //输出 3.140000

      format对象的一些成员函数:

      str():返回内部已经格式化好的字符串
      size():相当于str().size()
      clear():清空内部缓存,执行后立即调用str()或size()会抛出异常
      parse():清空内部缓存并使用一个新的格式化字符串,执行后立即调用str()或size()会抛出异常

      参数及其数量必须匹配格式化字符串中要求的参数及数量,否则使用<<输出format对象、调用成员函数str()、size()等会抛出异常,所以使用format的时候最好加上异常处理。

      format基本继承了printf的格式化语法,如:

       %05d:输出宽度为5的整数,不足位用0填充
       %-8.3f:输出左对齐,宽度为8,小数位3位的浮点数
       % 10s:输出宽度为10的字符串,不足位用空格填充
       %5X:输出宽度为5的大写十六进制整数

      format对于指定位数的小数是会进行四舍五入的,如下所示:

        double d = 299.999;
        boost::format fmt("%.3lf");
        fmt % d;
        std::string s = fmt.str(); //"299.999"
    
        boost::format fmt2("%.2lf");
        fmt2 % d;
        s = fmt2.str(); //"300.00"

      format要比printf速度慢几倍,可以先建立const format对象,然后拷贝这个对象进行格式化操作,这样比直接使用format对象能够提高一些速度:

        const format fmt("%d, %d");
        string str = (format(fmt) % 50 % 100).str();

     3、string_algo

    string_algo是一个非常全面的字符串算法库,使用它需要包含头文件"boostalgorithmstring.hpp",算法库的命名规范符合标准库的惯例:前缀i表示是大小写不敏感的,后缀_copy即为不改变原输入的copy版本,后缀_if表示使用一个谓词函数对象,很多算法都有包含这三个版本的函数,使用示例:

    #include "boostalgorithmstring.hpp"
    
    int main()
    {
        string str("readme.txt");
    
        boost::to_upper(str);
        string strUpper = boost::to_lower_copy(str);
    
        bool bRet = boost::starts_with(str, "read");
        bRet = boost::iends_with(strUpper, "txt");
        bRet = boost::contains(str, "me");
        boost::all(str, boost::is_lower()); //判断每个字符是否都是小写
        boost::all(str, boost::is_alpha()); //判断每个字符是否都是字母
        boost::all(str, boost::is_digit()); //判断每个字符是否都是十进制数字
        boost::all(str, boost::is_alnum()); //判断每个字符是否都是字母或数字
        boost::all(str, boost::is_any_of("*+-")); //判断每个字符是否都是*或+或-
    
        boost::trim(str);
        boost::trim_if(str, boost::is_lower() || boost::is_digit());//清除两端小写的字符或数字
        boost::trim_left(str);
    
        str = "readme.txt";
        boost::iterator_range<string::iterator> rge; //boost::iterator_range相当于容器(string)的子区间类型,它有begin()、end()、size()、empty()等成员函数。
        rge = boost::find_first(str, "me"); //查找首次出现的位置
        if (rge/*!rge.empty()*/) //rge可以隐式转换为bool,所以有两种方法判断查找的结果
        {
            int iFoundPos = rge.begin() - str.begin(); //iFoundPos为4
            string strFind(rge.begin(), rge.end()); //strFind为"me"
            string strFull(rge.begin(), str.end()); //strFull为me.txt
            int a = 0;
        }
        boost::find_last(str, "txt"); //查找最后一次出现的位置
        boost::find_nth(str, "dm", 1); //查找"dm第二次出现的位置"
    
        str = "abc, TestD, test";
        vector<string> vs;
        boost::ifind_all(vs, str, "test"); //查找所有出现的位置
        for (auto obj : vs)
        {
            string s = obj;
            cout << s << ","; //输出为Test, test
        }
        vector<boost::iterator_range<string::iterator>> vr;
        boost::ifind_all(vr, str, "test");
        for (auto obj : vr)
        {
            string strSub(obj.begin(), obj.end());
            cout << strSub << ","; //输出为Test, test
    
            string strTemp(obj.begin(), str.end());
            cout << strTemp << ";"; //输出为TestD, test; test
    
            int iFoundPos = obj.begin() - str.begin();
            cout << iFoundPos << ","; //输出为5, 12
        }
        
        replace / erase_all(); //替换/删除所有出现的字符串
        replace / erase_first(); //替换/删除第一次出现的字符串
        replace / erase_last(); //替换/删除所有出现的字符串
        replace / erase_nth(); //替换/删除第n + 1次出现的字符串
        replace / erase_head(); //替换/删除开头的n个字符串
        replace / erase_tail(); //替换/删除结尾的n个字符串
    
        //split()以指定单个字符分割字符串到一个容器中,其参数列表的最后是一个带默认参数,取值可为token_compress_on、token_compress_off
        //token_compress_on表示连续两个分割字符出现时视为一个,token_compress_off为正常操作(会分割出一个空字符串来)。
        str = "c++ java c#";
        list<string> l;
        boost::split(l, str, boost::is_space()); //以空格分割
        auto it = l.begin();
        for (; it != l.end(); ++it)
        {
            string str = *it;
            cout << str << ","; //输出为c++, java, c#
        }

    std::vector<std::string> vc;
    boost::split(vc, str, boost::is_any_of(" ")); //以空格分割
    for (auto& item : vc)
       {
        cout << item << ","; //输出为c++, java, c#,
       }
    struct SIs_space { bool operator()(const char& ch)const { return ch == ' '; } }; list<boost::iterator_range<string::iterator>> lr; boost::split(lr, str, SIs_space()); auto iter = lr.begin(); for (; iter != lr.end(); ++iter) { string strSub(iter->begin(), iter->end()); cout << strSub << ","; //输出为c++, java, c# string strTemp(iter->begin(), str.end()); cout << strTemp << ";"; //输出为c++ java c#; java c#; c# int iFoundPos = iter->begin() - str.begin(); cout << iFoundPos << ","; //输出为0, 4, 9 } //使用分割迭代器来分割字符串,可以以多个字符来分割 str = "Samus || samus || mario |||| Link"; typedef boost::split_iterator<string::iterator> string_split_iterator; string_split_iterator p, endp; for (p = boost::make_split_iterator(str, boost::first_finder("||", boost::is_equal())); p != endp; ++p) { string strSub = string(p->begin(), p->end()); //cout << strSub << ","; //输出为Samus , samus , mario ,, Link string strFull = string(p->begin(), str.end()); cout << strFull << ","; //输出为 Samus || samus || mario |||| Link, samus || mario |||| Link, mario |||| Link, || Link, Link int iPos = p->begin() - str.begin(); cout << iPos << ","; //输出为0, 8, 17, 26, 28 } return 0; }

     4、tokenizer

      使用tokenizer库可以很容易的执行分词操作,但它只支持使用单个字符进行分词,而且它对wstring(unicode)缺乏完善的考虑。通常建议使用string_algo或正则表达式来替换它的工作。

     5、xpressive

      xpressive是一个功能强大的正则表达式库,它比原正则表达式库boost.regex速度更快,而且不用编译。xpressive不仅是一个类似boost.regex的正则表达式解析器,还是一个类似于boost.spirit的语法分析器,并且将这两种不相交的文本处理方式融合在了一起。

      c++11中已经有了正则表达式类regex。

  • 相关阅读:
    list去重
    安装go与nebula-importer遇见的问题
    2.安装docker后运行其他镜像
    2.绝对路径Linux和Windows上的写法
    1.SpringBoot 读取配置文件的值 赋给静态变量
    04747JAVA语言程序设计练习题(第一章)
    Revit文件加载到arcgis pro中调整位置并生成slpk包
    新部署arcgis javascript api 服务器添加的两个mime
    转发博客园中的文章
    【转】使用ArcGIS Pro编辑在线三维服务图层
  • 原文地址:https://www.cnblogs.com/milanleon/p/8710304.html
Copyright © 2020-2023  润新知