format

作用

格式化输出对象,可以不改变流输出状态实现类似于printf()的输出

头文件

#include <boost/format.hpp>
using namespace boost;

简单的例子

//第一种用法
cout << format("%s:%d+%d=%d\n") %"sum" %1 %2 %(1+2);
//第二种用法
format fmt("(%1% + %2%) * %2% = %3%\n");
fmt %2 %5;
fmt %((2+5)*5);
cout << fmt.str();

运行结果:

sum:1+2=3
(2 + 5) * 5 = 35

说明:

  1. 第一种用法使用了和printf类似的语法结构,不必赘述
  2. 第二种用法,先实例化format对象确定输出格式,使用%N%指示参数位置

format对象操作

//返回格式化后的字符串
formatobj.str();
//返回已格式化的字符串长度
formatobj.size();
//清空格式和内容
formatobj.parse();
//只清除格式
formatobj.clear();

格式化规则

  • %05d:输出宽度为5的整数,不足位用0填充
  • %-8.3f:输出左对齐,宽度总为8,小数位为3的浮点数
  • % 10s:输出10位的字符串,不足用空格填充
  • 05X:输出宽度为5的大写16进制整数,不足填充0
  • %|spec|:将格式化选项包含进两个竖线之间,更好的区分格式化选项和普通字符
  • %N%:标记弟N个参数,相当于占位符,不带任何其他的格式化选项
format fmt1("%05d\t%-8.3f\t% 10s\t%05X\n");
cout << fmt1 %62 %2.236 %"123456789" %48;
format fmt2("%|05d|\t%|-8.3f|\t%| 10s|\t%|05X|\n");
cout << fmt2 %62 %2.236 %"123456789" %48;

执行结果:

00062   2.236            123456789      00030
00062 2.236 123456789 00030

lexical_cast

功能

对字符串进行“字面值”的转换,对字符串与整数/浮点数之间进行转换

需要包含的头文件

#inlude <boost/lexical_cast.hpp>
using namespace boost;

声明

//标准形式,转换数字和字符串
template <typename Target,typename Source>
inline Target lexical_cast(const Source &arg); //转换C字符串
template <typename Target>
inline Target lexical_cast(const char * chars,std::size_t count)

使用

在模板参数里指定转换的目标类型即可

//string -> int
int x = lexical_cast<int> ("100"); // string -> float
float pai = lexical_cast<float> ("3.14159e5"); //int -> string
string str = lexical_cast<string> (456); //float -> string
string str = lexical_cast<string> (0.618); //hex -> string
string str = lexical_cast<string> (0x10);

【注意事项】

该模板智能转换字面值,如果出现不合理的转换,例如“hello”转int类型,则会报错(正常人应该不会这么干)

错误处理

当lexical_cast无法执行转换操作时会抛出异常bad_lexical_cast,它是std::bad_cast的派生类

传统保护办法

在使用lexical_cast时应该使用try_catch来保护代码

try
{
cout <<lexical_cast<int>("0x100");
}
catch(bad_lexical_cast& e)
{
cout << "error: \n" << e.what() << endl;
} //运行结果
error:
bad lexical cast:source type value could not be interpreted as target

已有库的保护办法

需要使用命名空间:boost::conversion

函数:

boost::conversion::try_lexical_cast(typeRaw,typeTarget);

返回值为bool表示是否转换成功

【技巧:验证数字字符串的合法性(用于验证用户输入的有效性)】

实现一个模板类

template<typename T>
bool num_valid(const char* str)
{
T tmp;
return conversion::try_lexical_convert(str,tmp) //尝试转换数字
} //用法
assert(num_valid<double>("3.14"));
assert(!num_valid<int>("3.14"));
assert(num_valid<int>("65535"));

转换要求

lexical_cast对转换对象有一定要求

  • 转换的起点对象是可流输出的(可以用“<<”)

    【注意事项】对于重载了“<<”操作符的自定义类型也可以使用它

  • 转换的终点对象是可流输入的(可以用“>>”)

  • 转换的终点对象是可默认构造的、可拷贝构造的

最常用的搭档:int,double,string等POD类型

C++标准转换函数

//字符串转换为数字
int stoi(const string& str,size_t *idx = 0,int base = 10);
long stol(const string& str,size_t *idx = 0,int base = 10);
long long stoll(const string& str,size_t *idx = 0,int base = 10);
float stof(const string& str,size_t *idx = 0);
double stod(const string& str,size_t *idx = 0); //数字转换为string
string to_string(Type val);

【注意事项】必须以空格或数字开头,否则报错

和lexical_cast的比较:

优点:

  • 无需写模板参数
  • 允许出现非数字字符(忽略起始空格,遇到无法转换的字符终止)

缺点:

  • 不支持对自定义类型的转换

string_algo

功能

提供了强大的字符串处理能力,如查找、访问、基本的字符串处理

头文件和命名空间

#include <boost/algorithm/string.hpp>

using namespace boost;

用法

【注意事项】不仅可以用在string上(在这里string被看作是vector<char>),也可以用于部分其他容器,例如(vector<T>

大小写转换

string str("Hello");

//转向大写
cout << to_upper(str) << endl; //这种方式会改变源数据
cout << to_upper_copy(str) << endl; //这种方法返回一个转换后的拷贝对象 //转向小写
cout << to_lower(str) <<endl;
cout << to_lower_copy(str) << endl;

判断式(算法)

  • lexicographical_compare:根据字典顺序检测一个字符串是否小于另一个字符串
  • starts_with:检测字符串是否以另一个字符串为前缀
  • ends_with:检测字符串是否以另一个字符串为后缀
  • contains:检测字符串是否包含另一个字符串
  • equals:检测两个字符串是否相等
  • all:检测字符串是否满足指定的判断式

【注意事项】

  • 除了all以外都有一个i前缀的版本,表示大小写无关
  • 这些函数都不变动字符串

用法示例

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)); //大小写无关判断相等 assert(ilexicographical_compare(str,str3)); //大小写无关字符串比较 assert(all(str2.substr(0,5),is_lower())); //检测字符串均小写

分类

提供一组分类函数,用于检测字符串是否符合某种特性,主要搭配其他算法使用,如上一节的all

  • is_space:字符是否为空格或制表符(tab)
  • is_alnum:字符是否为字母和数字字符
  • is_alpha:字符是否为字母
  • is_cntrl:字符是否为控制字符
  • is_digit:字符是否为十进制数字
  • is_graph:字符是否为图形字符
  • is_lower:字符是否为小写字符
  • is_print:字符是否为可打印字符
  • is_punct:字符是否为标点符号字符
  • is_upper:字符是否为大写字符
  • is_xdigit:字符是否为十六进制数字
  • is_any_of:字符是否是参数字符序列中的任意字符
  • if_from_range:字符是否位于指定区间内,即from<=ch<=to

需要注意的是这些函数并不真正地检测字符,而是返回一个类型为detail::is_classifiedF的函数对象,这个函数对象的operator()才是真正的分类函数(因此,这些函数都属于工厂函数)。

修剪

提供三个算法,删去字符串开头结尾的空格,提供_copy后缀和_if后缀

  • trim_left:删除左边的空格
  • trim_right:删除右边的空格
  • trim:删除两边的空格

用法示例

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 = "2020 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());

执行结果

|samus aran|
|samus aran |
| samus aran|
| Happy new Year!!!|
|2020 Happy new Year|
|Happy new Year|

查找

提供的查找算法如下:

  • find_first:查找字符串在输入中第一次出现的位置
  • find_last:查找字符串在输入中最后一次出现的位置
  • find_nth:查找字符串在输入中的第N次(从0开始计数)出现的位置
  • find_head:取一个字符串开头N个字符的子串,相当于substr(0,n)
  • find_tail:取一个字符串末尾N个字符的子串

【注意事项】

这些算法的返回值是iterator_range,在概念上类似于std::pair,包装了两个迭代器,可以用begin()end()访问。提供了i前缀的用法。

用法示例

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); //取前4个字符
cout << fmt % rge % (rge.begin() - str.begin()); rge = find_tail(str,5); //取末5个字符
cout << fmt % rge % (rge.begin() - str.begin()); rge = find_first(str,"samus"); //找不到
assert(rge.empty() && !rge);

执行结果

|long|.pos = 5
|Long|.pos = 0
|ng|.pos = 30
|Long|.pos = 0
|king.|.pos = 28

替换与删除

替换、删除操作与查找算法非常接近,是在查找到结果后再对字符串进行处理,具体如下:

replace/erase_first:替换/删除字符串在输入中的第一次出现

replace/erase_last:替换/删除字符串在输入中的最后一次出现

replace/erase_nth:替换/删除字符串在输入中的第n次出现

replace/erase_all:替换/删除字符串在输入中的所有出现

replace/erase_head:替换/删除输入的开头

replace/erase_tail:替换/删除输入的末尾

前8个算法每个都有前缀i、后缀_copy的组合,有四个版本,后4个则只有后缀_copy的两个版本

示例代码如下:

// 替换和删除
string str_2 = "Samus beat the monster.\n";
// replace
cout << replace_first_copy(str_2, "Samus", "samus");
replace_last(str_2, "beat", "kill");
cout << str_2;
replace_tail(str_2, 9, "ridley.\n");
cout << str_2;
// delete
cout << ierase_all_copy(str_2, "samus ");
cout << replace_nth_copy(str_2, "l", 1, "L");
cout << erase_tail_copy(str_2, 8);

运行结果:

samus beat the monster.
Samus kill the monster.
Samus kill the ridley.
kill the ridley.
Samus kilL the ridley.
Samus kill the

分割

string_algo提供了两个字符串分割算法:find_all(虽然它的名称含有find,但因为其功能而被归类为分割算法)和split,可以使用某种策略把字符串分割成若干部分,并将分割后的字符串拷贝存入指定的容器。

分割算法对容器类型的要求是必须能够持有查找到结果的拷贝或引用,因此容器的元素类型必须是stringiterator_range<string::iterator>,容器则可以是vector、list、deque等标准容器。

find_all算法类似于普通的查找算法,它搜索所有匹配的字符串,将其加入容器,有一个忽略大小写的前缀i版本。

split算法使用判断式Pred来确定分割的依据,如果字符ch满足判断式Pred(Pred(ch)==true),那么它就是一个分割符,将字符串从这里分割。

还有第三个参数eCompress可以取值为token_compress_ontoken_compress_off,如果值为前者,那么当两个分隔符连续出现时,它们将被视为一个分隔符,如果值为后者则两个连续的分隔符标记了一个空字符串。参数eCompress的默认取值为token_compress_off

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; // 存储range对象
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;

程序运行结果如下:

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

合并

合并算法join是分割算法的逆运算,它把存储在容器中的字符串连接成一个新的字符串,并且可以指定连接的分隔符。

join还有一个后缀_if的版本,它接收一个判断式,只有满足判断式的字符串才能合并。

vector<string> v = list_of("Samus")("Link")("Zelda")("Mario");
cout << join(v, "+") << endl;
cout << join_if(
v, "**",
[](string_ref s)
{
return contains(s, "a");
}
) << endl;

程序首先使用assign库向vector添加了4个字符串,然后用+合并它们。随后的join_if算法使用lambda表达式定义了一个简单的谓词,它包装了算法contains,判断字符串是否包含字符a。

程序运行结果如下:

Samus+Link+Zelda+Mario
Samus**Zelda**Mario

string_ref

功能

一种轻量级的string,持有string类型的引用

头文件

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

类摘要

template<typename charT,typename traits>
class basic_string_ref
{
public:
//和std::string有着几乎一样的接口
private:
const charT* ptr_; //字符串指针
std::size_t len_; //字符串长度
};

不拷贝字符串,所以不分配内存,使用两个成员变量表示字符串

用法

【注意事项】只能像std::string&一样去获取其内容,但不能修改其本身

1、构造

//通过标准字符数组构造普通string,有拷贝成本
const char* ch = "hello";
string str(ch); //字符数组构造,无成本
string_ref s1(ch); //标准字符串构造,无成本
string_ref s2(str);

可以像使用普通string一样使用string_ref(除了修改)

2、用在哪

用于代替string&作为函数参数和返回值,可以完全避免字符串拷贝代价

字符串算法(string_algorithm)的更多相关文章

  1. boost字符串算法

    boost::algorithm简介 2007-12-08 16:59 boost::algorithm提供了很多字符串算法,包括: 大小写转换: 去除无效字符: 谓词: 查找: 删除/替换: 切割: ...

  2. 【字符串算法1】 再谈字符串Hash(优雅的暴力)

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  [字符串算法1] 字符串Hash 老版原文: RK哈希(Rabin_Ka ...

  3. 【字符串算法2】浅谈Manacher算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  字符串算法2:Manacher算法 问题:给出字符串S(限制见后)求出最 ...

  4. 【字符串算法3】浅谈KMP算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  [字符串算法3]KMP算法 Part1 理解KMP的精髓和思想 其实KM ...

  5. ACM -- 算法小结(八)字符串算法之Manacher算法

    字符串算法 -- Manacher算法 首先介绍基础入门知识,以下这部分来着一贴吧,由于是很久之前看的,最近才整理一下,发现没有保存链接,请原创楼主见谅. //首先:大家都知道什么叫回文串吧,这个算法 ...

  6. 字符串算法之 AC自己主动机

    近期一直在学习字符串之类的算法,感觉BF算法,尽管非常easy理解,可是easy超时,全部就想学习其它的一些字符串算法来提高一下,近期学习了一下AC自己主动机.尽管感觉有所收获,可是还是有些朦胧的感觉 ...

  7. <转自原博客> 可爱的字符串算法们

    在非常强又非常关心学弟学妹学习的企鹅学长变态的考纲下,我们无奈中选择一起学习新姿势 first:KMP算法 这是一个小迪更过博客的算法,我就不好意思在这里献丑了,所以献上友链一份:http://rab ...

  8. C# 计算一串字符串算法

    工作中遇到一个小问题,就是要做一个类似excel那种的公式的东西,就是A0+A1*B0那样的公式,然后得出结果. 首先,分析. 这不是计算器,计算器要比这个简易,计算器是所按即所得,即你点击+-之类的 ...

  9. 【字符串算法】AC自动机

    国庆后面两天划水,甚至想接着发出咕咕咕的叫声.咳咳咳,这些都不重要!最近学习了一下AC自动机,发现其实远没有想象中的那么难. AC自动机的来历 我知道,很多人在第一次看到这个东西的时侯是非常兴奋的.( ...

随机推荐

  1. Oracle中left join、right join、full join应用场景

    一.提出问题:三个表分别存不同属性,一条sql查询各个公司的不同的属性 (1) 提供的三个表,相同的维度[company] (2) 需要的结果: 二.问题解析:可通过先查出所有公司再左连接三个表,或者 ...

  2. BeetleX数据分析中间服务V3

    V3版可以对更多的数据场景分析,可以用在系统日志,销售数据,医疗门诊等不同行业的数据进行分析透视.而它的目标并不是简单地进行数据汇总,更注重于不同时间段和不同标签之前的数据的汇总和差异对比,通过数据的 ...

  3. kubernetes addons之node-problem-detector

    node-problem-detector简介 node-problem-detector的作用是收集k8s集群管理中节点问题,并将其报告给apiserver.它是在每个节点上运行的守护程序.node ...

  4. springboot的logback的配置文件

    之前敲出来一个 logback 的配置文件,防止以后找起来麻烦在这里存个档 修改了日志输出的内容 设置默认级别为 INFO 正常日志 ( TRACE 到 WARN ) 输出到单独的文件夹 异常日志 ( ...

  5. 01- web测试快速入门

    web测试与APP测试最非常重要的两个测试种类.web端指的就是在浏览器页面的测试. 你测试的软件通常是两种结构的,B/S架构与C/S架构. B/S架构:Browser/Server 浏览器与服务器模 ...

  6. ZOJ 3781 最短路(想法好题目)

    题意:       给你一个n*m的矩阵,上面只有两种字符,X或者O,每次可以同时改变相同颜色的一个连通块,上下左右连通才算连通,用最小的步数把这个图弄成全是X或者全是O,题意要是没看懂看下面的样例. ...

  7. Windows中的共享文件和文件服务器

    目录 共享文件的设置 默认共享 关闭默认共享 关闭共享服务 共享文件夹权限 文件服务器资源管理器的搭建 文件共享是指主动地在网络上共享自己的计算机文件.一般文件共享使用P2P模式,文件本身存在用户本人 ...

  8. SEO优化技术的简介

    严格来讲,seo技术没有所谓的严格的黑帽与白帽之分.即使是正常的301重定向,在某些情况下也能作用于黑帽seo技术.我们能判定一个人是真正的好人还是坏人么?答案是否定的.之所以解密所谓的黑帽seo,是 ...

  9. 【hugo】- hugo 博客 添加鼠标单击特效

    hugo 博客 监听鼠标点击事件,添加动画效果 js下载 链接:https://pan.baidu.com/s/1SZu76WdEXRxLCfqJ2lbbtQ 密码:r056 移入hugo博客中 打开 ...

  10. (Py练习)日期格式转换

    #将日期转换为易读的格式 #使用dateuti包 from dateutil import parser dt = parser.parse("Mar 6 2019 12:00AM" ...