Cpp之旅(学习笔记)第10章 字符串和正则表达式

Cpp之旅(学习笔记)第10章 字符串和正则表达式

10.1 引言

  • Cpp标准库提供了 string 类型,使用程序员不必在使用C风格的文本处理方式——通过指针来处理字符数组。
  • Cpp标准库还提供了 string_view 类型,允许程序以容器方式访问字符序列( std::string 或者 char[] )。
  • 还提供了正则表达式匹配功能以查找文本中的模式。

10.2 字符串

string 是用于管理不同字符类型字符序列的 regular 类型。string 类型提供了很多有用的字符串处理操作:

例如:连接操作

string compose(const string& name, const string& domain) {
    return name + '@' + domain;
}
auto addr = compose("dmr", "bell-labs.com");
// 结果:[email protected]

函数 compose 中的字符串“加法”表示连接操作。

标准库 string 定义了一个移动构造函数,因此,即使是以传值方式而不是传引用方式返回一个很长的 string 也会很高效。

连接操作最常见的用法是在一个 string 的末尾追加一些内容。这可以直接通过 += 操作来实现。

void m2(string& s1, string& s2) {
    s1 = s1 + '\n';
    s2 += '\n';
}

除此之外,string 还支持下标操作(使用[])和提取子串操作。

string name = "Niels Stroustrup";
void m3() {
    string s = name.substr(6,10);	// s = "Stroustrup"
    name.replace(0,5,"nicholas");	// name 变成 "nicholas Stroustrup"
    name[0] = toupper(name[0]);		// name 变成 "Nicholas Stroustrup"
}

substr()操作返回 string ,保存其参数指定的子字符串的拷贝。

substr()参数:

  • 第一个参数是指向 string 中某个位置的下标。
  • 第二个参数是指出所需子串的长度。

replace()操作替换子串内容。在本例中,要替换的是从0开始、长度为5的子串,即Niels,它被替换为nicholas。最后将首字母变为大写。

注意:替换的内容和被替换的子串不必一样长。

如果你需要一个C风格的字符串(一个以0结尾的 char 数组),string 提供了对其包含的 C 风格字符串进行只读访问的接口

void print(const string& s) {
    // s.c_str()返回一个指向s所拥有的字符的指针
    printf("For people who like printf: %s\n",s.c_str());
    cout << "For people who like streams: " << s << '\n';
}

根据定义,字符串字面量的类型是 const char *。

要想获得 std::string 类型的字面量可以加上 s 后缀。

要想使用s后缀,需要使用命名空间 `std::literals::string_literals。

例如:

auto cat = "Cat"s;		// std::string类型
auto dog = "Dog";		// 一个C风格字符串:const char* 类型

10.3 字符串视图

字符串视图(string_view)本质上就是一个(指针,长度)对,表明了一个字符串序列。

string_view 类型可以作为一个范围定义,因此可以用它来遍历字符。

void print_lower(string_view sv1)
{
    for(char ch : sv1)
        cout << tolower(ch);
}

string_view 类型的显著限制就在于它是只读的。

例如,如果函数需要将参数内容修改为小写。就不能使用 string_view 来传递字符串。这种情况下,需要考虑使用 span

string_view bad(){
    string s = "Once upon a time";
    return {&s[5],4};				// 糟糕,返回了局部数据的指针
}

10.4 正则表达式

标准库定义了 std::regex 类及其支持的函数,提供对正则表达式的支持。

regex pat {R"(\w{2}\s*\d{5}(-\d{4})?)"};	// 美国邮政编码模式:XXddddd-dddd
											// 以及其他变种

它指定了一个以两个字母开始的模式 \w{2},后面是任意个空白符 \s*,在接下来是五个数字 \d{5},然后是可选的一个破折号和四个数字 -\d{4}。

书中使用了原始字符串字面量,它以 R”( 开始,以 )“ 结束。

原始字符串字面量的好处是可以直接包含反斜线和引号而无需转义,因此非常适合表示正则表达式。

正则表达式常常包含大量反斜线,如果使用常规字符串,模式定义如下:

regex pat {"\\w{2}\\s*\\d{5}(-\\d{4})?"};

中,标准库为正则表达式提供了如下支持:

  • regex_match():将正则表达式与一个(已知长度的)字符串进行匹配。
  • regex_search():在一个(任意长的)数据流中搜索与正则表达式匹配的字符串。
  • regex_replace():在一个(任意长的)数据流中搜索与正则表达式匹配的字符串并将其替换。
  • regex_iterator:遍历匹配结果和子匹配。
  • regex_token_iterator:遍历未匹配部分。

10.5 正则表达式的符号表示

正则表达式的特殊字符 正则表达式的特殊字符
. 任意单个字符(”通配符“) \ 下一个字符有特殊意义
[ 字符集开始 * 零或多次重复(后缀操作符)
] 字符集结束 + 一次或多次重复(后缀操作符)
{ 指定重复次数开始 ? 可选零或一次(后缀操作符)
} 指定重复次数结束 | 二选一(或)
( 分组开始 ^ 行开始;非
( 分组结束 $ 行结束

10.6 建议

  1. 使用 std::string 来保护字符序列;
  2. 优先选择 string 操作而不是C风格的字符串函数;
  3. 使用 string 声明变量和成员,而不要将它作为基类;
  4. 返回 string 应采用传值方式(依赖移动语义和拷贝消除);
  5. 直接或间接使用 substr() 读子字符串,使用 replace() 写子字符串;
  6. string 在需要的时候会自动扩展或收缩;
  7. 当需要范围检测时,应使用 at() 而不是迭代器或 [];
  8. 当需要优化性能时,应使用迭代器或 [] ,而不是 at();
  9. 只有迫不得已时,才使用 c_str() 或 data() 获得 string 的 C 风格字符串表示;
  10. 使用 stringstream 或通过的值提取函数(如 to)将字符串转换为数值;
  11. 可用 basic_string 构造任意类型字符组成的字符串;
  12. 字符串加上 s 后缀用来表示标准库 string;

你可能感兴趣的:(C++之旅,学习,笔记,正则表达式,c++)