您的位置:首页 > 编程语言 > C语言/C++

C/C++中字符串String及字符操作方法

2014-06-22 13:33 309 查看
本文总结C/C++中字符串操作方法,还在学习中,不定期更新。。。

字符串的输入方法

1、单个单词可以直接用std::cin,因为:std::cin读取并忽略开头所有的空白字符(如空格,换行符,制表符),读取字符直至再次遇到空白字符,读取终止。所以cin只能读取单个单词。显然可以多次使用cin来获取多个单词;

2、多个单词使用函数std::getline(std::cin, s)请看下面代码:

#include <iostream>
#include <string>
int main()
{
std::string line; // empty string
while(std::getline(std::cin, line))
{
// read line at time until end-of-file
std::cout << line << std::endl; // write s to the output
}
return 0;
}
Name: getline

这个函数接受两个参数:一个输入流对象和一个 string 对象。getline 函数从输入流的下一行读取,并保存读取的内容到不包括换行符。和输入操作符不一样的是,getline 并不忽略行开头的换行符。只要 getline 遇到换行符,即便它是输入的第一个字符,getline 也将停止读入并返回。如果第一个字符就是换行符,则 string 参数将被置为空 string。

由于getline函数返回时丢弃换行符,换行符将不会存储在string对象中。

Prototype: ssize_t getline (char **lineptr, size_t *n, FILE *stream)

Description:

This function reads an entire line from stream, storing the text (including the newline and a terminating null character) in a buffer and storing the buffer address in *lineptr. 

Before calling getline, you should place in *lineptr the address of a buffer *n bytes long, allocated  with malloc. If this buffer is long enough to hold the line, getline stores the line in this buffer.  Otherwise, getline makes the buffer bigger using realloc,
storing the new buffer address back in  *lineptr and the increased size back in *n. . 

If you set *lineptr to a null pointer, and *n to zero, before the call, then getline allocates the initial buffer for you by calling malloc. 

In either case, when getline returns, *lineptr is a char * which points to the text of the line. 

When getline is successful, it returns the number of characters read (including the newline, but  not including the terminating null). This value enables you to distinguish null characters that are  part of the line from the
null character inserted as a terminator. 

This function is a GNU extension, but it is the recommended way to read lines from a stream. The  alternative standard functions are unreliable. 

If an error occurs or end of file is reached without any bytes read, getline returns -1. Header files:stdio.h

String的操作方法

s.empty()

Returns true if s is empty; otherwise returns false

如果 s 为空串,则返回 true,否则返回 false。

s.size()

Returns number of characters in s
返回 s 中字符的个数

s

Returns the character at position n in s; positions start at 0.

返回 s 中位置为 n 的字符,位置从 0 开始计数

【注意:1、引用下标时如果超出下标作用范围就会引起溢出错误。同样不会报错!2、索引的实际数据类型是类型 unsigned 类型string::size_type。】

#include <iostream>
#include <string>

int main()
{
std::string s = "hello world";
std::cout<<s<<std::endl;
for (std::string::size_type ix = 0; ix != s.size(); ++ix)
s[ix] = '*';
std::cout<<"Now s is:"<<s<<std::endl;
std::cout<<"s's len is:"<<s.size()<<", s[12]="<<s[100]<<std::endl;
return 0;
}
注意:循环中使用了std::string::size_type ix = 0;请使用string内置类型size_type来操作。因为int型可能不够string的长度,所以内置类型size_type(实际可以认为是unsigned)被创建,保证各机器的兼容性,避免溢出(和下标溢出可不是一回事)。任何存储
string 的 size 操作结果的变量必须为 string::size_type 类型。特别重要的是,还要把 size 的返回值赋给一个 int 变量。

s1 + s2

Returns a string equal to the concatenation of s1 and s2

把 s1 和s2 连接成一个新字符串,返回新生成的字符串

【备注: 可以连续加,和Python类似。string s3 = s1 + ", " + s2 + "\n";。注意:当进行 string 对象和字符串字面值混合连接操作时,+ 操作符的左右操作数必须至少有一个是
string 类型的【想象下级联也就知道这确实是有道理的】。----1、也就是说+连接必须保证前两个有一个为string类型!2、字符串字面值不能直接相加,字符串字面值和string是不同类型的,字符串里面没有空字符'\0'。(更新于2014.06.24)】

s1 = s2

Replaces characters in s1 by a copy of s2

把 s1 内容替换为 s2 的副本

【备注:。它必须先把 s1 占用的相关内存释放掉,然后再分配给 s2 足够存放 s2 副本的内存空间,最后把 s2 中的所有字符复制到新分配的内存空间。】

v1 == v2

Returns true if v1 and v2 are equal; false otherwise

比较 v1 与 v2 的内容,相等则返回 true,否则返回 false

!=, <, <=, >, and >=

Have their normal meanings

保持这些操作符惯有的含义

cctype Functions

我们经常要对 string 对象中的单个字符进行处理,例如,通常需要知道某个特殊字符是否为空白字符、字母或数字。以下 列出了各种字符操作函数,适用于 string 对象的字符(或其他任何 char 值)。这些函数都在cctype 头文件中定义。

isalnum(c)

True if c is a letter or a digit.如果 c 是字母或数字,则为 True。

isalpha(c)

true if c is a letter.如果 c 是字母,则为 true。

iscntrl(c)

true if c is a control character.如果 c 是控制字符,则为 true

isdigit(c)

true if c is a digit.如果 c 是数字,则为 true。

isgraph(c)

true if c is not a space but is printable.如果 c 不是空格,但可打印,则为 true。

islower(c)

true if c is a lowercase letter.如果 c 是小写字母,则为 true。

isprint(c)

True if c is a printable character.如果 c 是可打印的字符,则为 true。
【注意:可打印的字符是指那些可以表示的字符】

ispunct(c)

True if c is a punctuation character.如果 c 是标点符号,则 true。

【注意:标点符号则是除了数字、字母或(可打印的)空白字符(如空格)以外的其他可打印字符】

isspace(c)

true if c is whitespace.如果 c 是空白字符,则为 true。

【注意:空白字符则是空格、制表符、垂直制表符、回车符、换行符和进纸符中的任意一种】

isupper(c)

True if c is an uppercase letter.如果 c 是大写字母,则 true。

isxdigit(c) 

true if c is a hexadecimal digit.如果是 c 十六进制数,则为 true。

tolower(c) 

If c is an uppercase letter, returns its lowercase equivalent; otherwise returns c unchanged.如果 c 大写字母,返回其小写字母形式,否则直接返回 c。

toupper(c)

If c is a lowercase letter, returns its uppercase equivalent; otherwise returns c unchanged.如果 c 是小写字母,则返回其大写字母形式,否则直接返回 c。

【注意:ctype.h是定义在C标准库中的头文件,cctype 其实就是利用了 C 标准库函数。C 标准库头文件命名形式为 name 而 C++ 版本则命名为 cname ,少了后缀,.h而在头文件名前加了
c 表示这个头文件源自 C 标准库。因此,cctype 与 ctype.h 文件的内容是一样的,只是采用了更适合 C++程序的形式。特别地,cname 头文件中定义的名字都定义在命名空间 std 内,而 .h 版本中的名字却不是这样。通常,C++
程序中应采用 cname 这种头文件的版本,而不采用 name.h 版本,这样,标准库中的名字在命名空间 std 中保持一致。使用 .h 版本会给程序员带来负担,因为他们必须记得哪些标准库名字是从 C 继承来的,而哪些是 C++ 所特有的。】

字符串操作

以下总结更新于2014.10.01,来源于经典教材。

其中:s和str是字符串string,ca是一个字符数组,str_ca是一个字符串或者一个字符数组,str_ca_ch是一个字符串、字符数组或一个字符,ch是一个字符,n、n1、n2、pos1、pos2是整数。

长度操作

s.capacity()

返回s获取的存储容量;

s.size()/s.length()

返回s的长度;

s.empty()

如果s没有包含字符则返回true,否则返回false;

s.max_size()

返回s可能的最大长度; 

编辑操作

s.append(str_ca)

将str_ca添加到s的结尾,返回s;

s.append(ca, n)

将ca的前n个字符添加到s的结尾,返回s;

s.append(n, ch)

将ch的n份拷贝添加到s的结尾,返回s;

s.insert(pos, str)

将str的拷贝插入到s的pos位置,返回s;

s.insert(pos1, str, pos2, n)

将str中从pos2位置开始的n个字符插入到s的pos1位置,返回s;【如果n大于str的长度,不会有问题,没有溢出错误,只会复制到str的末尾】

s.insert(pos, ca, n)

将ca的前n个字符插入到s的pos位置,如果n被省略,则插入ca中所有的字符到pos位置,返回s;

s.insert(pos, n, ch)

将字符ch的n个拷贝插入到s的pos位置,返回s;

s.erase(pos, n)

删除s中从pos开始的n个字符(默认pos为0),返回s;

s.replace(pos1, n1, str)

将s中pos1位置开始的长度为n1的字符串替换为str【如果n1太大,从pos到s结尾的所有字符将被替换】,返回s;

s.replace(pos1, n1, ca, n2)

和上面一样,只不过取ca的前n2个字符,返回s;

s.swap(str)/swap(s, str)

交换s和str的内容分,返回为void;

复制操作

支持+  +=操作符。

s.assign(str_ca)

将str_ca的一份拷贝赋予s,返回s;

s.assign(ca, n)

将ca的前n个字符构成的字符串赋予s,返回s;

s.assign(n, ch)

将n个ch组成的字符串赋予s,返回s;

s.substr(pos, n)

返回s中从pos(默认为0)开始的,有n个字符组成的s的子串的拷贝;

查找操作

s.find(str_ca_ch, pos)

返回s中第一个大于等于pos的位置,并且从这个位置的下一个字符开始s中字符和str_ca_ch中相应字符匹配。如果没有这样的位置则返回npos,pos默认为0

s.find_first_of(str_ca_ch, pos)

返回s中大于等于pos的第一个和str_ca_ch中任意字符匹配的字符的位置,如果没有这样的位置则返回npos,pos的默认值为0

s.find_first_not_of(str_ca_ch, pos)

返回s中大于等于pos的第一个和str_ca_ch中任意字符都不匹配的字符的位置,如果没有这样的位置则返回npos,pos的默认值为0

s.find_last_of(str_ca_ch, pos)

返回s中小于等于pos的最大的一个和str_ca_ch中任意字符匹配的字符的位置,如果没有这样的位置则返回npos,pos的默认值为0

s.find_last_not(str_ca_ch, pos)

返回s中小于等于pos的最大的一个和str_ca_ch中任意字符都不匹配的字符的位置,如果没有这样的位置则返回npos,pos的默认值为0

s.rfind(str_ca_ch, pos)

返回s中最后一个小于等于pos的位置,并且从这个位置开始的str_ca_ch.size()个字符和str_ca_ch中相应的字符匹配。如果没有这样的位置则返回npos,pos默认为npos

比较操作

支持上述 <、<=、>、>=、==、!=操作符。

s.compare(str_ca)

返回值为正、0、负

string和C风格字符串的转换

s.c_str()

返回一个常字符数组,这个数组包含存储在s中字符,以一个空字符结束;

s.data()

返回一个常字符数组,这个数组包含存储在s中字符,但没有以空字符结束;

s.copy(charArray, pos, n)

将charArray替换为s中从pos开始的n个字符,如果pos被省略了,即从0开始,如果n太大,那么拷贝字符直到s结束,返回最终拷贝的字符个数。

备注:data()和c_str()都可以被用来从一个文件名中提取open操作所需要的字符数组,此部分内容可能会在后续文件操作中接触到。

例子

【此小节更新于2014.06.24】
原题在另一篇博文中:C/C++中容器vector使用方法http://blog.csdn.net/zhanh1218/article/details/33323111

#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl; using std::string; using std::vector;

string deal_word(string word)
{
// 使用c++11 auto 语句 以及range for 语句
for(auto &c : word)
{
if (not ispunct(c))
{
c = toupper(c); //连接非标点字符到字符串
}
else
{
word.erase(word.size()-1, 1); //只能删除最后一个标点符号。有局限性!
}
}
return word;
}

string deal_word2(string word)
{
// 使用下标及c++11 decltype
for (decltype(word.size()) index = 0; index != word.size(); ++index)
{
if (not ispunct(word[index]))
{
word[index] = toupper(word[index]);
}
else
{
word.erase(index, 1); // 删除指定位置上的某一个字符,在此为标点
index -= 1; //保证下标不越界!重要!
}
}
return word;
}

int main()
{
string word; // 缓存输入的单词
vector<string> text; // empty vector
cout<<"Please input the text:"<<endl; //提示输入
while (std::cin >> word and word != "INPUTOVER") // INPUTOVER 用于标示输入结束,也可以ctrl + z停止输入
{
word = deal_word(word); // 单词处理
text.push_back(word); // append word to text
}
for(std::vector<int>::size_type ix =0, j = 0; ix != text.size(); ++ix, ++j)
{
if (j==8) // 8个单词一行
{
cout<<endl; //换行
j = 0; //重新计数
}
cout<<text[ix]<<" "; //加空格!
}
return 0;
}


改写了两种处理单词的方法。使用了c++11中的新特性!
【更新于2014.06.05,一直忽视了for循环中不要增删迭代器中内容的问题,这个确实不好处理,还是选择复制吧(也就是原来的方法)!错误概率低,可读性强,效率上还有待考证。待补充。。。】

其他

str.erase()方法:来自百度

1、erase(pos, n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符

2、erase(position); 删除position处的一个字符(position是个string类型的迭代器)

3、erase(first, last); 删除从first到last之间的字符(first和last都是迭代器)

本文由@The_Third_Wave(Blog地址:http://blog.csdn.net/zhanh1218)原创。不定期更新,有错误请指正。

如果你看到这篇博文时发现不完整,那是我为防止爬虫先发布一半的原因,请看原作者Blog。

如果这篇博文对您有帮助,为了好的网络环境,不建议转载,建议收藏!如果您一定要转载,请带上后缀和本文地址。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐