C++抽象编程——字符串(2)——<string>库的应用与字符串遍历

Operator overloading

正如你在上篇的图中所看到的一样,string库利用了C++中非常强大的特性,重新定义了一系列的标准运算,我们称为运算符重载(operator overloading)。它根据操作对象的数据类型,重新定义了操作符的行为。 在<string>库中,最重要的是重载的运算符是+号。 当+应用于数字时,它执行加法。 当+时应用于字符串,它执行字符串之间的连接,就是把两个字符串首尾相连接。你还可以使用+ =形式将新文本连接到现有字符串上, +和+ =运算符允许串联或单个的连接字符,比如下面的例子,它设置字符串变量str为字符串“abcd”:

#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "abc";
str += "d";
cout << str << endl;
return 0;
}

结果如图;

学过Java的人可能想+运算符通过其他类型的值将这些值转换为字符串,然后连接他们在一起。 很遗憾,该功能在C ++中不可用,它会把使用具有不兼容操作数的+运算符作为错误返回。C ++还重载关系运算符,以便可以比较字符串值(这比很多语言,比如C和java中更加方便)。例如,你可以检查str的值是否等于“quit”:

if (str == "quit")

关系运算符使用字母顺序来比较字符串,他的顺序由底层ASCII代码定义。 所以,很显然这是区分大小写的,因此“abc”不等于“ABC”。


Selecting characters from a string

在C++中,string的下标是从0开始计数的,比如我们上一篇的博文中的“hello, world”,它每一个元素的下标如图:


每一个字符下面的数字代表字符所在的位置,我们称为下标(index)。C++提供了两种不同的办法去从一个字符串中提取单个字符。其中一种就是在string的后面加一个方括号,里面提供它的下标比如:

str[0]

此时,它将会返回第一个元素“h”。C++还提供了另外一个调用方法,.at 方法,虽然上面的方式我们更好理解,但是在除了字符串的过程中,我们更愿意用.at函数去代替上面的方法,因为.at方法会检查你的下标是否越界。他们的功能都是一样的,操作如下:

str.at(i)

其实我们不仅仅可以选择他们,我们还可以对选择的字符进行赋值操作,比如:

str[0] = 'H'; 或者 str.at(0) = 'H';

这个时候字符串就变为了 “Hello, world”。


String assignment

C ++重新定义字符串的赋值,以便为一个字符串赋值另一个复制字符,就像这样:

str2 = str1;

这个表达式,意思就是把str1的字符赋值给str2,在这期间注意是先把str1 copy下来再进行赋值,复赋值后str1的值不受影响,也就是单纯的复制,除非这个str的参数为引用类型。


Extracting parts of a string

字符串的连接使得一个字符串由短变长,但是我们常常做的操作却是在一个长字符串中进行一些翻转,分离操作。 字符串类出口一个名为substr的方法,它接受两个参数:要选择字符的索引开始位置和截止的位置。 调用str.substr(start,n)通过从str指定的索引位置开始从str中提取n个字符来创建一个新字符串。 例如,如果str包含字符串“hello,world”,则调用方法

str.substr(1, 3);

那么它会返回一个从位置1跟3截取的字符串“ell”,当然我们如果只是输入一个数字,那么它就默认为开始位置,一直截取到最后,例如:

str.substr(7)

那么返回的是“world”。当然我们也可以写一个函数来获取字符串的后半部分:

string secondHalf(string str) {
return str.substr(str.length() / 2);
}


Searching within a string

很多时候,你会发现我们常常要在一个字符串中查找某个特殊的字符或者字符,这是很经常的操作。为了解决这个问题,<string>库出口了一个叫 str.find(pattern)的函数来帮助你。这个函数返回第一个遇到这个字符或者字符串的下标,例如我们上面的例子:


x不在字符串中,所以我们返回系统定义的找不到的error。

Iterating throughthe characters in a string

         虽然<string>库中提供了很多强力的工具来处理字符串,但是通过学习一些简单的代码示例去编程往往使得问题更加简单,这样的编程示例我们称为范式(pattern)。例如我们遍历字符串中的字符我们需要用到下面的代码:

for (int i = 0; i< str.length(); i++) {
. . . body of loop that manipulates str[i] . . .
}

在每个循环周期,选择表达式str [i]指的是字符串中第i个字符,循环的目的是处理每个字符,循环继续,直到i到达字符串的长度。 因此,你可以使用下面的函数来数该字符串中的空格数量,代码如下:

#include <iostream>
#include <string>
using namespace std;
int countSpaces(string str);
int main() {
string str;
getline(cin,str);
cout << "空格数量为:" << countSpaces(str) << endl;
return 0;
}
/*里面的for循环是重点*/ 
int countSpaces(string str) {
int nSpaces = 0;
for (int i = 0; i < str.length(); i++) {
if (str[i] == ' ') nSpaces++;
}
return nSpaces;
}

运行结果如下;

对于某些应用,通常从后面开始遍历会有意想不到的结果。所以我们可以通过下面的范式实现从后面开始遍历,

for (int i = str.length() - 1; i >= 0; i--)
这里 i 从最后一个字符的下标开始往回遍历,一直到下标为0为止。当然我们自己也可以通过思考写出这些代码,但是这会恒消耗你的时间,我们可以适当的记忆一些标准的范式以提高我们的编程效率。当然,我们肯定是可以从前面开始遍历的:

for (int i = 0; i < str.length(); i++)

对于某些程序,你可能要修改不同的循环模式来开始或者结束循环,比如要求写一个函数来检查某个字符串是否以某个特别的前缀开头,代码如下:

bool startsWith(string str, string prefix) {
if (str.length() < prefix.length()) return false;
for (int i = 0; i < prefix.length(); i++) {
if (str[i] != prefix[i]) return false;
}
return true;
}
程序一开始检查两边的长度,以确保str的长度不能小于prefix(前缀)的长度,当你阅读这个程序的时候,很值得你思考的是这两个return语句,一旦发现字符串之间和前缀不同,那么内部循环就会返回false,当遍历完所有的字符后都没有发现有不同的字符,程序的循环外部才会返回true。以后这个基础的范式你会一次又一次的发现。

Growing a string through concatenation

另外一个你要记住的范式就是创建一个含同样字符的字符串,虽然循环的结构体取决于应用程序本身,但是一般的模式斗志这样的:

string str = " ";
for (whatever loop header line fits the application) {
str += the next substring or character;
}

作为一个简单的例子,我们可以写出下面的一个函数:

string repeatChar(int n, char ch) {
string str = "";
for (int i = 0; i < n; i++) {
str += ch;
}
return str;
}
当我们使用输出语句的时候,比如:

cout << repeatChar(72, '-') << endl;
这个时候会输出72个减号;

很多时候,我们将连接范式跟循环范式一起使用,比如我们的字符串翻转函数,就像"desserts",翻转后变为"stressed",代码如下;

string reverse(string str) {
string rev = "";
for (int i = str.length() - 1; i >= 0; i--) {
rev += str[i];
}
return rev;
}
稍后补上完整的代码。实话,这些函数很有用。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值