除了顺序容器共有的操作之外,string类型还提供了一些额外的操作。这些操作中的大部分要么是提供string类和C风格字符数组之间的相互转换,要么是增加了允许我们用下标代替迭代器的版本。
构造string的其他方法
除了前面的介绍的关于string的操作javascript:void(0),下面介绍string的其他方法:
构造string的其他方法 |
n、len2和pos2都是无符号值 string s(cp,n) s是cp指向的数组中的第n个字符的拷贝,此数组至少应该包含n个字符 string s(s2,pos2) s是string s2从下标pos2开始的字符的拷贝。若pos2>s2.size(),构造函数的行为未定义 string s(s2,pos2,len2) s是string s2从下标pos2开始len2个字符的拷贝。若pos2>s2.size(),构造函数的行为未定义。不管len2的值是多少,构造函数至多拷贝s2.size()-pos2个字符 |
这些构造函数接受一个string或一个const char*参数,还接受指定拷贝多少个字符的参数。当我们传递给它们的是一个string时,还可以给定一个下标来指出从哪里开始拷贝:
const char *cp="Hello World!"; //以空字符结束的数组 char noNull[]={'H','i'}; //不是以空字符结束 string s1(cp); //拷贝cp中的字符直到遇到空字符 string s2(noNull,2); //从noNull拷贝两个字符 string s3(noNull); //未定义:noNull不是以空字符结束 string s4(cp+6,5); //从cp[6]开始拷贝5个字符 string s5(s1,6,5); //从s1[6]开始拷贝5个字符 string s6(s1,6); //从s1[6]开始直到s1的末尾 string s7(s1,6,20); //正确,只拷贝到s1的末尾 string s8(s1,16); //抛出一个out_of_range异常
通常当我们从一个const char*创建string时,指针指向的数组必须以空字符结尾,拷贝操作遇到字符时停止。如果我们还传递给构造函数一个计数值,数组就不必以空字符结尾。如果我们未传递计数值且数组也未以空字符结尾,或者给定计数值大于数组大小,则构造函数的行为是未定义的。
当从一个string拷贝字符时,我们可以提供一个可选的开始位置和一个计数值。开始位置必须小于或等于给定的string的大小。如果位置大于size,则构造函数抛出一个out_of_range异常。如果我们传递了一个计数值,则从给定位置开始拷贝这么多个字符。不管我们要求拷贝多少个字符,标准库最多拷贝到string结尾,不会更多。
substr操作
substr操作返回一个string,它是原始string的一部分或全部的拷贝。可以传递给substr一个可选的开始位置和计数值:
string s("hello world");
string s2=s.substr(0,5); //s2=hello
string s3=s.substr(6); //s3=world
string s4=s.substr(6,11); //s4=world
string s5=s.substr(12); //抛出一个out_of_range异常
如果开始位置超过了string的大小,则substr函数抛出一个out_of_range异常。如果开始位置加上计数值大于string的大小,则substr会调整计数值,只拷贝到string的末尾。
子字符串的操作 |
s.substr(pos,n) 返回一个string,包含s中从pos开始的n个字符的拷贝。pos的默认值为0。n的默认值的s.size()-pos,即拷贝从pos开始的所以字符 |
改变string的其他方法
string类型支持顺序容器的赋值运算符以及assign、insert和erase操作。除此之外,它还定义了额外的insert和erase版本。
除了接受迭代器的insert和erase版本外,string还提供了接受下标的版本。下标指出了开始删除的位置,或是insert到给定值之前的位置:
s.insert(s.size(),5,'!'); //在s末尾插入5个感叹号
s.erase(s.size()-5,5); //从s删除最后5个字符
标准库string类型还提供了接受C风格字符数组的insert和assign版本。例如,我们可以将以空字符结尾的字符数组insert到或assign给一个string:
const char *cp="Stately,plump Buck";
s.assign(cp,7); //s="Stately"
s.insert(s.size(),cp+7); //s=="Stately,plump Buck"
此处我们首先通过调用assign替换s的内容。我们赋予s的是从cp指向的地址开始的7个字符。要求赋值的字符数必须小于或等于cp指向的数组中的字符数(不包括结尾的空字符)。
接下来在s上调用insert,我们的意图是将字符插入到s[size()]处(不存在的)元素之前的位置。此例中,我们将cp开始的7个字符(至多到结尾空字符之前)拷贝到s中。
我们也可以指定将来自其它string或字符串的字符插入到当前string中或赋予当前string:
string s="some string",s2="some other string";
s.insert(0,s2); //在s中位置0之前插入s2的拷贝
//在s[0]之前插入s2中开始的s2.size()个字符
s.insert(0,s2,0,s2.size());
append和replace函数
string类定义了两个额外的成员函数:append和replace,这两个函数可以改变string的内容。下表描述了这两个函数的功能。append操作是在string末尾进行插入操作的一种简写放形式:
string s("C++ primer"),s2=s;
s.insert(s.size()," 4th Ed.");
s2.append(" 4th Ed."); //s==s2
replace操作是调用erase和insert的一种简写形式:
//将“4th”替换成“5th”的等价方法
s.erase(11,3);
s.insert(11,"5th");
等价于:
s2.replace(11,3,"5th"); //等价方法:s==s2
此例中调用replace时,插入的文本恰好与删除的文本一样长。这不是必须的,可以插入一个更长或更短的string:
s.replace(11,3,"Fifth");
在此调用中,删除了3个字符,但在其位置插入了5个新字符。
修改string的操作 |
s.insert(pos,args) 在pos之前插入args指定的字符,pos可以是一个下标或者一个迭代器。接受下标的版本返回一个指向s的引用;接受迭代器的版本返回指向第一个插入字符的迭代器 s.erase(pos,len) 删除从位置pos开始的len个字符。如果len被省略,则删除从pos开始直至s末尾的所有字符。返回一个指向s的引用 s.assign(args) 将s中的字符替换为args指定的字符。返回一个指向s的引用 s.append(args) 将args追加到s。返回以指向s的引用 s.replace(range,args) 删除s中范围range内的字符,替换为args指定的字符。range或者是一个下标和一个长度,或者是一对指向s的迭代器,返回一个指向s的引用
args可以是下列形式之一:append和assign可以使用所有形式: str不能与s相同,迭代器b和e不能指向s
str 字符串str str,pos,len str中从pos开始最多len个字符 cp,len 从cp指向的字符数组的前(最多)len个字符 cp cp指向的以空字符串结尾的字符数组 n,c n个字符c b,e 迭代器b和e指定的范围内的字符 初始化列表 花括号包围,以逗号分隔的字符列表
replace和insert所允许的args形式依赖于range和pos是如何指定的 replace replace insert insert args可以是 (pos,len,args) (b,e,args) (pos,args) (iter,args) 是 是 是 否 str 是 否 是 否 str,pos,len 是 是 是 否 cp,len 是 是 否 否 cp 是 是 是 是 n,c 否 是 否 是 b2,e2 否 是 否 是 初始化列表 |
改变string的多种重载函数
上表列出了append、assign、insert和replace函数有多个重载版本。根据我们如何指定要添加的字符和string中被替换的部分,这些函数的参数有不同的版本。幸运的是,这些函数有共同的接口。
assign和append函数无须指定要替换string中哪个部分:assign总是替换string中的所有内容,append总是将新字符追加到string末尾。
replace函数提供了两种指定删除元素范围的方式。可以通过一个位置和一个长度来指定范围,也可以通过一个迭代器范围来指定。insert函数允许我们用两种方式指定插入点:用一个下标或一个迭代器。在两种情况下,新元素都会插入到给定下标(或迭代器)之前的位置。
可以用好几种方式指定要添加到string中的字符。新字符可以来自于另一个string,来自于一个字符指针(指向的字符数组),来自于一个花括号包围的字符列表,或者一个字符和一个计数值。当字符来自于一个string或一个字符指针时,我们可以传递一个额外的参数来控制是拷贝部分还是全部字符。
并不是每个函数都支持所有形式的参数。例如,insert就不支持下标和初始化列表的参数。类似的,如果我们希望用迭代器指定插入点,就不能用字符指针指定新字符的来源。
string搜索操作
string类提供了6个不同的搜索函数,每个函数都有4个重载版本。下表描述了这些搜索成员函数及其参数。每个搜索操作都返回一个string::size_type值,表示匹配发生位置的下标。如果搜索失败,返回一个名为string::npos的static成员。标准库将npos定义为一个const string::size_type类型,并初始化为值-1。由于npos是一个unsigned类型,此初始化值意味着npos等于任何string最大的可能大小。
find函数完成最简单的搜索。它查找参数指定的字符串,若找到,则返回第一个匹配位置的下标,否则返回npos:
string name("AnnaBelle");
auto pos1=name.find("Anna"); //pos1==0
这段程序返回0,即子字符串"Anna"在"AnnaBelle"中第一次出现的下标
搜索(以及其他string操作)是大小写敏感的。当在string中查找子字符串时,要注意大小写。
一个更复杂的问题是查找与给定字符串中任何一个字符匹配的位置。例如,下面代码定位name中的第一个数字:
string numbers("0123456789"),name("r2d2");
//返回1,即,name中第一个数字的下标
auto pos=name.find_first_of(numbers);
如果是要搜索第一个不在参数中的字符,我们应该调用find_first_not_of,例如,为了搜索一个string中第一个非数字字符,可以这样做:
string dept("03714p3");
//返回5,字符'p'的下标
auto pos=dept.find_first_not_of(numbers);
string 搜索操作 |
搜索操作返回指定字符出现的下标,如果未找到则返回npos s.find(args) 查找s中args第一次出现的位置 s.rfind(args) 查找s中args最后一次出现的位置 s.find_first_of(args) 在s中查找args中任何一个字符第一次出现的位置 s.find_last_of(args) 在s中查找args中任何一个字符最后一次出现的位置 s.find_first_not_of(args) 在s中查找第一个不存在args 中的字符 s.find_last_not_of(args) 在s中查找最后一个不在args中的字符
args必须是以下形式之一 c,pos 从s中位置pos开始查找字符c,pos默认为0 s2,pos 从s中位置pos开始查找字符串s2,pos默认为0 cp,pos 从s中位置pos开始查找指针cp指向的空字符结尾的C风格字符串,pos默认为0 cp,pos,n 从s中位置pos开始查找指针cp指向的数组的前n个字符。pos和n无默认值 |
指定从哪里开始搜索
我们可以传递给find操作一个可选的开始位置。这个可选的参数指出从哪个位置开始搜索。默认情况下,此位置被置为0。一种常见的程序设计模式是用这个可选参数在字符串中循环地搜索子字符串出现的所有位置:
string::size_type pos=0; //每步循环查找name中下一个数 while((pos=name.find_first_of(numbers,pos))!=string::npos) { cout<<"found number at index:"<<pos<<" element is "<<name[pos]<<endl; ++pos; //移动到下一个字符 }
while的循环条件将pos重置为从pos开始遇到的第一个数字的下标。只要find_first_of返回以合法的下标,我们就打印当前结果并递增pos。
如果忽略了递增pos,循环就永远也不会停止。
逆向搜索
到目前为止,我们已经用过的find操作都是从左至右搜索。标准库还提供了类似的,但由右至左搜索的操作。rfind成员函数搜索最后一个匹配,即子字符串最靠右的出现位置:
string river("Mississippi");
auto first_pos=river.find("is"); //返回1
auto last_pos=river.find("is"); //返回4
find返回下标1,表示第一个"is"的位置,而rfind返回下标4.表示最后一个"is"的位置。
类似的,find_last函数的功能与find_last函数相似,只是它们返回最后一个而不是第一个匹配:
- find_last_of搜索与给定string中任何一个字符匹配的最后一个字符
- find_last_not_of搜索最后一个不出现在给定string中的字符
每个操作都接受一个可选的第二参数,可用来指出从什么位置开始搜索。
compare函数
除了关系运算符外,标准库string类型还提供了一组compare函数,这些函数与C标准库的strcmp函数很相似。类似strcmp,根据s是等于、大于还是小于参数指定的字符串,s.compare返回0,正数和负数。
如表所示,compare有6个版本,根据我们是要比较两个string还是一个string与一个字符数组,参数各不相同。在这两种情况下,都可以比较整个或一部分字符串。
s.compare的几种参数形式 |
s2 比较s和s2 pos1,n1,s2 将s中从pos1开始的n1个字符与s2进行比较 pos1,,n1,s2,pos2,n2 将s中从pos1开始的n1个字符与s2中从pos2开始的n2个字符进行比较 cp 比较s与cp指向的以空字符结尾的字符数组 pos1,n1,cp 将s中从pos1开始的n1个字符和cp指向的以空字符结尾的字符数组进行比较 pos1,n1,cp,n2 将s中从pos开始的n1个字符与指针cp指向的地址开始的n2个字符进行比较 |
数值转换
字符串中常常包含表示数值的字符。例如,我们用两个字符的string表示数值15——字符'1'后跟字符'5'。一般情况,一个数的字符表示不同于其数值。
新标准引入了多个函数,可以实现数值数据与标准库string之间的转换。
int i=42;
string s=to_string(i); //将整数i转换为字符表示形式
double d=stod(d); //将字符串s转换为浮点数
此例中我们调用to_string将42转换为对应的string形式,然后调用stod将此string转换为浮点值。
要转换为数值的string中第一非空白符必须是数值中可能出现的字符:
string s2="pi=3.14";
//转换s中以数字开始的第一个子串,结果d=3.14
d=stod(s2.substr(s2.find_first_of("+-.0123456789)));
在这个stod调用中,我们调用了find_first_of来获得s中第一个可能是数值的一部分的字符的位置。我们将s中从此位置开始的子串传递给stod。stod函数读取此参数,处理其中的字符,直至遇到不可能是数值的一部分的字符。然后它就将找到这个数值的字符串表示形式转换为对应的双精度浮点值。
string参数中第一个非空白字符必须是符号(+或-)或数字。
string和数值之间的转换 |
to_string(val) 一组重载函数,返回数值val的string表示。val可以是任何算术类型。对每个浮点类型和int或更大的整型,都有相应版本的to_string。 stoi(s,p,b) 返回s的起始子串(表示整数内容)的数值。返回值类型是int、long、unsigned long、long long、unsigned long long。b表示转换所用的基数,默认值是10.p是size_t指针,用来stol(s,p,b) 保存s中第一个非数值字符的下标,p默认是0,即,函数不保存下标 stoul(s,p,b) stoll(s,p,b) stoull(s,p,b)
stof(s,p) 返回s的起始子串(表示浮点数内容)的数值,返回值类型分别是float、double和long double,参数p的作用与整数转换中相同 stod(s,p) stold(s,p) |