05_字符串处理

字符串处理

char* 窄字符

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	
	//变量c分配了1字节的存储空间,并使用16进制数 Ox41来初始化他(字符A的ASCII置为Ox41)
	char c = 'A';

	//指针变量pStr 需要4字节的存储空间,指针变量pStr 指向的字符串需要7字节的存储空间。
	const char* pStr = "Hello!";

	//字符数组 szStr 同样需要7字节的存储空间
	char szStr[] = "Hello!";


	return 0;
}

w_char* 宽字符

Unicode(一般指的是UTF-16),统一用2个字节来表达一个字符。

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	
	//大写字母L表明右边的字符使用宽字符进行存储
	//变量wc分配了2个字节的存储空间,并使用16进制数Ox0041来初始化他
	wchar_t wc = L'A';

	//指针变量pwStr 需要4字节的存储空间. 指针变量pwStr 指向的字符串需要14字节的存储空间。
	const wchar_t* pwStr = L"Hello"; 


	//字符数组szwStr 同样也需要14字节的存储空间。
	wchar_t szwStr[] = L"Hello";

	return 0;
}

利用sizeof 操作符,去查下面变量占用内存多少字节。

	char ch = 'A'; //1
	wchar_t wch = L'A'; //2
	char str[] = "C语言"; //6
	wchar_t wstr[] = L"C语言"; //8

	printf("ch=%d,wch = %d str = %d wstr = %d", 
		sizeof ch,
		sizeof wch,
		sizeof str,
		sizeof wstr);

为啥是1,2,6,8.能理解就说明你已经知道的多字节字符集存储字符和Unicode字符集存储字符的区别了。

TCHAR通用数据类型

WINDOWS在winnt.h 头文件中,定义了自己的字符和宽字符数据类型。


typedef char CHAR; //字符
#ifndef _MAC
typedef wchar_t WCHAR;   //宽字符
#else
typedef unsigned short WCHAR;  // Macintosh编译器 没有定义wchar_t数据类型,宽字符会被定义为16位整数值
#endif

winnet.h头文件还有如下定义:

在这里插入图片描述

//
// Neutral ANSI/UNICODE types and macros
//
#ifdef  UNICODE                     // r_winnt

#ifndef _TCHAR_DEFINED
typedef WCHAR TCHAR, *PTCHAR;
typedef WCHAR TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */

typedef LPWCH LPTCH, PTCH;
typedef LPCWCH LPCTCH, PCTCH;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR PCTSTR, LPCTSTR;
typedef LPUWSTR PUTSTR, LPUTSTR;
typedef LPCUWSTR PCUTSTR, LPCUTSTR;
typedef LPWSTR LP;
typedef PZZWSTR PZZTSTR;
typedef PCZZWSTR PCZZTSTR;
typedef PUZZWSTR PUZZTSTR;
typedef PCUZZWSTR PCUZZTSTR;
typedef PZPWSTR PZPTSTR;
typedef PNZWCH PNZTCH;
typedef PCNZWCH PCNZTCH;
typedef PUNZWCH PUNZTCH;
typedef PCUNZWCH PCUNZTCH;
#define __TEXT(quote) L##quote      // r_winnt 

#else   /* UNICODE */               // r_winnt

#ifndef _TCHAR_DEFINED
typedef char TCHAR, *PTCHAR;
typedef unsigned char TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */

typedef LPCH LPTCH, PTCH;
typedef LPCCH LPCTCH, PCTCH;
typedef LPSTR PTSTR, LPTSTR, PUTSTR, LPUTSTR;
typedef LPCSTR PCTSTR, LPCTSTR, PCUTSTR, LPCUTSTR;
typedef PZZSTR PZZTSTR, PUZZTSTR;
typedef PCZZSTR PCZZTSTR, PCUZZTSTR;
typedef PZPSTR PZPTSTR;
typedef PNZCH PNZTCH, PUNZTCH;
typedef PCNZCH PCNZTCH, PCUNZTCH;
#define __TEXT(quote) quote         // r_winnt

#endif /* UNICODE */    

这里UNICODE宏存在不存在决定了带T通用类型,是用的具体什么类型。一般用VS创建工程,默认使用的是Unicode字符集,我们可以在C/C++ 命令行中可以看到UNICODE_UNICODE宏被定义了。如果我们修改为多字节字符集,则可以看不到UNICODE_UNICODE宏被定义了。

在这里插入图片描述

总的来说,WINDOW程序设计,要么这个UNICODE _UNICODE 被定义,要么都不被定义。根据此宏,TCHAR被解释为CHAR(char) 或者 WCHAR(wchar_t)数据类型。

#ifdef  UNICODE                   
	#define __TEXT(quote) L##quote    
#else   /* UNICODE */              
	#define __TEXT(quote) quote   

__TEXT() ## 被称为令牌粘贴, 即当quote="Hello"L##quote就是 L"Hello".

这个宏的目的就是说,如果.cpp 文件中有以下定义:

TCHAR szBuf[] = TEXT("C语言");

如果这个项目是 Unicode字符集,则上面的定义将被解释为:

WCHAR szBuf[] = L"C语言";

又如果说这个项目是多字节字符集,则上面的定义将被解释为:

CHAR szBuf[] = "C语言";

常用字符串处理函数

查字符串长度

size_t __cdecl strlen(_In_z_ char const* _Str ); //char 类型字符串指针
size_t __cdecl wcslen( _In_z_ wchar_t const* _String ); //wchar类型字符串 指针

size_tvcruntime.h 头文件中定义如下:

// Definitions of common types

#ifdef _WIN64 // 如果编译为64位程序,那么 size_t 表示64位无符号整型
    typedef unsigned __int64 size_t;
    typedef __int64          ptrdiff_t;
    typedef __int64          intptr_t;
#else
    typedef unsigned int     size_t; //反之,如果编译为32位程序,则表示32位无符号整型
    typedef int              ptrdiff_t;
    typedef int              intptr_t;
#endif

查字符串中首次出现的字符

#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{

	TCHAR szStr[] = TEXT("WindowAPI是最为强大的编程语言!");

	LPTSTR lp = _tcschr(szStr,_T('最')); //查不到字符返回NULL,查到返回指向这个字符的地址

	setlocale(LC_ALL, "chs"); //用_tprintf函数输出中文字符的时候,需要调用本函数设置区域。

	_tprintf(_T("szStr的地址 %p lp的地址 %p\n"), szStr, lp); 
	// szStr的地址 0000006A4BBDF6C8 lp的地址 0000006A4BBDF6DC

	_tprintf(_T("%s"), lp);//最为强大的编程语言!

	return 0;
}

查子串出现的位置

如果说strSearch是str的字串,则返回strSearch在str中首次出现的地址,如果strSearch不是str的子串,就返回NULL.

 char* __CRTDECL strstr(_In_z_ char* const str, _In_z_ char const* const strSearch)
 wchar_t* __CRTDECL wcsstr(_In_z_ wchar_t* str, _In_z_ wchar_t const* strSearch)
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{

	TCHAR szStr[] = TEXT("Hello,Windows,Windows API program simple and Powerful!");

	TCHAR szStrSearch[] = TEXT("Windows");
	
	_tprintf(TEXT("%s\n"), _tcsstr(szStr, szStrSearch));
	//Windows,Windows API program simple and Powerful!

	return 0;
}

从一个字符串中查找另一个字符串中的任何字符

  char* __CRTDECL strpbrk(_In_z_ char* const str, _In_z_ char const* const _Control)
  wchar_t* __CRTDECL wcspbrk(_In_z_ wchar_t* str, _In_z_ wchar_t const* _Control)

函数在源字符串str中找出最先含有搜索字符串strCharSet中任一字符的位置并返回,如果找不到则返回NULL.

#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
	TCHAR szStr[] = TEXT("the 3 men and 2 boys ate 5 pigs");
	TCHAR szStrCharSet[] = TEXT("0123456789");
	LPTSTR lpSearch = NULL;

	_tprintf(TEXT("1:%s\n"), szStr);

	lpSearch = _tcspbrk(szStr, szStrCharSet);
	_tprintf(TEXT("2:%s\n"), lpSearch);

	lpSearch++;

	lpSearch = _tcspbrk(lpSearch, szStrCharSet);
	_tprintf(TEXT("3:%s\n"), lpSearch);

	lpSearch++;
	lpSearch = _tcspbrk(lpSearch, szStrCharSet);
	_tprintf(_T("4:%s\n"), lpSearch);


	//1:the 3 men and 2 boys ate 5 pigs
	//2:3 men and 2 boys ate 5 pigs
	//3:2 boys ate 5 pigs
	//4:5 pigs
	return 0;
}

转换字符串中的字符大小写

  //将字符串转换为大写
_ACRTIMP errno_t __cdecl _wcsupr_s(
    _Inout_updates_z_(_Size) wchar_t* str,
    _In_  size_t _Size //字符个数
);
 //把字符串转为小写
 _Check_return_wat_ _ACRTIMP errno_t __cdecl _wcslwr_s(
    _Inout_updates_z_(_SizeInWords) wchar_t* str,
    _In_        size_t   _SizeInWords //字符个数
    );

//将字符转为小写
wint_t __cdecl towlower(_In_ wint_t _C);

//将字符转为大写
wint_t __cdecl towupper(_In_ wint_t _C);
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
	TCHAR szStr[] = _T("windows是一种强大的编程语言");

	setlocale(LC_ALL, "chs");

	_tcsupr_s(szStr, _tcslen(szStr) + 1); //将字符串中的小写字符变成大写字符
	_tprintf(_T("%s\n"), szStr);
	_tcslwr_s(szStr, _tcslen(szStr) + 1); //将字符串中的大写字符变成小写字符
	_tprintf(_T("%s\n"), szStr);
    
    //输出结果:
    //WINDOWS是一种强大的编程语言
	 //windows是一种强大的编程语言
	return 0;
}
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
	TCHAR szStr[] = _T("Hello,Windows,Windows API program simple and 强大!");

	//把每一个字符转为小写
	int count = _tcslen(szStr);
	for (size_t i = 0; i < count; i++)
	{
		szStr[i] = _totlower(szStr[i]);
	}
	setlocale(LC_ALL, "chs");
	_tprintf(_T("%s\n"), szStr);
	
	//将字符串转为大写
	for (size_t i = 0; i < count; i++)
	{
		szStr[i] = _totupper(szStr[i]);
	}
	_tprintf(_T("%s\n"), szStr);


	return 0;
}

字符串拼接

    _ACRTIMP errno_t __cdecl strcat_s(
        _Inout_updates_z_(_SizeInBytes) char*       _Destination,
        _In_     rsize_t     _SizeInBytes, //目标字符串缓冲区大小,字节单位
        _In_z_  char const* _Source
        );
    _ACRTIMP errno_t __cdecl wcscat_s(
        _Inout_updates_z_(_SizeInWords) wchar_t* _Destination,
        _In_ rsize_t _SizeInWords,//目标缓存区大小,字符单位
        _In_z_ wchar_t const* _Source
        );
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
	TCHAR szStrDest[64] = TEXT("WindowsAPI");
	TCHAR szStrSour[] = TEXT("是一种强大的编程语言!");
	_tcscat_s(szStrDest, _countof(szStrDest), szStrSour); //注意,这是Uncoide字符集,使用的是wcscat_s,第二个参数注入字符个数。用_countof求算,得64个字符空间。
    //如果用sizeof 则会得到128个字节。
    //如果是多字节字符集得化,_countof求算也是64个字符空间,而sizeof 求算 会得到64字节空间。
    //所以用_countof 可以兼容两个字符集,而sizeof 不行!
	 setlocale(LC_ALL, "chs");
	_tprintf(TEXT("%s\n"), szStrDest);
}

建议直接用::StringCchCat() 替代使用 _tcscat_s()

#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{
	TCHAR szStrDest[64] = TEXT("WindowsAPI");
	TCHAR szStrSour[] = TEXT("是一种强大的编程语言!");
	::StringCchCat(szStrDest, _countof(szStrDest), szStrSour);
	setlocale(LC_ALL, "chs");
	_tprintf(TEXT("%s\n"), szStrDest);
}

字符串复制

    _ACRTIMP errno_t __cdecl strcpy_s(
        _Out_writes_z_(_SizeInBytes) char*       _Destination,
        _In_          rsize_t     _SizeInBytes,//目标缓冲区的大小,字节单位
        _In_z_          char const* _Source 
        );

    _ACRTIMP errno_t __cdecl wcscpy_s(
        _Out_writes_z_(_SizeInWords) wchar_t* _Destination,
        _In_ rsize_t _SizeInWords,//目标缓冲区的大熊啊,字符单位。
        _In_z_ wchar_t const* _Source
        );
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
	
	TCHAR szStrDest[64];
	TCHAR szStrSour[] = _T("WindowsAPI是一种强大的编程语言!");
	_tcscpy_s(szStrDest, _countof(szStrDest), szStrSour);
	setlocale(LC_ALL, "chs");
	_tprintf(_T("%s\n"), szStrDest);//WindowsAPI是一种强大的编程语言!
}

建议直接用::StringCchCopy() 替代使用_tcscpy_s().

#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{
	
	TCHAR szStrDest[64];
	TCHAR szStrSour[] = _T("WindowsAPI是一种强大的编程语言!");
	::StringCchCopy(szStrDest, _countof(szStrDest), szStrSour);
	setlocale(LC_ALL, "chs");
	_tprintf(_T("%s\n"), szStrDest);//WindowsAPI是一种强大的编程语言!
}

字符串比较

比的是每一个字符的ASCII码,两个字符串相等返回0.

int __cdecl strcmp(
    _In_z_ char const* _Str1,
    _In_z_ char const* _Str2
    );
_ACRTIMP int __cdecl wcscmp(
    _In_z_ wchar_t const* _String1,
    _In_z_ wchar_t const* _String2
    );
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{
	TCHAR szStr1[] = TEXT("ABCDE"); //E的ASCII 为Ox45
	TCHAR szStr2[] = TEXT("ABCDe"); //e的ASCII 为Ox65

	int n = _tcscmp(szStr1, szStr2);

	setlocale(LC_ALL, "chs");
	if (n > 0)
	{
		_tprintf(_T("szStr1 大于 szStr2\n"));
	}
	else if (n == 0)
	{
		_tprintf(_T("szStr1 等于 szStr2\n"));
	}
	else // n < 0
	{
		_tprintf(_T("szStr1 小于 szStr2\n"));
	}
	//szStr1 小于 szStr2

	//忽略大小写比较
	int n1 = _tcsicmp(szStr1, szStr2);
	if (n1 > 0)
	{
		_tprintf(_T("szStr1 大于 szStr2\n"));
	}
	else if (n1 == 0)
	{
		_tprintf(_T("szStr1 等于 szStr2\n"));
	}
	else // n < 0
	{
		_tprintf(_T("szStr1 小于 szStr2\n"));
	}
	//szStr1 等于 szStr2

}

带时区的字符串比较

默认情况下,如果没有这句设置中文区域设置 setlocale(LC_ALL, "chs"); 程序则默认执行setlocale(LC_ALL, "C");

如果我设置了中文区域设置和不设置中文区域设置 _tcscoll() 比较的结果不同,究其理由是_tcscoll() 带时区特征,如为中文区域,则中文字符按照拼音进行比较(和操作系统有关,WINDOW操作系统还可以按照笔划排序)

#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{

    
    setlocale(LC_ALL, "chs");   // LC_ALL包括LC_COLLATE
    TCHAR szStr1[] = TEXT("我爱老王");
    // Unicode:11 62 31 72 01 80 8B 73 00 00  多字节:CE D2 B0 AE C0 CF CD F5 00
    TCHAR szStr2[] = TEXT("我是老王");
    // Unicode:11 62 2F 66 01 80 8B 73 00 00  多字节:CE D2 CA C7 C0 CF CD F5 00

    int n = _tcscmp(szStr1, szStr2);
    if (n > 0)
        _tprintf(TEXT("szStr1 > szStr2\n"));
    else if (n == 0)
        _tprintf(TEXT("szStr1 == szStr2\n"));
    else
        _tprintf(TEXT("szStr1 < szStr2\n"));
    //

    n = _tcscoll(szStr1, szStr2);
    if (n > 0)
        _tprintf(TEXT("szStr1 > szStr2\n"));
    else if (n == 0)
        _tprintf(TEXT("szStr1 == szStr2\n"));
    else
        _tprintf(TEXT("szStr1 < szStr2\n"));
    //

}

在这里插入图片描述

分割字符串

   _ACRTIMP char*  __cdecl strtok_s(
       _Inout_opt_z_                 char*       strToken,//要分割的字符串
       _In_z_                        char const* _Delimiter, //风格符字符串,分隔符字符串中每个字符均为分割符
       _Inout_ _Deref_prepost_opt_z_ char**      _Context //返回strToken中剩余没有被分割的部分,提供一个字符串的指针的指针即可。
       );
   _ACRTIMP wchar_t* __cdecl wcstok_s(
       _Inout_opt_z_                 wchar_t*       _String,
       _In_z_                        wchar_t const* _Delimiter,
       _Inout_ _Deref_prepost_opt_z_ wchar_t**      _Context
       );
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
#include<vector>
int main()
{
	std::vector<LPTSTR> vecLpStrs;
	TCHAR strToken[] = TEXT("120~130~150~200~250");
	TCHAR strDelimit[] = TEXT("~");
	LPTSTR lpToken = NULL; //被分割除部分的指针
	LPTSTR lpTokenNext = NULL;  //剩余未被分割部分的指针

	lpToken = _tcstok_s(strToken, strDelimit, &lpTokenNext);
	
	while (lpToken != NULL)
	{
		vecLpStrs.push_back(lpToken);
		lpToken = _tcstok_s(NULL, strDelimit, &lpTokenNext);
	}//把分割出来的结果放到容器中

	setlocale(LC_ALL, "chs");
	for (size_t i = 0; i < vecLpStrs.size(); i++)
	{
		_tprintf(_T("%s\n"), vecLpStrs[i]);
	}
	//120
	//130
	//150
	//200
	//250
}
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
#include<vector>
#include<iostream>
int main()
{
	std::vector<LPTSTR> vecLpStrs;
	TCHAR strToken[] = TEXT("4.78~12.5!0.01");
	TCHAR strDelimit[] = TEXT("~!"); //~ 和 ! 都是分割符
	LPTSTR lpToken = NULL; //被分割除部分的指针
	LPTSTR lpTokenNext = NULL;  //剩余未被分割部分的指针

	TCHAR step[50] = { 0 };
	TCHAR range_low[50] = { 0 };
	TCHAR range_high[50] = { 0 };

	lpToken = _tcstok_s(strToken, strDelimit, &lpTokenNext);
	::StringCchCopy(range_low, _countof(range_low), lpToken);



	lpToken = _tcstok_s(NULL, strDelimit, &lpTokenNext);
	::StringCchCopy(range_high, _countof(range_high), lpToken);
	::StringCchCopy(step, _countof(step), lpTokenNext);


	setlocale(LC_ALL, "chs");
	_tprintf(_T("step = %s\n"), step);
	_tprintf(_T("range_low = %s\n"), range_low);
	_tprintf(_T("range_high = %s\n"), range_high);
	//step = 0.01
	//range_low = 4.78
	//range_high = 12.5

}

字符串快速排序

#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
#include<vector>
#include<iostream>


int main()
{
	
     LPCTSTR arrStr[] = {
      TEXT("架构风格之资源管理.AVI"),
      TEXT("模块化之合理内聚.AVI"),
      TEXT("总结.AVI"),
      TEXT("模块化之管理依赖.AVI"),
      TEXT("系统架构设计概述.AVI"),
      TEXT("架构风格之分布式.AVI")
    };

   

     qsort(arrStr, _countof(arrStr), sizeof(LPTSTR), [](const void* arg1, const void* arg2)->int 
         {
             return _tcscoll(*(LPTSTR*)arg2 ,*(LPTSTR*)arg1);
         });

     setlocale(LC_ALL,"chs");
     for (int i = 0; i < _countof(arrStr); i++)
         _tprintf(TEXT("%s\n"), arrStr[i]); 

     //系统架构设计概述.AVI
     //模块化之管理依赖.AVI
     //模块化之合理内聚.AVI
     //架构风格之资源管理.AVI
     //架构风格之分布式.AVI
     //总结.AVI
}

字符串与数值型相互转化

字符串转数值

double    __cdecl atof   (_In_z_ char const* _String);
double __cdecl _wtof( _In_z_ wchar_t const* _String ); // 字符串 转双精度浮点型

int       __cdecl atoi   (_In_z_ char const* _String);
int __cdecl _wtoi(_In_z_ wchar_t const* _String ); //字符串转整型

 long      __cdecl atol   (_In_z_ char const* _String);
long __cdecl _wtol(_In_z_ wchar_t const* _String ); //字符串转长整型

__int64   __cdecl _atoi64(_In_z_ char const* _String); //字符串转64位整型
long long __cdecl _wtoll(_In_z_ wchar_t const* _String); //字符串转long long 长整型

z_ char const* _String);
double __cdecl _wtof( _In_z_ wchar_t const* _String ); // 字符串 转双精度浮点型

int       __cdecl atoi   (_In_z_ char const* _String);
int __cdecl _wtoi(_In_z_ wchar_t const* _String ); //字符串转整型

 long      __cdecl atol   (_In_z_ char const* _String);
long __cdecl _wtol(_In_z_ wchar_t const* _String ); //字符串转长整型

__int64   __cdecl _atoi64(_In_z_ char const* _String); //字符串转64位整型
long long __cdecl _wtoll(_In_z_ wchar_t const* _String); //字符串转long long 长整型

上述函数,并不要求字符串必须是一个数值形式,比如说某个字符串str是"-1.23456你好,老王",调用_ttof(str)函数返回的结果是double型的-1.23456,函数会跳过前面的空格字符,知道遇到数字或者正负号才开始转换,知道出现非数字或者字符串结束标志时,才结束转换。并把转换后的结果返回。你要相信,人家写库的人,你会怎么调用的情况都想过了的~~~

当然啊,如果开头部分就是不可转换字符,比如说"你好-1.23456你好,老王",则函数返回0.0.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值