std string使用

来源:互联网 发布:pic单片机汇编指令 编辑:程序博客网 时间:2024/04/29 10:34

用 string来代替char * 数组,使用sort排序算法来排序,用unique 函数来去重
1、Define
        string s1 = "hello";
        string s2 = "world";
        string s3 = s1 + "," + s2 +"!\n";
2、append
        s1 += ",shanshan\n";
3、Compare
        if(s1 == s2)
           .....
        else if(s1 == "hello")
           .....
4、 string 重载了许多操作符,包括 +, +=, <, =, , [], <<, >>等,正式这些操作符,对字符串操作非常方便

#include <string>#include <iostream>using namespace std;int main(){        string strinfo="Please input your name:";        cout << strinfo ;        cin >> strinfo;        if( strinfo == "winter" )        cout << "you are winter!"<<endl;        else if( strinfo != "wende" )        cout << "you are not wende!"<<endl;        else if( strinfo < "winter")        cout << "your name should be ahead of winter"<<endl;        else         cout << "your name should be after of winter"<<endl;        strinfo += " , Welcome to China!";        cout << strinfo<<endl;        cout <<"Your name is :"<<endl;        string strtmp = "How are you? " + strinfo;        for(int i = 0 ; i < strtmp.size(); i ++)        cout<<strtmp[i];        return 0;} 
5、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表示的是-1。即没找到就返回-1。例子如下:#include <string>#include <iostream>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"<<endl;                return -1;        }         int last = strinfo.find_last_of(strset);        if(last == string::npos) {                 cout<<"not find any characters"<<endl;                return -1;        }         cout << strinfo.substr(first, last - first + 1)<<endl;//string.substr是子串        return 0;}6、insert函数, replace函数和erase函数string只是提供了按照位置和区间的replace函数,而不能用一个string字串来替换指定string中的另一个字串。例子:#include <string>#include <iostream>using namespace std;int main() {        string strinfo="This is Winter, Winter is a programmer. Do you know Winter?";        cout<<"Orign string is :\n"<<strinfo<<endl;        string_replace(strinfo, "Winter", "wende");        cout<<"After replace Winter with wende, the string is :\n"<<strinfo<<endl;        return 0;}string.erase(pos,srclen);//srclen是删除的长度string.insert(pos,strdst); //pos是定位,strdst是插入的函数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;        }}相关链接:http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString 7、切割字符串#include <sstream>#include <string>#include <iostream>using namespace std;int main(){        string text = "big|dog|china|sonic|free";        stringstream ss(text);        string sub_str;        while(getline(ss,sub_str,'|'))  //以|为间隔分割test的内容                cout << sub_str << endl;        return 0;}输出如下:bigdogchinasonicfree8、构造函数和析构函数string s                  生成一个空字符串Sstring s(str)             Copy构造函数,生成字符串Str的一个复制品string s(str,stridx)      将字符串Str内始于位置Stridx的部分,当作字符串S的初值string s(str,stridx,strlen)  将字符串Str内始于位置Stridx且长度为strlen的部分,当作字符串S的初值
string s(cstr)            以C-String cstr作为S的初值
string s(num,c)           生成一个字符串,包含Num个C字符
string s(beg,end)         以区间[beg,end]内的字符作为s初值
s.~string()               销毁所有字符,释放内存
注意:
std::string s('x');//error
std::string s(1,'x'); //ok,create a string that has one charactor 'x'

9、substr(string.substr的方法)
 

(1)参数

start:Number -- 一个整数,指示 my_str 中用于创建子字符串的第一个字符的位置。如果 start 为一个负数,则起始位置从字符串的结尾开始确定,其中 -1 表示最后一个字符。

length:Number -- 要创建的子字符串中的字符数。如果没有指定 length,则子字符串包括从字符串开头到字符串结尾的所有字符。

(2)返回

String -- 指定字符串的子字符串。

(3)示例

下面的示例创建一个新字符串 my_str,并使用 substr() 返回该字符串中的第二个单词;首先,使用正的 start 参数,然后使用负的 start 参数:

var my_str:String = new String("Hello world");
var mySubstring:String = new String();
mySubstring = my_str.substr(6,5);
trace(mySubstring); // 输出:world

mySubstring = my_str.substr(-5,5);
trace(mySubstring); // 输出:world

toupper, tolower
地球人都知道 C++ 的 string 没有 toupper ,好在这不是个大问题,因为我们有 STL 算法:

string s("heLLo");
transform(s.begin(), s.end(), s.begin(), toupper);
cout << s << endl;
transform(s.begin(), s.end(), s.begin(), tolower);
cout << s << endl;

当然,我知道很多人希望的是 s.to_upper() ,但是对于一个这么通用的 basic_string 来说,的确没办法把这些专有的方法放进来。如果你用 boost stringalgo ,那当然不在话下,你也就不需要读这篇文章了。

------------------------------------------------------------------------
trim
我们还知道 string 没有 trim ,不过自力更生也不困难,比 toupper 来的还要简单:

    string s("   hello   ");
    s.erase(0, s.find_first_not_of(" \n"));
    cout << s << endl;
    s.erase(s.find_last_not_of('' '') + 1);
    cout << s << endl;

注意由于 find_first_not_of 和 find_last_not_of 都可以接受字符串,这个时候它们寻找该字符串中所有字符的 absence ,所以你可以一次 trim 掉多种字符。

-----------------------------------------------------------------------
erase
string 本身的 erase 还是不错的,但是只能 erase 连续字符,如果要拿掉一个字符串里面所有的某个字符呢?用 STL 的 erase + remove_if 就可以了,注意光 remove_if 是不行的。

    string s("   hello, world. say bye   ");
    s.erase(remove_if(s.begin(),s.end(), 
        bind2nd(equal_to<char>(), '' '')), 
    s.end());

上面的这段会拿掉所有的空格,于是得到 hello,world.saybye。

-----------------------------------------------------------------------
replace
string 本身提供了 replace ,不过并不是面向字符串的,譬如我们最常用的把一个 substr 换成另一个 substr 的操作,就要做一点小组合:

    string s("hello, world");
    string sub("ello, ");
    s.replace(s.find(sub), sub.size(), "appy ");
    cout << s << endl;

输出为 happy world。注意原来的那个 substr 和替换的 substr 并不一定要一样长。

-----------------------------------------------------------------------
startwith, endwith
这两个可真常用,不过如果你仔细看看 string 的接口,就会发现其实没必要专门提供这两个方法,已经有的接口可以干得很好:

    string s("hello, world");
    string head("hello");
    string tail("ld");
    bool startwith = s.compare(0, head.size(), head) == 0;
    cout << boolalpha << startwith << endl;
    bool endwith = s.compare(s.size() - tail.size(), tail.size(), tail) == 0;
    cout << boolalpha << endwith << endl;

当然了,没有 s.startwith("hello") 这样方便。

------------------------------------------------------------------------
toint, todouble, tobool...
这也是老生常谈了,无论是 C 的方法还是 C++ 的方法都可以,各有特色:

    string s("123");
    int i = atoi(s.c_str());
    cout << i << endl;
    
    int ii;
    stringstream(s) >> ii;
    cout << ii << endl;
    
    string sd("12.3");
    double d = atof(sd.c_str());
    cout << d << endl;
   
 double dd;
    stringstream(sd) >> dd;
    cout << dd << endl;
    
    string sb("true");
    bool b;
    stringstream(sb) >> boolalpha >> b;
    cout << boolalpha << b << endl;

C 的方法很简洁,而且赋值与转换在一句里面完成,而 C++ 的方法很通用。

------------------------------------------------------------------------
split
这可是件麻烦事,我们最希望的是这样一个接口: s.split(vect, '','') 。用 STL 算法来做有一定难度,我们可以从简单的开始,如果分隔符是空格、tab 和回车之类,那么这样就够了:

    string s("hello world, bye.");
    vector<string> vect;
    vect.assign(
        istream_iterator<string>(stringstream(s)),
        istream_iterator<string>()
    );

不过要注意,如果 s 很大,那么会有效率上的隐忧,因为 stringstream 会 copy 一份 string 给自己用。

------------------------------------------------------------------------
concat
把一个装有 string 的容器里面所有的 string 连接起来,怎么做?希望你不要说是 hand code 循环,这样做不是更好?

    vector<string> vect;
    vect.push_back("hello");
    vect.push_back(", ");
    vect.push_back("world");
    
    cout << accumulate(vect.begin(), vect.end(), string(""));

不过在效率上比较有优化余地。

-------------------------------------------------------------------------

reverse
其实我比较怀疑有什么人需要真的去 reverse 一个 string ,不过做这件事情的确是很容易:

  std::reverse(s.begin(), s.end());

上面是原地反转的方法,如果需要反转到别的 string 里面,一样简单:

  s1.assign(s.rbegin(), s.rend());

效率也相当理想。

-------------------------------------------------------------------------

解析文件扩展名
字数多点的写法:

    std::string filename("hello.exe");

    std::string::size_type pos = filename.rfind(''.'');
    std::string ext = filename.substr(pos == std::string::npos ? filename.length() : pos + 1);

不过两行,合并成一行呢?也不是不可以:

    std::string ext = filename.substr(filename.rfind(''.'') == std::string::npos ? filename.length() : filename.rfind(''.'') + 1);

我知道,rfind 执行了两次。不过第一,你可以希望编译器把它优化掉,其次,扩展名一般都很短,即便多执行一次,区别应该是相当微小。

GBK中文编码和std::string的冲突问题

最近写了一个按照分隔符拆分字符串的接口,
void PickUp(std::string &strDes,std::vector<std::string>

&vecData,const std::string sign=";" )
{
 std::string::size_type fpos=0,bpos=0;
 std::string strTemp;
 while(bpos != std::string::npos && strDes.size())
 {
  bpos = strDes.find(sign,fpos);
  strTemp = strDes.substr (fpos,bpos-fpos);
  vecData.push_back (strTemp);
  fpos = bpos+1;
 }
}
开始用得挺舒服没有出现问题,但是后来出现了一个新的需求又用到这个接口,但是分隔符不再是默认的";",而是换成了下划线"_"。这时问题出现了:比如下代码
int main()
{
 std::string strDes("開关_電視臺");
 std::vector<std::string> vecTemp;
 PickUp(strDes,vecTemp,"_");
 system("pause");
 return 0;
}
粗看可能看不出什么问题,但是结果是错误的,仔细断点跟踪并网上查阅了相关资料,终于弄懂原因了。
std::string 的find函数是按照单字节查找对比的,而GBK 采用双字节表示,总体编码范围为 0x8140-FEFE,首字节在 0x81-FE 之间,尾字节在 0x40-FE 之间
而開字的内存数据为e9 5f,臺字的内存数据为c5 5f,下划线"_"的内存为5f,也就是说開字的尾字节和下划线ascii"_"是一样的,不行的是std::string 的find是采用单字节查找的,所以出现的结果是vecTemp的size()变成了4,其中包括两个空的字符串,而不是预期的结果2;而之前没有出问题是因为分隔符分号的缘故";",";"的ascii码是小于0x40的。
所以解决此种问题的办法就是分隔符应该去小于0x40也就是ascii码小于64的,至于哪些小于64就需自己去查了
或者可以自己写个单字节比较find算法.....

boost::tokenizer不错


原创粉丝点击