注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

_

_

 
 
 

日志

 
 

标准C++的字符串操作  

2013-05-06 22:04:38|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
标准C++的字符串操作

2011-02-24 16:021005人阅读评论(0)收藏举报

c++stringbasiciostokenize语言

目录(?)[+]

  1. 字符串的format
  2. 各种类型字符串间的转换
  3. Trim操作
  4. 字符串的分词
  5. 字符串的hash操作

使用过MFC会发现CString比std::string好用,而使用过C#,会发现System.String用起来更爽。标准C++是否也可以得心应手地处理字符串呢?答案是肯定的,我接下来 会介绍如何实现以下操作

  1. 字符串的format
  2. char*, wchar_t*, _bstr_t, CComBSTR, basic_string, System.String间的转换
  3. Trim操作
  4. 字符串的分词

  5. 字符串与各种类型间的转换

  6. 字符串的hash操作

  • 字符串的format

CString与System.String都与Format方法,在标准C++如何实现这样的功能呢?有两种方法:

  1. 使用boost的Format方法
  2. 使用basic_stringstream

下面我就使用basic_stringstream进行format给出示例:

[cpp] view plaincopyprint?

  1. #include <sstream>
  2. #include <iostream>
  3. #include <iomanip>
  4. using namespace std;
  5. int _tmain(int argc, _TCHAR* argv[])
  6. {
  7. basic_stringstream<char> ss;
  8. int x = 30;
  9. float y = 0.00000009;
  10. float z = -9.9;
  11. ss << x << ' ' << y << z << endl; //按十进制输出
  12. cout << "按十进制输出" << endl;
  13. cout << ss.str() << endl;
  14. ss.rdbuf()->str("");
  15. ss << hex << x << ' ' << y << z << endl; //按十六进制输出
  16. cout << "按十六进制输出" << endl;
  17. cout << ss.str() << endl;
  18. ss.rdbuf()->str("");
  19. //设置基指示符,强制在正数前加+号,强制显示小数点后的无效0, 仍按十六机制输出
  20. ss << setiosflags(ios::showbase | ios::showpos | ios::showpoint) << x << ' ' << y << z << endl;
  21. cout << "设置基指示符,强制在正数前加+号, 仍按十六机制输出" << endl;
  22. cout << ss.str() << endl;
  23. ss.rdbuf()->str("");
  24. //取消设置基指示符与强制在正数前加+号,取消强制显示小数点后的无效0, 仍按十六进制输出
  25. ss << resetiosflags(ios::showbase | ios::showpos | ios::showpoint) << x << ' ' << y << z << endl;
  26. cout << "取消设置基指示符与强制在正数前加+号,取消强制显示小数点后的无效0, 仍按十六进制输出" << endl;
  27. cout << ss.str() << endl;
  28. ss.rdbuf()->str("");
  29. //设置基指示符,科学计数法,数值中的字母大写输出,十六进制输出
  30. ss << setiosflags(ios::showbase | ios::uppercase | ios::scientific) << x << ' ' << y << z <<endl;
  31. cout << "设置基指示符,科学计数法,数值中的字母大写输出,十六进制输出" << endl;
  32. cout << ss.str() << endl;
  33. ss.rdbuf()->str("");
  34. //仍是十六进制输出,取消基指示符与数值中的字母大写输出,取消科学计数法
  35. ss << resetiosflags(ios::showbase | ios::uppercase) << x << ' ' << y << z << endl;
  36. cout << "仍是十六进制输出,取消基指示符与数值中的字母大写输出,取消科学计数法" << endl;
  37. cout << ss.str() << endl;
  38. ss.rdbuf()->str("");
  39. ss << setiosflags(ios::fixed) << x << ' ' << y << ' ' << z << endl; //按固定十进制输出浮点数
  40. ss << "固定十进制输出浮点数" << endl;
  41. ss.rdbuf()->str("");
  42. ss << resetiosflags(ios::fixed) << x << ' ' << y << ' ' << z << endl; //取消按固定十进制输出浮点数
  43. ss << "取消按固定十进制输出浮点数" << endl;
  44. ss.rdbuf()->str("");
  45. ss << setprecision(18) << x << ' ' << y << ' ' << ' ' << endl; //设置精度为18,正常为6
  46. ss << "设置精度为18,正常为6" << endl;
  47. ss.rdbuf()->str("");
  48. ss << dec << x << ' ' << y << endl; //按十进制输出
  49. cout << "按十进制输出" << endl;
  50. cout << ss.str() << endl;
  51. ss.rdbuf()->str("");
  52. /*要输出如下的文字
  53. 第一章
  54. 1.1 什么是C语言...........................1
  55. 1.11 C语言的历史..........................58
  56. 第二章
  57. */
  58. ss = basic_stringstream<char>();
  59. ss << "第一章" << endl << " ";
  60. ss << setiosflags(ios::left) << setw(7); //设置宽度为7(只对下条输出有用),left对齐方式
  61. ss << "1.1" << "什么是C语言";
  62. ss << resetiosflags(ios::left); //取消对齐方式
  63. ss << setfill('.') << setw(30) << 1 << endl; //宽度为30(只对下条输出有用),填充为'.'输出
  64. ss << setfill(' '); //恢复填充为空格
  65. ss << " ";
  66. ss << setw(10)<<setiosflags(ios::left); //设置宽度为7(只对下条输出有用),left对齐方式
  67. ss << "1.11" << "C语言的历史";
  68. ss << resetiosflags(ios::left); //取消对齐方式
  69. ss << setfill('.') << setw(7) << 58 << endl; //宽度为30(只对下条输出有用),填充为’.’输出
  70. ss << setfill(' ') << "第二章" << endl;
  71. cout << ss.str();
  72. return 0;
  73. }

#include <sstream> #include <iostream> #include <iomanip> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { basic_stringstream<char> ss; int x = 30; float y = 0.00000009; float z = -9.9; ss << x << ' ' << y << z << endl; //按十进制输出 cout << "按十进制输出" << endl; cout << ss.str() << endl; ss.rdbuf()->str(""); ss << hex << x << ' ' << y << z << endl; //按十六进制输出 cout << "按十六进制输出" << endl; cout << ss.str() << endl; ss.rdbuf()->str(""); //设置基指示符,强制在正数前加+号,强制显示小数点后的无效0, 仍按十六机制输出 ss << setiosflags(ios::showbase | ios::showpos | ios::showpoint) << x << ' ' << y << z << endl; cout << "设置基指示符,强制在正数前加+号, 仍按十六机制输出" << endl; cout << ss.str() << endl; ss.rdbuf()->str(""); //取消设置基指示符与强制在正数前加+号,取消强制显示小数点后的无效0, 仍按十六进制输出 ss << resetiosflags(ios::showbase | ios::showpos | ios::showpoint) << x << ' ' << y << z << endl; cout << "取消设置基指示符与强制在正数前加+号,取消强制显示小数点后的无效0, 仍按十六进制输出" << endl; cout << ss.str() << endl; ss.rdbuf()->str(""); //设置基指示符,科学计数法,数值中的字母大写输出,十六进制输出 ss << setiosflags(ios::showbase | ios::uppercase | ios::scientific) << x << ' ' << y << z <<endl; cout << "设置基指示符,科学计数法,数值中的字母大写输出,十六进制输出" << endl; cout << ss.str() << endl; ss.rdbuf()->str(""); //仍是十六进制输出,取消基指示符与数值中的字母大写输出,取消科学计数法 ss << resetiosflags(ios::showbase | ios::uppercase) << x << ' ' << y << z << endl; cout << "仍是十六进制输出,取消基指示符与数值中的字母大写输出,取消科学计数法" << endl; cout << ss.str() << endl; ss.rdbuf()->str(""); ss << setiosflags(ios::fixed) << x << ' ' << y << ' ' << z << endl; //按固定十进制输出浮点数 ss << "固定十进制输出浮点数" << endl; ss.rdbuf()->str(""); ss << resetiosflags(ios::fixed) << x << ' ' << y << ' ' << z << endl; //取消按固定十进制输出浮点数 ss << "取消按固定十进制输出浮点数" << endl; ss.rdbuf()->str(""); ss << setprecision(18) << x << ' ' << y << ' ' << ' ' << endl; //设置精度为18,正常为6 ss << "设置精度为18,正常为6" << endl; ss.rdbuf()->str(""); ss << dec << x << ' ' << y << endl; //按十进制输出 cout << "按十进制输出" << endl; cout << ss.str() << endl; ss.rdbuf()->str(""); /*要输出如下的文字第一章 1.1 什么是C语言...........................1 1.11 C语言的历史..........................58 第二章 */ ss = basic_stringstream<char>(); ss << "第一章" << endl << " "; ss << setiosflags(ios::left) << setw(7); //设置宽度为7(只对下条输出有用),left对齐方式 ss << "1.1" << "什么是C语言"; ss << resetiosflags(ios::left); //取消对齐方式 ss << setfill('.') << setw(30) << 1 << endl; //宽度为30(只对下条输出有用),填充为'.'输出 ss << setfill(' '); //恢复填充为空格 ss << " "; ss << setw(10)<<setiosflags(ios::left); //设置宽度为7(只对下条输出有用),left对齐方式 ss << "1.11" << "C语言的历史"; ss << resetiosflags(ios::left); //取消对齐方式 ss << setfill('.') << setw(7) << 58 << endl; //宽度为30(只对下条输出有用),填充为’.’输出 ss << setfill(' ') << "第二章" << endl; cout << ss.str(); return 0; }

  • 各种类型字符串间的转换

介绍字符串类型char*,wchar_t*,_bstr_t,CComBSTR,CString,basic_string和System.String间的相互转换

pin_ptr<const wchar_t> addr. wch

char*

wchar_t*

_bstr_t

CComBSTR

CString

basic_string

System.String

char*

----

----

mbstowcs_s

_bstr_t(char*)

CComBSTR(char*)

CString(char*)

string(char*)

gcnew String(char*)

wchar_t*

----

wcstombs_s

----

_bstr_t(wchar_t*)

CComBSTR(wchar_t*)

CString(wchar_t*)

wstring(wchar_t*)

gcnew String(wchar_t*)

_bstr_t

----

(char*)

(wchar_t*)

----

->char*->CComBSTR

.GetBSTR()->CString(BSTR&)

->char*->string(char*)

char*->gcnew String(char*)

CComBSTR

----

->CW2A->strcpy_s

wcscpy_s

_bstr_t()

----

CString()

wstring()

gcnew String()

CStringA

----

strcpy_s

mbstowcs_s

_bstr_t()

CComBSTR()

----

string()

gcnew String()

CStringW

----

wcstombs_s

wcscpy_s

_bstr_t()

CComBSTR()

----

wstring()

gcnew String()

string

----

.c_str()->strcpy_s

mbstowcs_s

.c_str()->_bstr_t()

.c_str()->CComBSTR()

CString()

----

.c_str()->gcnew String()

System.String

PtrToStringChars

->wch ->wcstombs_s

->wch->wcscpy_s

->wch->_bstr_t()

->wch->CComBSTR()

->wch->CString()

->wch->wstring()

----

具体内容请查看:http://msdn.microsoft.com/en-us/library/ms235631.aspx

  • Trim操作

标准C++中没有提供Trim操作的方法,可以使用boost 的trim实现方案(http://www.boost.org/doc/libs/1_38_0/doc/html/string_algo/usage.html#id4001757 ),如下代码所示:

[cpp] view plaincopyprint?

  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include <string>
  4. #include <boost/algorithm/string/trim.hpp>
  5. using namespace std;
  6. using namespace boost;
  7. int _tmain(int argc, _TCHAR* argv[])
  8. {
  9. setlocale(LC_ALL, "chs");
  10. string str1=" 杨俊hello world! ";
  11. string str2=trim_left_copy(str1); //去除字符串最左端的空白符
  12. string str3=trim_right_copy(str2); //去除字符串最右端得空白符
  13. trim(str1); //去除字符串左右两端的空白符
  14. return 0;
  15. }

#include "stdafx.h" #include <iostream> #include <string> #include <boost/algorithm/string/trim.hpp> using namespace std; using namespace boost; int _tmain(int argc, _TCHAR* argv[]) { setlocale(LC_ALL, "chs"); string str1=" 杨俊hello world! "; string str2=trim_left_copy(str1); //去除字符串最左端的空白符 string str3=trim_right_copy(str2); //去除字符串最右端得空白符 trim(str1); //去除字符串左右两端的空白符 return 0; }

但是,我要提醒一点,boost的trim_left_copy, trim_right_copy以及trim没有支持多字节字符(或许是因为写这个实现的不是中国人)。因而上面代码并不能得到预期的效果(如果将string改为wstring可以得到正确的结果)。CString的Trim也不能支持多字节字符,所以说,大家写程序,字符串最好还是使用宽字符,不然就转为宽字符后再做处理。下面贴出我写的Trim函数(宽字节版本):

[cpp] view plaincopyprint?

  1. //去除左边的空白符
  2. wstring TrimLeft(const wstring str)
  3. {
  4. int ib = 0;
  5. int nlen = str.length();
  6. for (int i = 0; i < nlen; i++)
  7. {
  8. if (!iswspace(str[i]))
  9. {
  10. ib = i;
  11. break;
  12. }
  13. }
  14. return str.substr(ib);
  15. }
  16. //去除右边的空白符
  17. wstring TrimRight(const wstring str)
  18. {
  19. int ie = string::npos;
  20. int nlen = str.length();
  21. for (int i = nlen - 1; i >= 0; i--)
  22. {
  23. if (!iswspace(str[i]))
  24. {
  25. ie = i;
  26. break;
  27. }
  28. }
  29. return str.substr(0, ie+1);
  30. }
  31. //去除两边的空白符
  32. wstring Trim(const wstring str)
  33. {
  34. return TrimLeft(TrimRight(str));
  35. }

//去除左边的空白符 wstring TrimLeft(const wstring str) { int ib = 0; int nlen = str.length(); for (int i = 0; i < nlen; i++) { if (!iswspace(str[i])) { ib = i; break; } } return str.substr(ib); } //去除右边的空白符 wstring TrimRight(const wstring str) { int ie = string::npos; int nlen = str.length(); for (int i = nlen - 1; i >= 0; i--) { if (!iswspace(str[i])) { ie = i; break; } } return str.substr(0, ie+1); } //去除两边的空白符 wstring Trim(const wstring str) { return TrimLeft(TrimRight(str)); }

多字节版本下的Trim方法:

[cpp] view plaincopyprint?

  1. //返回-1表示出错
  2. unsigned int GetFirstCharactor(const char* lpstr)
  3. {
  4. //这一句话是为了底下tmp[0]<<8和tmp[1]不带符号。
  5. const unsigned char* tmp = (const unsigned char*)(lpstr);
  6. switch(_mbclen((const unsigned char*)(lpstr)))
  7. {
  8. case 2:
  9. {
  10. return ((tmp[0]<<8)|tmp[1]);
  11. }
  12. break;
  13. case 1:
  14. {
  15. return tmp[0];
  16. }
  17. break;
  18. case 0:
  19. {
  20. return -1;
  21. }
  22. break;
  23. default:
  24. return -1;
  25. }
  26. }
  27. string TrimLeft(string str)
  28. {
  29. const char* tmp = str.c_str();
  30. int nlen = str.length();
  31. int nb = 0;
  32. for(int i = 0; i < nlen; i += _mbclen((const unsigned char*)(tmp) + i))
  33. {
  34. unsigned int c = GetFirstCharactor(tmp + i);
  35. if (c == -1)
  36. {
  37. return string();
  38. }
  39. if (!_ismbcspace(c))
  40. {
  41. nb = i;
  42. break;
  43. }
  44. }
  45. return str.substr(nb);
  46. }
  47. string TrimRight(string str)
  48. {
  49. if (str.empty())
  50. {
  51. return string();
  52. }
  53. const char* lpBegin = str.c_str();
  54. const char* lpTmp = lpBegin + str.length();
  55. int ne = string::npos;
  56. for (int i = _mbstrlen(str.c_str())-1; i >= 0; i--)
  57. {
  58. lpTmp = (const char*)_mbsdec((const unsigned char*)(lpBegin), (const unsigned char*)(lpTmp));
  59. unsigned int c = GetFirstCharactor(lpTmp);
  60. if (c == -1)
  61. {
  62. return string();
  63. }
  64. if (!_ismbcspace(c))
  65. {
  66. break;
  67. }
  68. }
  69. return str.substr(0, lpTmp-lpBegin+1);
  70. }
  71. string Trim(string str)
  72. {
  73. return TrimLeft(TrimRight(str));
  74. }

//返回-1表示出错 unsigned int GetFirstCharactor(const char* lpstr) { //这一句话是为了底下tmp[0]<<8和tmp[1]不带符号。 const unsigned char* tmp = (const unsigned char*)(lpstr); switch(_mbclen((const unsigned char*)(lpstr))) { case 2: { return ((tmp[0]<<8)|tmp[1]); } break; case 1: { return tmp[0]; } break; case 0: { return -1; } break; default: return -1; } } string TrimLeft(string str) { const char* tmp = str.c_str(); int nlen = str.length(); int nb = 0; for(int i = 0; i < nlen; i += _mbclen((const unsigned char*)(tmp) + i)) { unsigned int c = GetFirstCharactor(tmp + i); if (c == -1) { return string(); } if (!_ismbcspace(c)) { nb = i; break; } } return str.substr(nb); } string TrimRight(string str) { if (str.empty()) { return string(); } const char* lpBegin = str.c_str(); const char* lpTmp = lpBegin + str.length(); int ne = string::npos; for (int i = _mbstrlen(str.c_str())-1; i >= 0; i--) { lpTmp = (const char*)_mbsdec((const unsigned char*)(lpBegin), (const unsigned char*)(lpTmp)); unsigned int c = GetFirstCharactor(lpTmp); if (c == -1) { return string(); } if (!_ismbcspace(c)) { break; } } return str.substr(0, lpTmp-lpBegin+1); } string Trim(string str) { return TrimLeft(TrimRight(str)); }

  • 字符串的分词

标准c++没有CString的Tokenize——补充一句,同样的问题,CString不支持MBCS,不信,把中文的标点符号作为分隔符试试,它马上就SB了,不要嫌我烦啊,强烈呼吁同胞在代码中使用宽字符;也没有System.String的Split,那如何对字符串进行分词呢,可以使用boost库或是其他第三方库(这些老外写的库,是否支持MBCS,很令人怀疑,http://ishare.iask.sina.com.cn/f/5164324.html 这是一个朋友总结的字符串分词方法),不过我推荐是使用_tcstok_s,也可以使用轻量级的方法,那就是basic_stringstream与getline的情侣组合。下面给出示例代码:

[cpp] view plaincopyprint?

  1. #include <stdio.h>
  2. #include <tchar.h>
  3. #include <string>
  4. #include <iostream>
  5. #include <sstream>
  6. using namespace std;
  7. int _tmain(int argc, _TCHAR* argv[])
  8. {
  9. /*使用_tcstok_s进行字符串分隔
  10. if _UNICODE&_MBCS not defined
  11. _tcstok_s => strtok_s
  12. if _MBCS defined
  13. _tcstok_s => _mbstok_s
  14. if _UNICODE defined
  15. _tcstok_s => wcstok_s
  16. _tcstok_s 会修改源字符串,将里面的分隔符(分隔符可以为单字节,多字节,或是宽字节)替换为/0
  17. */
  18. char* pold = setlocale(LC_ALL, "chs");
  19. cout<< _T("_tcstok_s") <<endl;
  20. char str[] = ";杨俊,杜俊;杨辉和杨钊";
  21. basic_stringstream<TCHAR> ss(str);
  22. TCHAR* outer = NULL;
  23. TCHAR* pOut = NULL;
  24. for (outer = _tcstok_s(str, _T(",;和"), &pOut); NULL != outer; outer = _tcstok_s(NULL, ",;和", &pOut))
  25. {
  26. cout << outer << endl;
  27. }
  28. cout << endl;
  29. cout << "getline" << endl;
  30. basic_string<char> s;
  31. while (getline(ss, s, _T(';')))
  32. {
  33. cout << s << endl;
  34. }
  35. return 0;
  36. }

#include <stdio.h> #include <tchar.h> #include <string> #include <iostream> #include <sstream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { /*使用_tcstok_s进行字符串分隔 if _UNICODE&_MBCS not defined _tcstok_s => strtok_s if _MBCS defined _tcstok_s => _mbstok_s if _UNICODE defined _tcstok_s => wcstok_s _tcstok_s 会修改源字符串,将里面的分隔符(分隔符可以为单字节,多字节,或是宽字节)替换为/0 */ char* pold = setlocale(LC_ALL, "chs"); cout<< _T("_tcstok_s") <<endl; char str[] = ";杨俊,杜俊;杨辉和杨钊"; basic_stringstream<TCHAR> ss(str); TCHAR* outer = NULL; TCHAR* pOut = NULL; for (outer = _tcstok_s(str, _T(",;和"), &pOut); NULL != outer; outer = _tcstok_s(NULL, ",;和", &pOut)) { cout << outer << endl; } cout << endl; cout << "getline" << endl; basic_string<char> s; while (getline(ss, s, _T(';'))) { cout << s << endl; } return 0; }

输出结果为:

_tcstok_s

杨俊

杜俊

杨辉

杨钊

getline

杨俊,杜俊

杨辉和杨钊

需要提出几点:_tcstok_s是支持MBCS的,它会改变源字符串;getline方法,一次只能指定一个分隔符,而且不支持MBCS。

字符串的hash操作

[cpp] view plaincopyprint?

  1. typedef const TCHAR* pctstr_t;
  2. typedef basic_string<TCHAR> tstring;
  3. tstring HashLongFileName(pctstr_t lpcszFileName)
  4. {
  5. size_t uLen = _tcslen(lpcszFileName);
  6. ptstr_t pszTmp = _tcsdup(lpcszFileName);
  7. std::locale loc ("chs");
  8. long nHash = std::use_facet<std::collate<char_t>>(loc).hash(pszTmp, &pszTmp[uLen-1]);
  9. std::basic_stringstream<char_t> ss;
  10. ss << nHash;
  11. free(pszTmp);
  12. return ss.str();
  13. }
  评论这张
 
阅读(841)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017