ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

一枝独秀的字符串:C++也能处理文本?

2022-04-17 01:35:01  阅读:145  来源: 互联网

标签:regex string auto C++ 一枝独秀 字符串 文本 type


string 的接口比较复杂,除了字符串操作,还有 size()、begin()、end()、push_back() 等类似容器的操作,这很容易让人产生“联想”,把它当成是一个“字符容器”。但我不建议你这样做。字符串和容器完全是两个不同的概念。
字符串是“文本”,里面的字符之间是强关系,顺序不能随便调换,否则就失去了意义,通常应该视为一个整体来处理。而容器是“集合”,里面的元素之间没有任何关系,可以随意增删改,对容器更多地是操作里面的单个元素。理解了这一点,把每个字符串都看作是一个不可变的实体,你才能在 C++ 里真正地用好字符串。但有的时候,我们也确实需要存储字符的容器,比如字节序列、数据缓冲区,这该怎么办呢?这个时候,我建议你最好改用vector,它的含义十分“纯粹”,只存储字符,没有 string 那些不必要的成本,用起来也就更灵活一些。接下来我们再看看 string 的一些小技巧。

字面量后缀

C++11 为方便使用字符串,新增了一个字面量的后缀“s”,明确地表示它是 string 字符串类型,而不是 C 字符串,这就可以利用 auto 来自动类型推导,而且在其他用到字符串的地方,也可以省去声明临时字符串变量的麻烦,效率也会更高:

using namespace std::literals::string_literals; //必须打开名字空间
auto str = "std string"s; // 后缀s,表示是标准字符串,直接类型推导

为了避免与用户自定义字面量的冲突,后缀“s”不能直接使用,必须用 using 打开名字空间才行,这是它的一个小缺点。

原始字符串

C++11 还为字面量增加了一个“原始字符串”(Raw string literal)的新表示形式,比原
来的引号多了一个大写字母 R 和一对圆括号,就像下面这样:

auto str = R"(nier:automata)"; // 原始字符串:nier:automata

这种形式初看上去显得有点多余,它有什么好处呢?你一定知道,C++ 的字符有“转义”的用法,在字符前面加上一个“\”,就可以写出“\n”“\t”来表示回车、跳格等不可打印字符。但这个特性也会带来麻烦,有时我们不想转义,只想要字符串的“原始”形式,在 C++ 里写起来就很难受了。特别是在用正则表达式的时候,由于它也有转义,两个转义效果“相乘”,就很容易出错。比如说,我要在正则里表示“$”,需要写成"\$",而在 C++ 里需要对“\”再次转义,就是“\\\$”,你能数出来里面到底有多少个“\”吗?如果使用原始字符串的话,就没有这样的烦恼了,它不会对字符串里的内容做任何转义,完全保持了“原始风貌”,即使里面有再多的特殊字符都不怕:

auto str1 = R"(char""'')"; // 原样输出:char""''
auto str2 = R"(\r\n\t\")"; // 原样输出:\r\n\t\"
auto str3 = R"(\\\$)"; // 原样输出:\\\$
auto str4 = "\\\\\\$"; // 转义后输出:\\\$

不过,想要在原始字符串里面写引号 + 圆括号的形式该怎么办呢?对于这个问题,C++ 也准备了应对的办法,就是在圆括号的两边加上最多 16 个字符的特别“界定符”(delimiter),这样就能够保证不与字符串内容发生冲突:

auto str5 = R"==(R"(xxx)")==";// 原样输出:R"(xxx)"

字符串转换函数

在处理字符串的时候,我们还会经常遇到与数字互相转换的事情,以前只能用 C 函数atoi()、atol(),它们的参数是 C 字符串而不是 string,用起来就比较麻烦,于是,C++11就增加了几个新的转换函数:
stoi()、stol()、stoll() 等把字符串转换成整数;
stof()、stod() 等把字符串转换成浮点数;
to_string() 把整数、浮点数转换成字符串。
这几个小函数在处理用户数据、输入输出的时候,非常方便:

assert(stoi("42") == 42); // 字符串转整数
assert(stol("253") == 253L); // 字符串转长整数
assert(stod("2.0") == 2.0); // 字符串转浮点数
assert(to_string(1984) == "1984"); // 整数转字符串

字符串视图类

再来说一下 string 的成本问题。它确实有点“重”,大字符串的拷贝、修改代价很高,所以我们通常都尽量用 const string&,但有的时候还是无法避免(比如使用 C 字符串、获取子串)。如果你对此很在意,就有必要找一个“轻量级”的替代品。
在 C++17 里,就有这么一个完美满足所有需求的东西,叫 string_view。顾名思义,它是一个字符串的视图,成本很低,内部只保存一个指针和长度,无论是拷贝,还是修改,都非常廉价。唯一的遗憾是,它只出现在 C++17 里,不过你也可以参考它的接口,自己在 C++11 里实现一个简化版本。下面我给你一个简单的示范,你可以自己扩展:

class my_string_view final // 简单的字符串视图类,示范实现
{
public:
using this_type = my_string_view; // 各种内部类型定义
using string_type = std::string;
using string_ref_type = const std::string&;
using char_ptr_type = const char*;
using size_type = size_t;
private:
char_ptr_type ptr = nullptr; // 字符串指针
size_type len = 0; // 字符串长度
public:
my_string_view() = default;
~my_string_view() = default;
my_string_view(string_ref_type str) noexcept
: ptr(str.data()), len(str.length())
{}
public:
char_ptr_type data() const // 常函数,返回字符串指针
{
return ptr;
}
size_type size() const // 常函数,返回字符串长度
{
return len;
}
};

正则表达式

说了大半天,其实我们还是没有回答这节课开头提出的疑问,也就是“在 C++ 里该怎么处理文本”。string 只是解决了文本的表示和存储问题,要对它做大小写转换、判断前缀后缀、模式匹配查找等更复杂的处理,要如何做呢?
C++11 在标准库里加入了正则表达式库 regex,利用它的强大能力,你就能够任意操作文本、字符串。
C++ 正则表达式主要有两个类。
regex:表示一个正则表达式,是 basic_regex 的特化形式;
smatch:表示正则表达式的匹配结果,是 match_results 的特化形式。
C++ 正则匹配有三个算法,注意它们都是“只读”的,不会变动原字符串。
regex_match():完全匹配一个字符串;
regex_search():在字符串里查找一个正则匹配;
regex_replace():正则查找再做替换。
所以,你只要用 regex 定义好一个表达式,然后再调用匹配算法,就可以立刻得到结果,用起来和其他语言差不多。不过,在写正则的时候,记得最好要用“原始字符串”,不然转义符绝对会把你折腾得够呛。
下面我举个例子:

标签:regex,string,auto,C++,一枝独秀,字符串,文本,type
来源: https://www.cnblogs.com/ailen-ailen/p/16154846.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有