当前位置:文档之家› string

string

string
string

排列方式:

日志

日志摘要

日期2010年 8月

2010年 7月

2010年 6月

2010年 5月

2010年 4月

2010年 3月

2010年 2月

2010年 1月

2009年 12月

2009年 11月

2009年 10月

2009年 9月

2009年 8月

2009年 7月

2009年 6月

2009年 5月

2009年 4月

2009年 3月

2009年 2月

2009年 1月

2008年 12月

2008年 11月

2008年 10月

2008年 9月 < 上一页 下一页 >2006/12/31 详细解说STL string (Linux 发表于 2005-10-9 14:30:49) 前言: string 的角色 1 string 使用 1.1 充分使用string 操作符 1.2 眼花缭乱的string find 函数 1.3 string insert, replace, erase 2 string 和 C 风格字符串 3 string 和 Charactor Traits 4 string 建议 5 小结 6 附录前言: string 的角色 C++ 语言是个十分优秀的语言,但优秀并不表示完美。还是有许多人不愿意使用C 或者C++,为什么?原因众多,其中之一就是C/C++的文本处理功能太麻烦,用起来很不方便。以前没有接触过其他语言时,每当别人这么说,我总是不屑一顾,认为他们根本就没有领会C++的精华,或者不太懂C++,现在我接触 perl, php, 和Shell 脚本以后,开始理解了以前为什么有人说C++文本处理不方便了。 举例来说,如果文本格式是:用户名 电话号码,文件名name.txt Tom 23245332 Jenny 22231231 Heny 22183942 Tom 23245332 ... 现在我们需要对用户名排序,且只输出不同的姓名。 那么在shell 编程中,可以这样用: awk '{print $1}' name.txt | sort | uniq 简单吧? 如果使用C/C++ 就麻烦了,他需要做以下工作: 先打开文件,检测文件是否打开,如果失败,则退出。 声明一个足够大得二维字符数组或者一个字符指针数组 读入一行到字符空间 然后分析一行的结构,找到空格,存入字符数组中。 关闭文件 写一个排序函数,或者使用写一个比较函数,使用qsort 排序 遍历数组,比较是否有相同的,如果有,则要删除,copy... 输出信息 你可以用C++或者C 语言去实现这个流程。如果一个人的主要工作就是处理这种类似的文本(例如做apache 的日志统计和分析),你说他会喜欢C/C++么? 当然,有了STL ,这些处理会得到很大的简化。我们可以使用 fstream 来代替麻烦的fopen fread fclose, 用vector 来代替数组。最重要的是用 string 来代替char * 数组,使用sort 排序算法来排序,用unique 函数来去重。听起来好像很不错 。看看下面代码(例程1): #i nclude #i nclude #i nclude #i nclude #i nclude using namespace std; int main(){

ifstream in("name.txt");

string strtmp;

个人资料 我这大学生活 照片 日志 列表 更多

工具 帮助登录

Windows Live ?Hotmail Messenger Office 照片MSN

2008年 8月2008年 7月2008年 6月2008年 5月2008年 4月2008年 3月2008年 2月2008年 1月2007年 12月2007年 11月2007年 10月2007年 9月2007年 8月2007年 7月2007年 6月2007年 5月2007年 4月2007年 3月2007年 2月2007年 1月2006年 12月2006年 11月2006年 10月2006年 9月2006年 8月2006年 7月2006年 6月2006年 5月2006年 4月2006年 3月2006年 2月 vector vect;

while(getline(in, strtmp, '\n'))

vect.push_back(strtmp.substr(0, strtmp.find(' ')));

sort(vect.begin(), vect.end());

vector::iterator it=unique(vect.begin(), vect.end());

copy(vect.begin(), it, ostream_iterator(cout, "\n"));

return 0;

}

也还不错吧,至少会比想象得要简单得多!(代码里面没有对错误进行处理,只是为了说明问题,不要效仿).

当然,在这个文本格式中,不用vector而使用map会更有扩充性,例如,还可通过人名找电话号码等等,但是使用了map就不那么好用sort了。你可以用map试一试。

这里string的作用不只是可以存储字符串,还可以提供字符串的比较,查找等。在sort和unique函数中就默认使用了less 和equal_to函数, 上面的一段代码,其实使用了string的以下功能:

存储功能,在getline() 函数中

查找功能,在find() 函数中

子串功能,在substr() 函数中

string operator < , 默认在sort() 函数中调用

string operator == , 默认在unique() 函数中调用

总之,有了string 后,C++的字符文本处理功能总算得到了一定补充,加上配合STL其他容器使用,其在文本处理上的功能已经与perl, shell, php的距离缩小很多了。 因此掌握string 会让你的工作事半功倍。

1 string 使用

其实,string并不是一个单独的容器,只是basic_string 模板类的一个typedef 而已,相对应的还有wstring, 你在string 头文件中你会发现下面的代码:

extern "C++" {

typedef basic_string string;

typedef basic_string wstring;

} // extern "C++"

由于只是解释string的用法,如果没有特殊的说明,本文并不区分string 和 basic_string的区别。

string 其实相当于一个保存字符的序列容器,因此除了有字符串的一些常用操作以外,还有包含了所有的序列容器的操作。字符串的常用操作包括:增加、删除、修改、查找比较、链接、输入、输出等。详细函数列表参看附录。不要害怕这么多函数,其实有许多是序列容器带有的,平时不一定用的上。

如果你要想了解所有函数的详细用法,你需要查看basic_string,或者下载STL编程手册。这里通过实例介绍一些常用函数。

1.1 充分使用string 操作符

string 重载了许多操作符,包括 +, +=, <, =, , [], <<, >>等,正式这些操作符,对字符串操作非常方便。先看看下面这个例子:tt.cpp(例程2)

#i nclude

#i nclude

using namespace std;

int main(){

string strinfo="Please input your name:";

cout << strinfo ;

cin >> strinfo;

if( strinfo == "winter" )

cout << "you are winter!"<

else if( strinfo != "wende" )

2006年 1月2005年 12月2005年 11月 cout << "you are not wende!"<

else if( strinfo < "winter")

cout << "your name should be ahead of winter"<

else

cout << "your name should be after of winter"<

strinfo += " , Welcome to China!";

cout << strinfo<

cout <<"Your name is :"<

string strtmp = "How are you? " + strinfo;

for(int i = 0 ; i < strtmp.size(); i ++)

cout<

return 0;

}

下面是程序的输出

-bash-2.05b$ make tt

c++ -O -pipe -march=pentiumpro tt.cpp -o tt

-bash-2.05b$ ./tt

Please input your name:Hero

you are not wende!

Hero , Welcome to China!

How are you? Hero , Welcome to China!

有了这些操作符,在STL中仿函数都可以直接使用string作为参数,例如 less, great, equal_to 等,因此在把string作为参数传递的时候,它的使用和int 或者float等已经没有什么区别了。例如,你可以使用:

map mymap;

//以上默认使用了 less

有了 operator + 以后,你可以直接连加,例如:

string strinfo="Winter";

string strlast="Hello " + strinfo + "!";

//你还可以这样:

string strtest="Hello " + strinfo + " Welcome" + " to China" + " !";

看见其中的特点了吗?只要你的等式里面有一个 string 对象,你就可以一直连续"+",但有一点需要保证的是,在开始的两项中,必须有一项是 string 对象。其原理很简单:

系统遇到"+"号,发现有一项是string 对象。

系统把另一项转化为一个临时 string 对象。

执行 operator + 操作,返回新的临时string 对象。

如果又发现"+"号,继续第一步操作。

由于这个等式是由左到右开始检测执行,如果开始两项都是const char* ,程序自己并没有定义两个const char* 的加法,编译的时候肯定就有问题了。

有了操作符以后,assign(), append(), compare(), at()等函数,除非有一些特殊的需求时,一般是用不上。当然at()函数还有一个功能,那就是检查下标是否合法,如果是使用:

string str="winter";

//下面一行有可能会引起程序中断错误

str[100]='!';

//下面会抛出异常:throws: out_of_range

cout<

了解了吗?如果你希望效率高,还是使用[]来访问,如果你希望稳定性好,最好使用at()来访问。

1.2 眼花缭乱的string find 函数

由于查找是使用最为频繁的功能之一,string 提供了非常丰富的查找函数。其列表如下:

函数名 描述 find 查找 rfind 反向查找 find_first_of 查找包含子串中的任何字符,返回第一个位置 find_first_not_of 查找不包含子串中的任何字符,返回第一个位置 find_last_of 查找包含子串中的任何字符,返回最后一个位置 find_last_not_of 查找不包含子串中的任何字符,返回最后一个位置 以上函数都是被重载了4次,以下是以find_first_of 函数为例说明他们的参数,其他函数和其参数一样,也就是说总共有24个函数 :

size_type find_first_of(const basic_string& s, size_type pos = 0)

size_type find_first_of(const charT* s, size_type pos, size_type n)

size_type find_first_of(const charT* s, size_type pos = 0)

size_type find_first_of(charT c, size_type pos = 0)

所有的查找函数都返回一个size_type类型,这个返回值一般都是所找到字符串的位置,如果没有找到,则返回string::npos。有一点需要特别注意,所有和string::npos的比较一定要用string::size_type来使用,不要直接使用int 或者unsigned int等类型。其实string::npos表示的是-1, 看看头文件:

template

const basic_string<_CharT,_Traits,_Alloc>::size_type

basic_string<_CharT,_Traits,_Alloc>::npos

= basic_string<_CharT,_Traits,_Alloc>::size_type) -1;

find 和 rfind 都还比较容易理解,一个是正向匹配,一个是逆向匹配,后面的参数pos都是用来指定起始查找位置。对于find_first_of 和find_last_of 就不是那么好理解。

find_first_of 是给定一个要查找的字符集,找到这个字符集中任何一个字符所在字符串中第一个位置。或许看一个例子更容易明白。

有这样一个需求:过滤一行开头和结尾的所有非英文字符。看看用string 如何实现:

#i nclude

#i nclude

using namespace std;

int main(){

string strinfo=" //*---Hello Word!......------";

string strset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

int first = strinfo.find_first_of(strset);

if(first == string::npos) {

cout<<"not find any characters"<

return -1;

}

int last = strinfo.find_last_of(strset);

if(last == string::npos) {

cout<<"not find any characters"<

return -1;

}

cout << strinfo.substr(first, last - first + 1)<

return 0;

}

这里把所有的英文字母大小写作为了需要查找的字符集,先查找第一个英文字母的位置,然后查找最后一个英文字母的位置,然后用substr 来的到中间的一部分,用于输出结果。下面就是其结果:

Hello Word

前面的符号和后面的符号都没有了。像这种用法可以用来查找分隔符,从而把一个连续的字符串分割成为几部分,达到 shell 命令中的 awk 的用法。特别是当分隔符有多个的时候,可以一次指定。例如有这样的需求:

张三|3456123, 湖南

李四,4564234| 湖北

王小二, 4433253|北京

...

我们需要以 "|" ","为分隔符,同时又要过滤空格,把每行分成相应的字段。可以作为你的一个家庭作业来试试,要求代码简洁。

1.3 string insert, replace, erase

了解了string 的操作符,查找函数和substr,其实就已经了解了string的80%的操作了。insert函数, replace函数和erase函数在使用起来相对简单。下面以一个例子来说明其应用。

string只是提供了按照位置和区间的replace函数,而不能用一个string字串来替换指定string中的另一个字串。这里写一个函数来实现这个功能:

void string_replace(string & strBig, const string & strsrc, const string &strdst) {

string::size_type pos=0;

string::size_type srclen=strsrc.size();

string::size_type dstlen=strdst.size();

while( (pos=strBig.find(strsrc, pos)) != string::npos){

strBig.replace(pos, srclen, strdst);

pos += dstlen;

}

}看看如何调用:

#i nclude

#i nclude

using namespace std;

int main() {

string strinfo="This is Winter, Winter is a programmer. Do you know Winter?";

cout<<"Orign string is :\n"<

string_replace(strinfo, "Winter", "wende");

cout<<"After replace Winter with wende, the string is :\n"<

return 0;

}其输出结果:

Orign string is :

This is Winter, Winter is a programmer. Do you know Winter?

After replace Winter with wende, the string is :

This is wende, wende is a programmer. Do you know wende?如果不用replace函数,则可以使用erase和insert来替换,也能实现

string_replace函数的功能:

void string_replace(string & strBig, const string & strsrc, const string &strdst) {

string::size_type pos=0;

string::size_type srclen=strsrc.size();

string::size_type dstlen=strdst.size();

while( (pos=strBig.find(strsrc, pos)) != string::npos){

strBig.erase(pos, srclen);

strBig.insert(pos, strdst);

pos += dstlen;

}

}当然,这种方法没有使用replace来得直接。

2 string 和 C风格字符串

现在看了这么多例子,发现const char* 可以和string 直接转换,例如我们在上面的例子中,使用

string_replace(strinfo, "Winter", "wende");来代用

void string_replace(string & strBig, const string & strsrc, const string &strdst) 在C语言中只有char* 和 const char*,为了使用起来方便,string提供了三个函数满足其要求:

const charT* c_str() const

const charT* data() const

size_type copy(charT* buf, size_type n, size_type pos = 0) const 其中:

c_str 直接返回一个以\0结尾的字符串。

data 直接以数组方式返回string的内容,其大小为size()的返回值,结尾并没有\0字符。

copy 把string的内容拷贝到buf空间中。

你或许会问,c_str()的功能包含data(),那还需要data()函数干什么?看看源码:

const charT* c_str () const

{ if (length () == 0) return ""; terminate (); return data (); }原来c_str()的流程是:先调用terminate(),然后在返回data()。因此如果你对效率要求比较高,而且你的处理又不一定需要以\0的方式结束,你最好选择data()。但是对于一般的C函数中,需要以const char*为输入参数,你就要使用c_str()函数。

对于 c_str() data()函数,返回的数组都是由string本身拥有,千万不可修改其内容。其原因是许多string实现的时候采用了引用机制,也就是说,有可能几个string使用同一个字符存储空间。而且你不能使用sizeof(string)来查看其大小。详细的解释和实现查看Effective STL的条款15:小心string实现的多样性。

另外在你的程序中,只在需要时才使用c_str()或者data()得到字符串,每调用一次,下次再使用就会失效,如:

string strinfo("this is Winter");

...

//最好的方式是:

foo(strinfo.c_str());

//也可以这么用:

const char* pstr=strinfo.c_str();

foo(pstr);

//不要再使用了pstr了, 下面的操作已经使pstr无效了。

strinfo += " Hello!";

foo(pstr);//错误!会遇到什么错误?当你幸运的时候pstr可能只是指向"this is Winter Hello!"的字符串,如果不幸运,就会导致程序出现其他问题,总会有一些不可遇见的错误。总之不会是你预期的那个结果。

3 string 和 Charactor Traits

了解了string的用法,该详细看看string的真相了。前面提到string 只是basic_string的一个typedef。看看basic_string 的参数:

template ,

class Allocator = allocator >

class basic_string

{

//...

}char_traits不仅是在basic_string 中有用,在basic_istream 和 basic_ostream中也需要用到。

就像Steve Donovan在过度使用C++模板中提到的,这些确实有些过头了,要不是系统自己定义了相关的一些属性,而且用了个typedef,否则还真不知道如何使用。

但复杂总有复杂道理。有了char_traits,你可以定义自己的字符串类型。当然,有了char_traits < char > 和char_traits < wchar_t > 你的需求使用已经足够了,为了更好的理解string ,咱们来看看char_traits都有哪些要求。

如果你希望使用你自己定义的字符,你必须定义包含下列成员的结构: 表达式描述

char_type 字符类型

int_type int 类型

pos_type 位置类型

off_type 表示位置之间距离的类型

state_type 表示状态的类型

assign(c1,c2) 把字符c2赋值给c1

eq(c1,c2) 判断c1,c2 是否相等

lt(c1,c2) 判断c1是否小于c2

length(str) 判断str的长度

compare(s1,s2,n) 比较s1和s2的前n个字符

copy(s1,s2, n) 把s2的前n个字符拷贝到s1中

move(s1,s2, n) 把s2中的前n个字符移动到s1中

assign(s,n,c) 把s中的前n个字符赋值为c

find(s,n,c) 在s的前n个字符内查找c

eof() 返回end-of-file

to_int_type(c) 将c转换成int_type

to_char_type(i) 将i转换成char_type

not_eof(i) 判断i是否为EOF

eq_int_type(i1,i2) 判断i1和i2是否相等

想看看实际的例子,你可以看看sgi STL的char_traits结构源码.

现在默认的string版本中,并不支持忽略大小写的比较函数和查找函数,如果你想练练手,你可以试试改写一个char_traits , 然后生成一个case_string 类, 也可以在string 上做继承,然后派生一个新的类,例如:ext_string,提供一些常用的功能,例如:

定义分隔符。给定分隔符,把string分为几个字段。

提供替换功能。例如,用winter, 替换字符串中的wende

大小写处理。例如,忽略大小写比较,转换等

整形转换。例如把"123"字符串转换为123数字。

这些都是常用的功能,如果你有兴趣可以试试。其实有人已经实现了,看看Extended STL string。如果你想偷懒,下载一个头文件就可以用,有了它确实方便了很多。要是有人能提供一个支持正则表达式的string,我会非常乐意用。

4 string 建议

使用string 的方便性就不用再说了,这里要重点强调的是string的安全性。

string并不是万能的,如果你在一个大工程中需要频繁处理字符串,而且有可能是多线程,那么你一定要慎重(当然,在多线程下你使用任何STL容器都要慎重)。

string的实现和效率并不一定是你想象的那样,如果你对大量的字符串操作,而且特别关心其效率,那么你有两个选择,首先,你可以看看你使用的STL 版本中string实现的源码;另一选择是你自己写一个只提供你需要的功能的类。

string的c_str()函数是用来得到C语言风格的字符串,其返回的指针不能修改其空间。而且在下一次使用时重新调用获得新的指针。

string的data()函数返回的字符串指针不会以'\0'结束,千万不可忽视。

尽量去使用操作符,这样可以让程序更加易懂(特别是那些脚本程序员也可以看懂)

5 小结

难怪有人说:

string 使用方便功能强,我们一直用它!

6 附录

string 函数列表 函数名描述

begin 得到指向字符串开头的Iterator

end 得到指向字符串结尾的Iterator

rbegin 得到指向反向字符串开头的Iterator

rend 得到指向反向字符串结尾的Iterator

size 得到字符串的大小

length 和size函数功能相同

max_size 字符串可能的最大大小

capacity 在不重新分配内存的情况下,字符串可能的大小

empty 判断是否为空

operator[] 取第几个元素,相当于数组

c_str 取得C风格的const char* 字符串

data 取得字符串内容地址

operator= 赋值操作符

reserve 预留空间

swap 交换函数

insert 插入字符

append 追加字符

push_back 追加字符

operator+= += 操作符

erase 删除字符串

clear 清空字符容器中所有内容

resize 重新分配空间

assign 和赋值操作符一样

replace 替代

copy 字符串到空间

find 查找

rfind 反向查找

find_first_of 查找包含子串中的任何字符,返回第一个位置

find_first_not_of 查找不包含子串中的任何字符,返回第一个位置

find_last_of 查找包含子串中的任何字符,返回最后一个位置

find_last_not_of 查找不包含子串中的任何字符,返回最后一个位置

substr 得到字串

compare 比较字符串

operator+ 字符串链接

operator== 判断是否相等

operator!= 判断是否不等于

operator< 判断是否小于

operator>> 从输入流中读入字符串

operator<< 字符串写入输出流

getline 从输入流中读入一行

12:38 | 添加评论 | 固定链接 | 引用通告 (0) | 记录它 | c++的点滴

有效使用STL迭代器的三条基本原则

有效使用STL迭代器的三条基本原则

STL 迭代器的概念看上去似乎已经足够直观了,然而,你会很快发现容器类(Container)实际上提供了四种不同的迭代器类型:iterator、

const_iterator、reverse_iterator和const_reverse_iterator。进而,你会注意到容器类的 insert和erase方法仅接受这四种类型中的一种作为参数。问题来了:为什么需要四种不同的迭代器呢?它们之间存在何种联系?它们是否可以相互转换?是否可以在STL算法(Algorithm)和其他工具函数中混合使用不同类型的迭代器? 这些迭代器与相应的容器类及其方法之间又是什么关系?

这篇从新近出版的《Effective STL》中摘录的文章将会通过迭代器使用的三条基本原则来回答上述问题,它们能够帮助你更为有效的使用STL迭代器。 原则一:尽量使用iterator取代const_iterator、reverse_iterator和const_reverse_iterator

STL 中的所有标准容器类都提供四种不同的迭代器类型。对于容器类container而言,iterator的功用相当于T*,而 const_iterator则相当于const T*(可能你也见到过T const *这样的写法,它们具有相同的语义[2])。累加一个iterator或者const_iterator可以由首至尾的遍历一个容器内的所有元素。 reverse_iterator与const_reverse_iterator同样分别对应于T*和const T*,所不同的是,累加reverse_iterator或者const_reverse_iterator 所产生的是由容器的尾端开始的反向遍历。

让我们先来看一下vector容器insert和erase方法的样式:

iterator insert(iterator position, const T& x);

iterator erase(iterator position);

iterator erase(iterator rangeBegin, iterator rangeEnd);

不同容器的insert和erase方法虽然可能具有截然不同的返回类型,但它们的参数形式却大都与此类似。需要注意的是:这些方法仅接受iterator 类型的参数,而不是const_iterator、reverse_iterator或者const_reverse_iterator。虽然容器类支持四种不同的迭代器类型,但其中iterator似乎有更为广泛的应用[3]。

下图清晰的表明了不同类型的迭代器之间的转换关系:

如图所示,你可以隐式的将iterator转换成const_iterator或者reverse_iterator,也可以隐式的将 reverse_iterator转换成

const_reverse_iterator。并且,reverse_iterator可以通过调用其base ()成员函数转换为iterator。const_reverse_iterator也可以类似的通过base ()转换成为 const_iterator。然而,一个图中无法显示的事实是:通过base()得到的也许并非你所期待的iterator,我们将会在原则三中详细讨论这一点。

很显然,我们没有办法从一个const_iterator转换得到一个iterator,也无法从 const_reverse_iterator得到reverse_iterator。这一点非常重要,因为这意味着当你仅仅得到一个 const_iterator或者const_reverse_iterator,你会在调用容器类的一些成员函数时遇到麻烦。这些成员函数要求 iterator作为参数,而你无法从const类型的迭代器中直接得到iterator。当需要指出插入或者删除的位置时,const类型的迭代器总是显得那么力不从心。

千万不要傻乎乎的宣称const类型的迭代器一无是处,它们仍然可以在特定的场合使用。比如,const类型的迭代器可以与STL算法默契配合——因为STL 算法通常只关心迭代器属于何种概念范畴(Category),而对其类型(Type)没有限制。很多容器类的成员方法也接受const类型的迭代器,只有insert和erase显得有些吹毛求疵。

即便是在需要插入或删除操作的时候,面对const类型的迭代器你也并非走投无路。一般情况下仍然有办法通过const类型的迭代器取得一个iterator,但这种方法并不总是行得通。而且就算可行,它也显得复杂而缺乏效率。原则二中将会提及这种转换的方法。

现在,我们已经有足够的理由相信应该尽量使用iterator取代const或者reverse类型的迭代器:

·大多数insert和erase方法要求使用iterator。如果你需要调用这些方法,你就必须使用iterator。

·没有一条简单有效的途径可以将const_iterator转换成iterator,我们将会在原则二中讨论的技术并不普遍适用,而且效率不彰。

·从reverse_iterator转换而来的iterator在使用之前可能需要相应的调整,在原则三种我们会讨论何时需要调整以及调整的原因。

由此可见,尽量使用iterator而不是const或reverse类型的迭代器,可以使得容器的使用更为简单而有效,并且可以避免潜在的问题。

在实践中,你可能会更多的面临iterator与const_iterator之间的选择,因为iterator与reverse_iterator之间的选择结果显而易见——依赖于顺序或者逆序的的遍历。而且,即使你选择了reverse_iterator,当需要iterator的时候,你仍然可以通过 base()方法得到相应的iterator(可能需要一些调整,我们会在条款三中讨论)。

而在iterator和 const_iterator之间举棋不定的时候,你有更充分的理由选择iterator,即使const_iterator同样可行,即使你并不需要调用容器类的任何成员函数。其中的缘由包括iterator与const_iterator之间的比较,如下代码所示:

typedef deque IntDeque; //typedef可以极大的简化

typedef IntDeque::iteratorIter; //STL容器类和iterator

typedef IntDeque::const_iteratorConstIter;//的操作。

Iter i;

ConstIter ci;

... //使ci和i指向同一容器。

if (i == ci) ... //比较iterator和const_iterator

我们所做的只是同一个容器中两个iterator之间的比较,这是STL中最为简单而常用的动作。唯一的变化是等号的一边是iterator,而另一边是

const_iterator。这应该不是问题,因为iterator应该在比较之前隐式的转换成const_iterator,真正的比较应该在两个 const_iterator之间进行。

对于设计良好的STL实现而言,情况确实如此。但对于其它一些实现,这段代码甚至无法通过编译。原因在于,这些STL实现将const_iterator的等于操作符(operator==)作为const_iterator的一个成员函数而不是友元函数。而问题的解决之道显得非常有趣:只要交换两个iterator的位置,就万事大吉了。

if (ci==i)...//问题的解决方法

不仅是比较是否相等,只要你在同一个表达式中混用iterator和const_iterator(或者reverse_iterator和const_reverse_iterator),这样的问题就会出现。例如,当你试图在两个随机存取迭代器之间进行减法操作时:

if (i-ci >= 3) ...//i与ci之间有至少三个元素

如果迭代器的类型不同,你的完全正确的代码可能会被无理的拒绝。你可以想见解决的方法(交换i和ci的位置),但这次,不仅仅是互换位置了:

if (ci+3 <= i) ...//问题的解决方法

避免类似问题的最简单的方法是减少混用不同类型的迭代器的机会,尽量以iterator取代const_iterator。从const correctness的角度来看,仅仅为了避

免一些可能存在的STL实现的弊端(而且,这些弊端都有较为直接的解决途径)而抛弃 const_iterator显得有欠公允。但综合考虑到iterator与容器类成员函数的粘连关系,得出iterator较之 const_iterator更为实用的结论也就不足为奇了。更何况,从实践的角度来看,并不总是值得卷入const_iterator 的麻烦当中去。

原则二:使用distance和advance将const_iterator转换成iterator

原则一中指出容器类的部分方法仅接受iterator作为参数,而不是const_iterator。那么,如何在一个const_iterator指出的容器位置上插入新元素呢?换言之,如何通过一个const_iterator得到指向容器中相同位置的iterator呢?由于并不存在从 const_iterator到iterator之间的隐式转换,你必须自己找到一条转换的途径。

嗨,我知道你在想什么!“每当无路可走的时候,就祭起强制类型转换的大旗!”。在C++的世界里,强制类型转换似乎总是最后的杀手锏。老实说,这恐怕算不上什么好主意——真不知道你是哪儿学来的。

让我们看看当你想把一个const_iterator强制转换为iterator时会发生什么:

typedef deque IntDeque;//typedef, 简化代码。

typedef IntDeque::iterator Iter;

typedef IntDeque::const_iterator ConstIter;

ConstIter ci;//const_iterator

Iter i(ci);//编译错误!

//没有隐式转换途径!

Iter i(const_cast(ci));//编译错误!

//转换不能成立!

这里只是以的deque为例,但是用其它容器类(list, set, multiset, map, multimap甚至非标准STL的基于hash表的容器[4])产生的代码大同小异。也许vector或string类的代码能够顺利编译,但这是非常特殊的情形。

包含显式类型转换的代码不能通过编译的原因在于,对于这些容器而言,iterator和const_iterator是完全不同的类。它们之间并不比 string和complex具有更多的血缘关系。编译器无法在两个毫无关联的类之间进行const_cast转换。 reinterpret_cast、static_cast甚至C语言风格的类型转换也不能胜任。

不过,对于vector和string容器来说,包含const_cast的代码也许能够通过编译。因为通常情况下STL的大多数实现都会采用真实的指针作为vector和string容器的迭代器。就这种实现而言,vector::iterator和vector::const_iterator分别被定义为T*和const T*,string::iterator和string::const_iterator则被定义为char*和const char*。因此,const_iterator与iterator之间的const_cast转换被最终解释成const T*到T*的转换。当然,这样的类型转换没有问题。但是,即便在这种STL的实现当中,reverse_iterator和 const_reverse_iterator仍然是实在的类,所以仍然不能直接将const_reverse_iterator强制转换成 reverse_iterator。而且,这些STL实现为了方便调试通常只会在Release模式时才使用指针表示vector 和string的迭代器 [5]。所有这些事实表明,出于可移植性的考虑,这样的强制类型转换即使是对vector和string来说也不可取。

如果你得到一个const_iterator并且可以访问它所指向的容器,那么这里有一条安全、可移植的途径将它转换成iterator,而且,用不着搅乱类型系统的强制转换。下面是基本的解决思路,称之为“思路”是因为还要稍作修改才能让这段代码通过编译。

typedef deque IntDeque;

typedef IntDeque::iterator Iter;

typedef IntDeque::const_iterator ConstIter;

IntDeque d;

ConstIter ci;

...//ci指向d。

Iter i(d.begin());//指向d的起始位置。

advance(i, distance(i, ci));//调整i,指向ci位置。

这种方法看上去非常简单,也很直观:要得到与const_iterator指向同一位置的iterator,首先将iterator指向容器的起始位置,并且取得const_iterator 距离容器起始位置的偏移量,然后将iterator向后移动相同的偏移即可。这些动作是通过< iterator>中声明的两个算法函数实现的:distance用以取得两个指向同一个容器的iterator之间的距离;advance则用于将一个iterator移动制定的距离。如果ci和i指向同一个容器,并且i指向容器的器时位置,表达式advance(i, distance(i, ci))会将i移动到与ci相同的位置上。

如果这段代码能够通过编译,它就能完成这种转换任务。但似乎事情并不那么顺利。先来看看distance的定义:

template

typename iterator_traits::difference_type

distance(InputIterator first, InputIterator last);

不必为长达56个字符的返回类型操心,也不用理会difference_type是什么东西。仔细看看调用的参数!编译器需要推断出它所遇到的distance调用的参数类型。再来看看我们的distance调用:

advance(i, distance(i, ci));//调整i,指向ci位置。

i 和ci分别是distance函数的两个参数,它们的类型分别是deque::iterator和deque< int>::const_iterator,而distance函数需要一种确定的参数类型,所以调用失败。也许相应的错误信息会告诉你编译器无法推断出InputIterator的类型。

要顺利的通过编译,你需要排除distance调用的歧义性。最简单的办法就是显式的指明distance调用的模版参数类型,从而避免编译器为此大伤脑筋。 advance(i, distance(i, ci));

这样,我们就可以通过advance和distance将一个const_iterator转换成iterator了。但另一个值的考虑的问题是,这样做的效率如何?答案在于你所转换的究竟是什么样的迭代器。对于随机存取的迭代器(如vector, string和deque)而言,这种转换只需要一个与容器中元素个数无关的常数时间;对于双向迭代器(其它容器,包括基于hash表的非标准容器的一些实现[6])而言,这种转换是与容器元素个数相关的线性时间操作。

这种从const_iterator到iterator的转换可能需要线性的时间代价,并且需要访问const_iterator所属的容器。从这个角度出发,也许你需要重新审视你的设计:是否真的需要从const_iterator到iterator的转换呢?

原则三:正确理解如何使用通过base()得到的iterator

调用reverse_iterator的base()方法可以得到“与之相对应的”iterator。这句话也许有些辞不达意。还是先来看一下这段代码,我们首先把从1到5的5个数放进一个vector中,然后产生一个指向3的reverse_iterator,并且通过其base()函数取得一个 iterator。

vector v;

for(int i = 0;i < 5; ++ i) {//插入1到5

v.push_back(i);

}

vector::reverse_iterator ri =//使ri指向3

find(v.rbegin(), v.rend(), 3);

vector::iterator i(ri.base());//取得i.

下图表示了执行上述代码之后的i和ci迭代器位置:

如图所示,rbegin()与end()、rend()与begin()之间存在一个元素的偏移,并且ri与i之间仍然保留了这种偏移。但这还远远不够,针对你所要进行的特定操作,你还需要知道一些技术细节。

原则一指出容器类的部分成员函数仅接受iterator类型的参数。上面的例子中,你并不能直接在ri所指出的位置上插入元素,因为insert方法不接受 reverse_iterator作为参数。如果你要删除ri位置上的元素,erase方法也有同样的问题。为了完成这种插入/删除操作,你必须首先用 base方法将reverse_iterator转换成iterator,然后用iterator调用insert或erase方法。

先让我们假设你要在ri指出的位置上进行插入操作,并且假设你要插入的值是99。由于ri遍历vector的顺序是自右向左,而insert操作会将新元素插入到ri 位置,并且将原先ri位置的元素移到遍历过程的“下一个”位置,插入操作之后,3应该出现在99的左侧,如下图所示:

当然,这些只是我们的假设而已。insert实际上并不接受reverse_iterator类型的参数,所以我们必须用i取代ri。如上所述,在插入操作之前,ri指向元素3而通过base()得到的i指向元素4。考虑到insert与遍历方向的关系,直接使用i进行insert操作,我们会得到与上述假设完全相同的结果。

·如果要在一个reverse_iterator指出的位置上插入新元素,只需通过base()得到相应的 iterator然后调用insert方法即可。对于insert操作而言,reverse_iterator与通过其base()方法得到的 iterator是完全等价的。

评论

引用通告

此日志的引用通告 URL 是:

https://www.doczj.com/doc/3114273380.html,/blog/cns!638d70adb8f96ead!450.trak

引用此项的网络日志

z

现在再来考虑删除元素的情况,先来回顾一下最初(没有进行insert 操作)的vector 的状态以及i 与ri 的位置:

如果你要删除ri 指向的元素,你恐怕不能直接使用i 了。这时i 与ri 分别指向不同的位置,因此,你需要删除的是i 所指向元素的前一个元素。

· 如果要删除一个reverse_iterator 指向的元素,需要通过base()得到相应的iterator ,并且删除此iterator 所指向的前一位值的元素。对于erase 操作而言,reverse_iterator 与通过其base()方法得到的iterator 并非完全等价。

我们还是有必要看看erase 操作的实际代码:

vector v;

... //插入1到5,同上

vecot::reverse_iterator ri =

find(v.rbegin(), v.rend(), 3); //ri 指向3

v.erase(--ri.base()); //vector 编译不通过。

这段代码并不存在什么设计问题,表达式--ri.base()确实能够指出我们需要删除的元素。而且,它们能够处理除了vector 和string 之外的其他所有容器。但问题是,对于vector 和string ,--ri.base()可能会无法通过编译。这是因为vector 和string 容器的 iterator 和const_iterator 通常会采用真实的指针来实现,而ri.base()会返回一个内建指针。

C 和C++都加强了对指针类型返回值的限制,你不能直接修改函数返回的指针。如果vector 和string 选用真实的指针作为iterator ,你也就不能修改base

()的返回值,所以--ri.base()无法通过编译。出于通用性和可移植性的考虑,应该避免直接修改base()的返回值。当然,我们只需要先增加 ri 的值,然后再调用base()方法:

...//同上

v.erase((++ri).base());//这下编译没问题了!

当你需要删除一个由reverse_iterator 指出的元素时,应该首选这种更为通用而可移植的方法。

由此可见,通过base()方法可以取得一个与reverse_iterator“相对应的”iterator 的说法并不准确。对于insert 而言,这种对应关系确实存在;但是对于erase 操作,情况并非如此简单。当你需要将reverse_iterator 转换成iterator 的时候,你必须根据所要进行的操作对base()的返回值进行相应的调整。

总结:

STL 容器提供了四种不同的迭代器类型,但在实践当中, iterator 比其它三种迭代器更为实用。如果你有一个const_iterator ,并且可以访问它所指向的容器,你就可以通过advance 和 distance 得到与值相应的iterator 。如果你有一个reverse_iterator ,你可以通过base()方法得到“相对应的” iterator ,但在你进行删除操作之前,必须首先调整iterator 的值。

备注与参考:

[1]Scott Meyers, Effective STL: 50 specific ways to improve your use of standard template library. Addison-Wesley, 2001. ISBN 0-201-749629. 本文摘录了Effective STL 中的条款26至28。

[2] Const T vs. T Const. Dan Saks. Embedded Systems Programming,1999二月。

[3] 很难弄清为什么iterator 会比其它三种迭代器更为特殊。HP 公司的最初的STL 实现中使用了iterator 作为insert 和erase 的参数,而STL 标准化过程中对此也未作改动。这种情况可能在STL 的未来版本中有所改变。C++类库工作小组的180号备注中提到:“这个问题应该成为重新审视 C++标准中的const 问题时的一个主要部分”(http://anubis.dkuug.dk/jtc1/sc-22/wg21/docs/lwg- defects.html)。

[4] 有两个较为常用的STL 实现中包含了基于hash 表的容器,Dinkumware STL 和SGISTL 。你可以在1998年12月版CUJ 上找到P.J.Plauger 的栏目“hash table”,它介绍了Dinkumware STL 的实现。就我所知,只有Effective STL 的条款25涉及SGISTL 中hash 类型容器的实现。你可以在http: //https://www.doczj.com/doc/3114273380.html,/tech/stl/HashAssociative-Containers.html 找到SGI 版本的调用界面。

[5]STLPort 再Debug 模式下就是如此。你可以在https://www.doczj.com/doc/3114273380.html, 找到相关资料。

[6]Dinkumware STL 实现的hash 容器提供双向迭代器,除此以外,SGISTL 、STLPort 和Metrowerk 的hash 容器实现都仅提供单向迭代器。

作者简介:

Scott Meyers ,C++程序设计领域著名作家,Effective STL 是他的第三本C++专著。Brown 大学计算机科学博士,NumeriX LLC 和Info Cruiser 顾问委员会成员。提供计算机科学领域的教学和咨询服务,网址:https://www.doczj.com/doc/3114273380.html,

| 10:09写入日志若要添加评论,请使用您的 Windows Live ID 登录。

? 2010 Microsoft 使用条款 隐私声明 广告 行为准则 安全 帮助中心 反馈举报不良信息简体中文

STRING类函数用法总结3

C++中的string类 前言:string的角色 1string使用 1.1充分使用string操作符 1.2眼花缭乱的string find函数 1.3string insert,replace,erase2string和C风格字符串 3string和Charactor Traits 4string建议 5小结 6附录前言:string的角色 C++语言是个十分优秀的语言,但优秀并不表示完美。还是有许多人不愿意使用C或者C++,为什么?原因众多,其中之一就是C/C++的文本处理功能太麻烦,用起来很不方便。以前没有接触过其他语言时,每当别人这么说,我总是不屑一顾,认为他们根本就没有领会C++的精华,或者不太懂C++,现在我接触perl,php,和Shell脚本以后,开始理解了以前为什么有人说C++文本处理不方便了。 举例来说,如果文本格式是:用户名电话号码,文件名name.txt Tom23245332 Jenny22231231 Heny22183942 Tom23245332 ... 现在我们需要对用户名排序,且只输出不同的姓名。 那么在shell编程中,可以这样用: awk'{print$1}'name.txt|sort|uniq 简单吧? 如果使用C/C++就麻烦了,他需要做以下工作: 先打开文件,检测文件是否打开,如果失败,则退出。 声明一个足够大得二维字符数组或者一个字符指针数组 读入一行到字符空间 然后分析一行的结构,找到空格,存入字符数组中。 关闭文件 写一个排序函数,或者使用写一个比较函数,使用qsort排序 遍历数组,比较是否有相同的,如果有,则要删除,copy... 输出信息 你可以用C++或者C语言去实现这个流程。如果一个人的主要工作就是处理这种

C++string类型总结

对C++中string类型的总结 string类对象的构造 简化构造函数原型如下(注意,为了简便,把模板中最后一个默认参数省略了): 1: explicit basic_string(); 2: string(const char *s); 3: string(const char *s, size_type n); 4: string(const string& str); 5: string(const string& str, size_type pos, size_type n); 6: string(size_type n, E c); 7: string(const_iterator first, const_iterator last); string对象的操作 字符串比较 支持六种关系运算符(==、!=、>、>=、<、<=),其采用字典排序策略(与C中字符串比较策略完全一样)。这六个关系运算符是非成员的重载运算符。而这些 运算符都支持三种操作数组合:string op string、string op const char*、cons t char* op string(其中op是前面六种关系运算符中任意一种)。解释:提供运算 符的三种重载版本主要是从效率角度考虑的,其避免了临时string对象的产生。 另外,string类还提供了各种重载版本的成员函数compare来比较,简化函数原型为: 1: int compare(const string& str) const; 2: int compare(size_type p0, size_type n0, const string& str); 3: int compare(size_type p0, size_type n0, const string& str, si ze_type pos, size_type n); 4: int compare(const char* s) const; 5: int compare(size_type p0, size_type n0, const char* s) const; 6: int compare(size_type p0, size_type n0, const char* s, size_t ype n) const; 返回值:如果调用该函数的对象的比较序列小于操作数比较序列,则返回负数; 若相等,则返回0;否则,返回正数。

CPPstring类常用函数

C++string类常用函数 string类的构造函数: string(const char *s); //用c字符串s初始化 string(int n,char c); //用n个字符c初始化 此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2="hello";都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常 string类的字符操作: const char &operator[](int n)const; const char &at(int n)const; char &operator[](int n); char &at(int n); operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。 const char *data()const;//返回一个非null终止的c字符数组 const char *c_str()const;//返回一个以null终止的c字符串 int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目 string的特性描述: int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数) int max_size()const; //返回string对象中可存放的最大字符串的长度 int size()const; //返回当前字符串的大小 int length()const; //返回当前字符串的长度 bool empty()const; //当前字符串是否为空 void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分 string类的输入输出操作: string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。 函数getline(istream &in,string &s);用于从输入流in中读取字符串到s中,以换行符'\n'分开。 string的赋值: string &operator=(const string &s);//把字符串s赋给当前字符串 string &assign(const char *s);//用c类型字符串s赋值 string &assign(const char *s,int n);//用c字符串s开始的n个字符赋值 string &assign(const string &s);//把字符串s赋给当前字符串 string &assign(int n,char c);//用n个字符c赋值给当前字符串 string &assign(const string &s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串 string &assign(const_iterator first,const_itertor last);//把first和last迭代器之间的部

string类的使用教程

这个是string类的使用教程,可以参考一下 之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用= 进行赋值操作,== 进行比较,+ 做串联(是不是很简单?)。我们尽可以把它看成是C++的基本数据类型。 好了,进入正题……… 首先,为了在我们的程序中使用string类型,我们必须包含头文件。如下:#include //注意这里不是string.h string.h是C字符串头文件 1.声明一个C++字符串 声明一个字符串变量很简单: string Str; 这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了string的默认的构造函数,这个函数所作的就是把Str初始化为一个空字符串。String类的构造函数和析构函数如下: a) string s; //生成一个空字符串s b) string s(str) //拷贝构造函数生成str的复制品 c) string s(str,stridx) //将字符串str内“始于位置stridx”的部分当作字符串的初值 d) string s(str,stridx,strlen) //将字符串str内“始于stridx且长度顶多strlen”的部分作为字符串的初值 e) string s(cstr) //将C字符串作为s的初值 f) string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s 的初值。 g) string s(num,c) //生成一个字符串,包含num个c字符 h) string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值 i) s.~string() //销毁所有字符,释放内存 都很简单,我就不解释了。 2.字符串操作函数 这里是C++字符串的重点,我先把各种操作函数罗列出来,不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数,再到后面看他的详细解释。 a) =,assign() //赋以新值 b) swap() //交换两个字符串的内容 c) +=,append(),push_back() //在尾部添加字符 d) insert() //插入字符 e) erase() //删除字符 f) clear() //删除全部字符 g) replace() //替换字符 h) + //串联字符串 i) ==,!=,<,<=,>,>=,compare() //比较字符串 j) size(),length() //返回字符数量

string类中函数介绍

标准c++中string类函数介绍 注意不是CString 之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用= 进行赋值操作,== 进行比较,+ 做串联(是不是很简单?)。我们尽可以把它看成是C++的基本数据类型。 好了,进入正题……… 首先,为了在我们的程序中使用string类型,我们必须包含头文件。 如下: #include //注意这里不是string.h string.h是C字符串头文件 #include using namespace std; 1.声明一个C++字符串 声明一个字符串变量很简单: string Str; 这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了string的默认的构造函数,这个函数所作的就是把Str 初始化为一个空字符串。String类的构造函数和析构函数如下: a) string s; //生成一个空字符串s b) string s(str) //拷贝构造函数生成str的复制品 c) string s(str,stridx) //将字符串str内“始于位置stridx”的部分当作字符串的初值 d) string s(str,stridx,strlen) //将字符串str内“始于stridx且长度顶多strlen”的部分作为字符串的初值 e) string s(cstr) //将C字符串作为s的初值 f) string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。 g) string s(num,c) //生成一个字符串,包含num个c字符 h) string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值 i) s.~string() //销毁所有字符,释放内存 都很简单,我就不解释了。 2.字符串操作函数 这里是C++字符串的重点,我先把各种操作函数罗列出来,不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数,再到后面看他的详细解释。 a) =,assign() //赋以新值 b) swap() //交换两个字符串的内容 c) +=,append(),push_back() //在尾部添加字符

C++string类标准库常用函数

C++ string类标准库常用函数 [string类的构造函数] string(const char *s); //用c字符串s初始化 string(int n,char c); //用n个字符c初始化 [string类的字符操作] const char &operator[](int n) const; const char &at(int n) const; char &operator[](int n); char &at(int n); operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range 异常,下标运算符[]不提供检查访问。 const char *data() const; //返回一个非null终止的c字符数组 const char *c_str() const; //返回一个以null终止的c字符串 int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目 [string的特性描述] int capacity() const; //返回当前容量(即string中不必增加内存即可存放的元素个数) int max_size() const; //返回string对象中可存放的最大字符串的长度 int size() const; //返回当前字符串的大小 int length() const; //返回当前字符串的长度 bool empty() const; //当前字符串是否为空 void resize(int len,char c); //把字符串当前大小置为len,并用字符c填充不足的部分 [string类的输入输出操作] string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。 函数getline(istream &in,string &s);用于从输入流in中读取字符串到s中,以换行符'\n'分开。 [string的赋值] string &operator=(const string &s); //把字符串s赋给当前字符串 string &assign(const char *s); //用c类型字符串s赋值 string &assign(const char *s,int n); //用c字符串s开始的n个字符赋值 string &assign(const string &s); //把字符串s赋给当前字符串 string &assign(int n,char c); //用n个字符c赋值给当前字符串 string &assign(const string &s,int start,int n);//把s中从start开始的n个字符赋给当前字符串string &assign(const_iterator first,const_iterator last);//把迭代器first和last之间的部分赋给字符串 [string的连接] string &operator+=(const string &s); //把字符串s连接到当前字符串的结尾 string &append(const char *s); //把c类型字符串s连接到当前字符串结尾 string &append(const char *s,int n); //把c类型字符串s的前n个字符连接到当前字符串结尾 string &append(const string &s); //同operator+=() string &append(const string &s,int pos,int n); //把字符串s中从pos开始的n个字符连接到当前字符串的结尾 string &append(int n,char c); //在当前字符串结尾添加n个字符c string &append(const_iterator first,const_iterator last); //把迭代器first和last之间的部分连接到当前字符串的结尾

java 字符串常用函数及其用法

java中的字符串也是一连串的字符。但是与许多其他的计算机语言将字符串作为字符数组处理不同,Java将字符串作为String类型对象来处理。将字符串作为内置的对象处理允许Java提供十分丰富的功能特性以方便处理字符串。下面是一些使用频率比较高的函数及其相关说明。 String相关函数 1)substring() 它有两种形式,第一种是:String substring(int startIndex) 第二种是:String substring(int startIndex,int endIndex) 2)concat() 连接两个字符串 例:String s="Welcome to "; String t=s.concat("AnHui"); 3)replace() 替换 它有两种形式,第一种形式用一个字符在调用字符串中所有出现某个字符的地方进行替换,形式如下: String replace(char original,char replacement) 例如:String s=”Hello”.replace(’l',’w'); 第二种形式是用一个字符序列替换另一个字符序列,形式如下: String replace(CharSequence original,CharSequence replacement) 4)trim() 去掉起始和结尾的空格 5)valueOf() 转换为字符串 6)toLowerCase() 转换为小写 7)toUpperCase() 转换为大写 8)length() 取得字符串的长度 例:char chars[]={’a',’b’.’c'}; String s=new String(chars); int len=s.length(); 9)charAt() 截取一个字符 例:char ch; ch=”abc”.charAt(1); 返回值为’b’ 10)getChars() 截取多个字符 void getChars(int sourceStart,int sourceEnd,char target[],int targetStart) sourceStart 指定了子串开始字符的下标 sourceEnd 指定了子串结束后的下一个字符的下标。因此,子串包含从sourceStart到sourceEnd-1的字符。

Java中string的相关函数

Java中string的相关函数 字串与字元 文字字串是一个相当基本且经常被使用到的资料型态,然而在Java 中字串不象char、int 与float 一样是个基本资料型态,而是使用https://www.doczj.com/doc/3114273380.html,ng.String 类别来加以表示,该类别定义了许多有用的方法来操作字串。String 物件是固定不变的(immutable):一旦一个String 物件被建立了,则没有任何方法可以改变它所代表的文字,因此,每个运作字串的方法会传回一个新的String 物件,而所修正过后的字串便是储存在此新物件里。 以下的程式码展示了你可以对字串所执行的运作: // 建立字串 String s = "Now "; // String 物件有个特殊的写法 String t = s + "is the time. "; // 使用+ 运算子来串连字串 String t1 = s + " " + 23.4; // + 将其它值转换为字串 t1 = String.valueOf( 'c '); // 从字元值获得对应的字串 t1 = String.valueOf(42); // 获得整数或其他任何数值的字串版本 t1 = Object.toString(); // 使用toString() 将物件转换为字串 // 字串长度 int len = t.length(); // 字串中的字元数:16 // 字串中的子字串 String sub = t.substring(4); // 传回从char 4 到最后的子字串:"is the time. " sub = t.substring(4, 6); // 传回chars 4 与5:"is " sub = t.substring(0, 3); // 传回chars 0 到2:"Now " sub = t.substring(x, y); // 传回从位置x 到y-1 间的子字串 int numchars = sub.length(); // 子字串的长度永远是(y-x) // 从一个字串中撷取(extract)出字元 char c = t.charAt(2); // 取得t 的第三个字元:w char[] ca = t.toCharArray(); // 将字串转换为一个字元阵列 t.getChars(0, 3, ca, 1); // 将t 中的前三个字元放到ca[1] 到ca[3] 中 // 大小写转换 String caps = t.toUpperCase(); // 转换为大写 String lower = t.toLowerCase(); // 转换为小写 // 字串比较 boolean b1 = t.equals( "hello "); // 传回flase:两字串并不相等 boolean b2 = t.equalsIgnoreCase(caps); // 忽略大小写的字串比较:true boolean b3 = t.startsWith( "Now "); // 传回true boolean b4 = t.endsWith( "time. "); // 传回true int r1 = https://www.doczj.com/doc/3114273380.html,pareTo( "Pow "); // 传回值<0:s 在"Pow "之前 int r2 = https://www.doczj.com/doc/3114273380.html,pareTo( "Now "); // 传回值0:两字串相等

C 中的string常用函数用法总结.

C++中的string常用函数用法总结首先,为了在我们的程序中使用string类型,我们必须包含头文件。 如下: #include //注意这里不是string.h string.h是C字符串头文件 #include using namespace std; 1.声明一个C++字符串 声明一个字符串变量很简单: string Str; 这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了string的默认的构造函数,这个函数所作的就是把Str 初始化为一个空字符串。String类的构造函数和析构函数如下: a) string s; //生成一个空字符串s b) string s(str) //拷贝构造函数生成str的复制品 c) string s(str,stridx) //将字符串str内“始于位置stridx”的部分当作字符串的初值 d) string s(str,stridx,strlen) //将字符串str内“始于stridx且长度顶多st rlen”的部分作为字符串的初值 e) string s(cstr) //将C字符串作为s的初值 f) string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。 g) string s(num,c) //生成一个字符串,包含num个c字符 h) string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值 i) s.~string() //销毁所有字符,释放内存 都很简单,我就不解释了。

String常见的操作和方法

String常见的操作和方法 String类适用于描述字符串事物 那么它就提供了多个方法对字符串进行操作。 常见的操作有哪些? “afbs” 1、获取 1.1 字符串中包含的字符数,也就是字符串的长度。 int length(): 获取长度。 1.2 根据位置获取位置上某个字符。 char charAt(int index): 1.3 根据字符获取字符在字符串中位置。 int indexOf(int ch): 返回的是ch在字符串中第一次出现的位置。 int indexOf(int ch, int fromIndex): 从fromIndex指定位置开始,获取ch在字符串中出现的位置。 int indexOf(int str): 返回的是str在字符串中第一次出现的位置。 int indexOf(int str, int fromIndex): 从fromIndex指定位置开始,获取str在字符串中出现的位置。 int lastIndexOf(int ch); 2、判断。 2.1 字符串中是否包含某一个子串。 boolean contains(str): 特殊之处:indexOf(str):可以索引str第一次出现的位置,如果返回-1.表示该str不存在字符串中。 所以,也可以用于对指定判断是否包含。 if(str.indexOf("aa")!=-1) 而且该方法既可以判断,又可以获取出现的位置。 2.2 字符串中是否有内容。

boolean ifEmpty(): 原理就是判断长度是否为0. 2.3 字符串是否是以指定内容开头。 boolean startsWith(str); 2.4 字符串是否是以指定内容结尾。 boolean endsWith(str); 2.5判断字符串内容是否相同。复写了Object类中的equals方法。boolean equals(str); 2.6判断内容是否相同,并忽略大小写。 boolean equalsIgnoreCase(); 3、转换 3.1 将字符数组转成字符串。 构造函数:String(char[]) String(char[],offset,count):将字符数组中的一部分转成字符串。 静态方法: static String copyValueOf(char[]); static String copyValueOf(char[] data,int offset,int count) static String valueOf(char[]): 3.2 将字符串转成字符数组。 char[] toCharArray(): 3.3 将字节数组转成字符串。 String(byte[]) String(byte[],offset,count):将字节数组中的一部分转成字符串。 3.4 将字符串转成字节数组。** byte[] getBytes(): 3.5 将基本数据类型转成字符串。 static String valueOf(int) static String valueOf(double) 3+"";//String.valueOf(3); 特殊:字符串和字节数组在转换过程中,是可以指定编码表的。

c++中string的用法

之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用 = 进行赋值操作,== 进行比较,+ 做串联(是不是很简单?)。我们尽可以把它看成是C++的基本数据类型。 首先,为了在我们的程序中使用string类型,我们必须包含头文件 。如下: #include //注意这里不是string.h string.h是C字符串头文件 1.声明一个C++字符串 声明一个字符串变量很简单: string Str; 这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了string的默认的构造函数,这个函数所作的就是把Str 初始化为一个空字符串。String类的构造函数和析构函数如下: a) string s; //生成一个空字符串s b) string s(str) //拷贝构造函数生成str的复制品 c) string s(str,stridx) //将字符串str内"始于位置stridx"的部分当作字符串的初值 d) string s(str,stridx,strlen) //将字符串str内"始于stridx且长度顶多strlen"的部分作为字符串的初值 e) string s(cstr) //将C字符串作为s的初值 f) string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。 g) string s(num,c) //生成一个字符串,包含num个c字符 h) string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值 i) s.~string() //销毁所有字符,释放内存 都很简单,我就不解释了。 2.字符串操作函数 这里是C++字符串的重点,我先把各种操作函数罗列出来,不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数,再到后面看他的详细解释。 a) =,assign() //赋以新值 b) swap() //交换两个字符串的内容 c) +=,append(),push_back() //在尾部添加字符 d) insert() //插入字符 e) erase() //删除字符 f) clear() //删除全部字符 g) replace() //替换字符 h) + //串联字符串 i) ==,!=,<,<=,>,>=,compare() //比较字符串 j) size(),length() //返回字符数量 k) max_size() //返回字符的可能最大个数 l) empty() //判断字符串是否为空 m) capacity() //返回重新分配之前的字符容量

C++string类常用函数

string类的构造函数: string(const char *s); //用c字符串s初始化 string(int n,char c); //用n个字符c初始化 此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2="hello";都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常 string类的字符操作: const char &operator[](int n)const; const char &at(int n)const; char &operator[](int n); char &at(int n); operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。 const char *data()const;//返回一个非null终止的c字符数组 const char *c_str()const;//返回一个以null终止的c字符串 int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目 string的特性描述: int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数) int max_size()const; //返回string对象中可存放的最大字符串的长度 int size()const; //返回当前字符串的大小 int length()const; //返回当前字符串的长度 bool empty()const; //当前字符串是否为空 void resize(int len,char c);//把字符串当前大小置为len,并用字符

string的用法

1.声明一个C++字符串 声明一个字符串变量很简单: string Str; 这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了string的默认的构造函数,这个函数所作的就是把Str 初始化为一个空字符串。String类的构造函数和析构函数如下: a) string s; //生成一个空字符串s b) string s(str) //拷贝构造函数生成str的复制品 c) string s(str,stridx) //将字符串str内"始于位置stridx"的部分当作字符串的初值 d) string s(str,stridx,strlen) //将字符串str内"始于stridx且长度顶多strlen"的部分作为字符串的初值 e) string s(cstr) //将C字符串作为s的初值 f) string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。 g) string s(num,c) //生成一个字符串,包含num个c字符 h) string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值 i) s.~string() //销毁所有字符,释放内存 都很简单,我就不解释了。 2.字符串操作函数 这里是C++字符串的重点,我先把各种操作函数罗列出来,不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数,再到后面看他的详细解释。 a) =,assign() //赋以新值 b) swap() //交换两个字符串的内容 c) +=,append(),push_back() //在尾部添加字符 d) insert() //插入字符 e) erase() //删除字符 f) clear() //删除全部字符 g) replace() //替换字符 h) + //串联字符串 i) ==,!=,<,<=,>,>=,compare() //比较字符串 j) size(),length() //返回字符数量 k) max_size() //返回字符的可能最大个数 l) empty() //判断字符串是否为空 m) capacity() //返回重新分配之前的字符容量 n) reserve() //保留一定量内存以容纳一定数量的字符 o) [ ], at() //存取单一字符 p) >>,getline() //从stream读取某值 q) << //将谋值写入stream r) copy() //将某值赋值为一个C_string s) c_str() //将内容以C_string返回 t) data() //将内容以字符数组形式返回 u) substr() //返回某个子字符串

C++ string类常用函数

C++ string类常用函数 #include using namespace std; 构造函数: string(const char *s); //用c字符串s初始化 string(int n, char c); //用n个字符c初始化 此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2="hello";都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常 字符操作: const char &operator[](int n)const; const char &at(int n)const; char &operator[](int n); char &at(int n); 注:operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。 const char *data()const; //返回一个非null终止的c字符数组 const char *c_str()const; //返回一个以null终止的c字符串 int copy(char *s, int n, int pos = 0) const; //把当前串中以pos开始的n个字符拷贝到以s为 //起始位置的字符数组中,返回实际拷贝的数目 特性描述: int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数) int max_size()const; //返回string对象中可存放的最大字符串的长度 int size()const; //返回当前字符串的大小 int length()const; //返回当前字符串的长度 bool empty()const; //当前字符串是否为空 void resize(int len,char c); //把字符串当前大小置为len,并用字符c填充不足的部分 输入输出操作: string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。 函数getline(istream &in,string &s);用于从输入流in中读取字符串到s中,以换行符分开。 赋值: string &operator=(const string &s); //把字符串s赋给当前字符串

C 中的STRING用法

#include//注意是,不是,带.h的是C语言中的头文件using std::string; using std::wstring; 或 using namespace std; 下面你就可以使用string/wstring了,它们两分别对应着char和wchar_t。 string和wstring的用法是一样的,以下只用string作介绍: string类的构造函数: string(const char*s);//用c字符串s初始化 string(int n,char c);//用n个字符c初始化 此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2="hello";都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常; string类的字符操作: const char&operator[](int n)const; const char&at(int n)const; char&operator[](int n); char&at(int n); operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。 const char*data()const;//返回一个非null终止的c字符数组 const char*c_str()const;//返回一个以null终止的c字符串 int copy(char*s,int n,int pos=0)const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目 string的特性描述: int capacity()const;//返回当前容量(即string中不必增加内存即可存放的元素个数)int max_size()const;//返回string对象中可存放的最大字符串的长度 int size()const;//返回当前字符串的大小 int length()const;//返回当前字符串的长度 bool empty()const;//当前字符串是否为空 void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分string类的输入输出操作: string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。函数getline(istream&in,string&s);用于从输入流in中读取字符串到s中,以换行符'\n'分开。

Java String类的常用方法

6.2 1 String类的常用方法 程序模板 按模板要求,将【代码1】~【代码9】替换为Java程序代码。 StringExample.java class StringExample { public static void main(String args[ ]) { String s1=new String("you are a student"), s2=new String("how are you"); if (【代码1】) // 判断s1与s2是否相同 { System.out.println("s1与s2相同"); } else { System.out.println("s1与s2不相同"); } String s3=new String("22030219851022024"); if (【代码2】) // 判断s3的前缀是否是“220302” { System.out.println("吉林省的身份证"); } String s4=new String("你"), s5=new String("我"); if(【代码3】) // 按着字典序s4大于s5的表达式 { System.out.println("按字典序s4大于s5"); } else { System.out.println("按字典序s4小于s5"); } int position=0; String path="c:\\java\\jsp\\A.java"; position=【代码5】// 获取path中最后出现目录分隔符号的位置 System.out.println("c:\\java\\jsp\\A.java中最后出现\\的位置:"+position); String fileName=【代码6】// 获取path中“A.java”子字符串 System.out.println("c:\\java\\jsp\\A.java中含有的文件名:"+fileName);

Java中String的用法总结

构造方法: String() 初始化一个新创建的String 对象,它表示一个空字符序列。 String(byte[] bytes) 构造一个新的String,方法是使用平台的默认字符集解码字节的指定数组。String(byte[] bytes, int offset, int length) 构造一个新的String,方法是使用指定的字符集解码字节的指定子数组。String(byte[] bytes, int offset, int length, String charsetName) 构造一个新的String,方法是使用指定的字符集解码字节的指定子数组。String(byte[] bytes, String charsetName) 构造一个新的String,方法是使用指定的字符集解码指定的字节数组。 String(char[] value) 分配一个新的String,它表示当前字符数组参数中包含的字符序列。 String(char[] value, int offset, int count) 分配一个新的String,它包含来自该字符数组参数的一个子数组的字符。String(int[] codePoints, int offset, int count) 分配一个新的String,它包含该Unicode 代码点数组参数的一个子数组的字符。 String(String original) 初始化一个新创建的String 对象,表示一个与该参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的一个副本。 String(StringBuffer buffer) 分配一个新的字符串,它包含当前包含在字符串缓冲区参数中的字符序列。String(StringBuilder builder) 分配一个新的字符串,它包含当前包含在字符串生成器参数中的字符序列 方法总结: char charAt(int index) 返回指定索引处的char 值。 int codePointAt(int index) 返回指定索引处的字符(Unicode 代码点)。 int codePointBefore(int index) 返回指定索引之前的字符(Unicode 代码点)。 int codePointCount(int beginIndex, int endIndex) 返回此String 的指定文本范围中的Unicode 代码点数。 int compareT o(String anotherString) 按字典顺序比较两个字符串(区分大小写)。 int compareT oIgnoreCase(String str) 不考虑大小写,按字典顺序比较两个字符串。 String concat(String str) 将指定字符串联到此字符串的结尾。 boolean contains(CharSequence s) 当且仅当此字符串包含char 值的指定序列时,才返回true。 boolean contentEquals(CharSequence cs) 当且仅当此String 表示与指定序列相同的char 值时,才返回true。

相关主题
文本预览
相关文档 最新文档