C/C++字符串处理相关
总览
< cctype >头文件的函数
< cctype >头文件中声明了一系列用于字符处理的函数
http://www.cplusplus.com/reference/cctype/
判断字符是否属于某一类
函数 | 功能 |
---|---|
int isalnum ( int c ); | 检查字符是否为字母或数字 |
int isalpha ( int c ); | 检查字符是否为字母 |
int isblank ( int c ); | 检查字符是否为空白符(’ ’ ‘\t’) |
int iscntrl ( int c ); | 检查字符是否为控制字符 |
int isdigit ( int c ); | 检查字符是否为十进制数字 |
int isgraph ( int c ); | 检查字符是否具有图形表示 |
int islower ( int c ); | 检查字符是否为小写字母 |
int isprint ( int c ); | 检查字符是否可打印 |
int ispunct ( int c ); | 检查字符是否为标点符号 |
int isspace ( int c ); | 检查字符是否为white-space (’ ’ ‘\t’ ‘\n’ ‘\v’ ‘\f’ ‘\r’) |
int isupper ( int c ); | 检查字符是否为大写字母 |
int isxdigit ( int c ); | 检查字符是否为十六进制数字 |
字符转换函数
函数 | 功能 |
---|---|
int tolower ( int c ); | 将大写字母转换为小写 |
int toupper ( int c ); | 将小写字母转换为大写 |
头文件内< cstring >的函数
<cstring>
http://www.cplusplus.com/reference/string/
Copying: | |
---|---|
memcpy | Copy block of memory (function ) |
memmove | Move block of memory (function ) |
strcpy | Copy string (function ) |
strncpy | Copy characters from string (function ) |
strcpy把 src 所指向的字符串复制到 dest。
char *strcpy(char *dest, const char *src);
[参数]
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
[返回值]
该函数返回一个指向最终的目标字符串 dest 的指针。
Concatenation: | |
---|---|
strcat | Concatenate strings (function ) |
strncat | Append characters from string (function ) |
Comparison: | |
---|---|
memcmp | Compare two blocks of memory (function ) |
strcmp | Compare two strings (function ) |
strcoll | Compare two strings using locale (function ) |
strncmp | Compare characters of two strings (function ) |
strxfrm | Transform string using locale (function ) |
Searching: | |
---|---|
memchr | Locate character in block of memory (function ) |
strchr | Locate first occurrence of character in string (function ) |
strcspn | Get span until character in string (function ) |
strpbrk | Locate characters in string (function ) |
strrchr | Locate last occurrence of character in string (function ) |
strspn | Get span of character set in string (function ) |
strstr | Locate substring (function ) |
strtok | Split string into tokens (function ) |
Other: | |
---|---|
memset | Fill block of memory (function ) |
strerror | Get pointer to error message string (function ) |
strlen | Get string length (function ) |
strlen()函数用来计算字符串的长度,其原型为:
unsigned int strlen (char *s);
【参数说明】s为指定的字符串。
strlen()用来计算指定的字符串s 的长度,不包括结束字符"\0"。
【返回值】返回字符串s 的字符数。
头文件< string >中的函数
<string>
http://www.cplusplus.com/reference/string/
Convert from strings | |
---|---|
stoi | Convert string to integer (function template ) |
stol | Convert string to long int (function template ) |
stoul | Convert string to unsigned integer (function template ) |
stoll | Convert string to long long (function template ) |
stoull | Convert string to unsigned long long (function template ) |
stof | Convert string to float (function template ) |
stod | Convert string to double (function template ) |
stold | Convert string to long double (function template ) |
Convert to strings | |
---|---|
to_string | Convert numerical value to string (function ) |
to_wstring | Convert numerical value to wide string (function ) |
为什么size_t重要?
ASCII字符与转义字符
http://c.biancheng.net/cpp/html/2890.html
转义字符以\或者\x开头,以\开头表示后跟八进制形式的编码值,以\x开头表示后跟十六进制形式的编码值。对于转义字符来说,只能使用八进制或者十六进制。
字符 1、2、3、a、b、c 对应的 ASCII 码的八进制形式分别是 61、62、63、141、142、143,十六进制形式分别是 31、32、33、61、62、63。下面的例子演示了转义字符的用法:
转义字符既可以用于单个字符,也可以用于字符串,并且一个字符串中可以同时使用八进制形式和十六进制形式。
常见的转义字符如下
转义字符 | 意义 | ASCII码值(十进制) |
---|---|---|
\a | 响铃(BEL) | 007 |
\b | 退格(BS) ,将当前位置移到前一列 | 008 |
\f | 换页(FF),将当前位置移到下页开头 | 012 |
\n | 换行(LF) ,将当前位置移到下一行开头 | 010 |
\r | 回车(CR) ,将当前位置移到本行开头 | 013 |
\t | 水平制表(HT) | 009 |
\v | 垂直制表(VT) | 011 |
’ | 单引号 | 039 |
" | 双引号 | 034 |
\ | 反斜杠 | 092 |
单引号、双引号、反斜杠是特殊的字符,不能直接表示:
- 单引号是字符类型的开头和结尾,要使用 \’ 表示,也即’ \’ ';
- 双引号是字符串的开头和结尾,要使用 \" 表示,也即" abc\"123 ";
- 反斜杠是转义字符的开头,要使用\\表示,也即’\\’,或者"abc\\123"。
读入一行数据
- getline():从流中读入一行数据
C++ getline函数用法
第一种:在头文件<istream>中,是iostream类的成员函数。
第二种:在头文件<string>中,是普通函数。
第一种: 在中的getline()函数有两种重载形式:
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
作用是: 从istream中读取至多n个字符(包含结束标记符)保存在s对应的数组中。即使还没读够n个字符,
如果遇到delim 或 字数达到限制,则读取终止,delim都不会被保存进s对应的数组中。
第二种: 在中的getline函数有四种重载形式:
istream& getline (istream& is, string& str, char delim);
istream& getline (istream&& is, string& str, char delim);
istream& getline (istream& is, string& str);
istream& getline (istream&& is, string& str);
用法和上第一种类似,但是读取的istream是作为参数is传进函数的。读取的字符串保存在string类型的str中。
函数的变量:
is :表示一个输入流,例如 cin。
str :string类型的引用,用来存储输入流中的流信息。
delim :char类型的变量,所设置的截断字符;在不自定义设置的情况下,遇到’\n’,则终止输入。
- stringstream
c++ stringstream
库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。
1.stringstream::str(); 返回带有流当前内容副本的字符串对象
2.stringstream::str (const string& s); 将s设置为流的内容,并丢弃所有先前的内容。
3.stringstream s; s.str(""); 清空流
4.实现任意类型的转换
示例
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
template<typename out_type, typename in_value>
out_type convert(const in_value & t){
stringstream stream;
stream<<t;
out_type result;
stream>>result;
return result;
}
int main(){
string s = "1 23 # 4";
stringstream ss;
ss<<s;
while(ss>>s){
cout<<s<<endl;
int val = convert<int,string>(s);
cout<<val<<endl;
}
return 0;
}
清空字符串区域
- memset(): 复制字符 value(一个无符号字符)到参数 ptr 所指向的字符串的前 num 个字符; value为要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
http://www.cplusplus.com/reference/cstring/
头文件
<cstring>
void * memset ( void * ptr, int value, size_t num );
Sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).
char* m_buf = new char[10];
memset(m_buf, '\0', 10);
- bzero():置字节字符串s的前n个字节为零且包括‘\0’。
头文件
#include <string.h>
extern void bzero(void *s, int n);
参数说明:s 要置零的数据的起始地址; n 要置零的数据字节个数。
说明:bzero无返回值,并且使用string.h头文件,string.h曾经是posix标准的一部分,但是在POSIX.1-2001标准里面,这些函数被标记为了遗留函数而不推荐使用。在POSIX.1-2008标准里已经没有这些函数了。推荐使用memset替代bzero。
复制字符串区域
- strcpy():把 src 所指向的字符串复制到 dest。需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。
char *strcpy(char *dest, const char *src)
- strncpy():把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
char *strncpy(char *dest, const char *src, size_t n);
搜索字符串相关
- strrchr:
char *strrchr(const char *str, int c)
函数说明:在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置
strpbrk():
char *strpbrk(const char *str1, const char *str2)
检索字符串 str1 中第一个匹配字符串 str2 中字符的字符,不包含空结束字符。
也就是说,依次检验字符串 str1 中的字符,当被检验字符在字符串 str2 中也包含时,
则停止检验,并返回该字符位置。
示例来自https://www.runoob.com/cprogramming/c-function-strpbrk.html
#include <stdio.h>
#include <string.h>
int main ()
{
const char str1[] = "abcde2fghi3jk4l";
const char str2[] = "34";
char *ret;
ret = strpbrk(str1, str2);
if(ret)
{
printf("第一个匹配的字符是: %c\n", *ret);
}
else
{
printf("未找到字符");
}
return(0);
}
- strspn()
size_t strspn(const char *str1, const char *str2)
检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标
字符串连接
- strcat(): 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾
char *strcat(char *dest, const char *src);
参数
dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
src -- 指向要追加的字符串,该字符串不会覆盖目标字符串。
返回值
该函数返回一个指向最终的目标字符串 dest 的指针。
字符串分割
在C++中没有直接对应的split函数,字符串分割可借助以下方法实现:
1、借助strtok函数
http://www.cplusplus.com/reference/cstring/strtok/
头文件
<cstring>
函数原型:
char * strtok ( char * str, const char * delimiters );
函数功能:以delim为分隔符分割字符串str
参数说明:str:要分隔的字符串;delim:分隔符
描述:strtok()用来将字符串分割成一个个片段,参数s指向将要被分隔的字符串,参数delim则为分隔字符串,当strtok()在参数s的字符串中发现到参数delim的分隔字符时,则会将该字符改为’\0’字符,直到找遍整个字符串, 返回指向下一个标记串,当没有标记串时则返回空字符NULL。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回被分隔片段的指针。
注意:
- strtok是一个线程不安全的函数,因为它使用了静态分配的空间来存储被分割的字符串位置,线程安全的函数叫strtok_r。
1.strtok函数分割char*类型的字符串
#include <iostream>
#include<cstring>
using namespace std;
int main() {
char s[] ="192.,*168.0.,*8...";// "my name is lmm";
char *p;
const char *delim = ".,*";
p = strtok(s, delim);
while(p) {
cout << p << endl;
p = strtok(NULL, delim);
}
system("pause");
return 0;
}
- 借助strtok分割string类型的字符串,将结果保存在vector中
#include <iostream>
#include<vector>
#include<cstring>
using namespace std;
vector<string> split(const string& str,const string& delim){
if(str=="") return {};
vector<string> res;
//先将要切割的字符串从string类型转换为char*类型
char* cstr=new char[str.length()+1];
strcpy(cstr,str.c_str());
char* cdelim=new char[delim.length()+1];
strcpy(cdelim,delim.c_str());
char* p=strtok(cstr,cdelim);
while(p){
string s=p;
res.push_back(s);
p=strtok(NULL,cdelim);
}
delete cstr;
delete cdelim;
return res;
}
int main() {
string str="192.,*168.0.,*8...";
string delim=".,*";
vector<string> res=split(str,delim);
for(auto&i:res)
cout<<i<<endl;
system("pause");
return 0;
}
字符串比较
- strcmp
头文件
<string.h>
int strcmp(const char *str1, const char *str2);
参数
str1 -- 要进行比较的第一个字符串。
str2 -- 要进行比较的第二个字符串。
返回值
该函数返回值如下:
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
- strcasecmp
头文件:
#include <string.h>
函数说明:strcasecmp()用来比较参数s1 和s2 字符串,比较时会自动忽略大小写的差异。
int strcasecmp (const char *s1, const char *s2);
返回值:若参数s1 和s2 字符串相同则返回0。s1 长度大于s2 长度则返回大于0 的值,s1 长度若小于s2 长度则返回小于0 的值。
字符串转整型/浮点型
字符串到数字的转换可以通过 stoX() 系列函数来执行。该系列函数的成员可以将字符串转换为 int、long、float 和 double 类型的数字。具体语法如下所示:
1.头文件< string >中
<string>
int stoi(const strings str, size_t* pos = 0, int base = 10)
long stol(const strings str, size_t* pos = 0, int base = 10)
float stof(const strings str, size_t* pos = 0)
double stod(const strings str, size_t* pos = 0)
第一个形参 str 是一个字符串(例如 “-342” 或 “3.48” 等),它将被转换为恰当的数字形式。这些函数可以将 str 可能的最长前缀转换为数字,并返回一个整数地址 pos,pos 中保存了 str 无法被转换的第一个字符的索引。类型 size_t 是在标准库中定义的,常用于表示无符号整数的大小或数组、矢量、字符串中的一个索引。
例如,如果试图转换字符串 “-34iseven”,则将成功返回整数 -34,而无法转换的第一个字符的位置 pos 则被设置为 3。base 形参仅适用于整数转换,指示用于转换的进制。pos 和 base 形参都是可选的,所以它们可以被忽略。如果 pos 被忽略,则不会存储停止字符的索引。如果 base 被忽略,则默认为十进制。如果字符串 str 包含一个无效值,例如 “is-34 even?”,则不会进行转换,函数将抛出一个 invalid_argument 异常。
2.头文件< cstdlib >中
<cstdlib>
http://www.cplusplus.com/reference/cstdlib/
函数 | 功能 |
---|---|
atof | Convert string to double (function ) |
atoi | Convert string to integer (function ) |
atol | Convert string to long integer (function ) |
atoll | Convert string to long long integer (function ) |
strtod | Convert string to double (function ) |
strtof | Convert string to float (function ) |
strtol | Convert string to long integer (function ) |
strtold | Convert string to long double (function ) |
strtoll | Convert string to long long integer (function ) |
strtoul | Convert string to unsigned long integer (function ) |
strtoull | Convert string to unsigned long long integer (function ) |
整型/浮点型转字符串
来自http://c.biancheng.net/view/1527.html
C++ 11 提供了若干 to_string(T value) 函数来将 T 类型的数字值转换为字符串形式。
以下是几个 to_string() 函数的列表:
1.头文件< string >中
<string>
http://www.cplusplus.com/reference/string/to_string/?kw=to_string
string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);
2.头文件< stdio.h >中
- sprintf
#include <stdio.h>
sprintf()函数用于将格式化的数据写入字符串,其原型为:
int sprintf(char *str, char * format [, argument, ...]);
【参数】str为要写入的字符串;format为格式化字符串,与printf()函数相同;argument为变量。
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数--格式化字符串--上。
printf()和sprintf()都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。
【返回值】成功则返回参数str 字符串长度,失败则返回-1,错误原因存于errno 中。
常见的format格式:
%% 印出百分比符号,不转换。
%c 整数转成对应的 ASCII 字元。
%d 整数转成十进位。
%f 倍精确度数字转成浮点数。
%o 整数转成八进位。
%s 整数转成字符串。
%x 整数转成小写十六进位。
%X 整数转成大写十六进位。
%n sscanf(str, "%d%n", &dig, &n),%n表示一共转换了多少位的字符
- snprintf
注意:C语言对数组进行操作时并不检测数组的长度,如果str的长度不够,上面的sprintf()很容易造成缓冲区溢出,带来意想不到的后果,黑客经常利用这个弱点攻击看上去安全的系统。
使用snprintf()来代替sprintf()将能够很好的解决这个问题。
功能:设将可变参数(...)按照 format 格式化成字符串,并将字符串复制到 str 中,size 为要写入的字符的最大数目,超过 size 会被截断。
int snprintf ( char * str, size_t size, const char * format, ... );
参数
str -- 目标字符串。
size -- 拷贝字节数(Bytes)。
format -- 格式化成字符串。
... -- 可变参数。
返回值
(1) 如果格式化后的字符串长度小于等于 size,则会把字符串全部复制到 str 中,并给其后添加一个字符串结束符 \0;
(2) 如果格式化后的字符串长度大于 size,超过 size 的部分会被截断,只将其中的 (size-1) 个字符复制到 str 中,并给其后添加一个字符串结束符 \0,返回值为欲写入的字符串长度。
示例
#include <stdio.h>
int main()
{
char buffer[50];
char* s = "runoobcom";
// 读取字符串并存储在 buffer 中
int j = snprintf(buffer, 6, "%s\n", s);
// 输出 buffer及字符数
printf("string:\n%s\ncharacter count = %d\n", buffer, j);
return 0;
}
- int vsprintf(char *str, const char *format, va_list arg) 使用参数列表发送格式化输出到字符串。
头文件
#include <stdarg.h>
#include <stdio.h>
int vsprintf(char *str, const char *format, va_list arg)
str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,
具体的见https://www.runoob.com/cprogramming/c-function-vsprintf.html
int vsnprintf( char* buf,size_t count,const char* format,va_list arg );
用法类似于vsprintf,不过加了count的限制,防止了内存溢出(count为str所指的存储空间的大小)。
返回值:执行成功,返回最终生成字符串的长度,若生成字符串的长度大于size,
则将字符串的前size个字符复制到str,同时将原串的长度返回(不包含终止符);
执行失败,返回负值,并置errno
va_start(),va_end()函数应用
va_list ap; //声明一个变量来转换参数列表
va_start(ap,format); //初始化变量
va_end(ap); //结束变量列表,和va_start成对使用
可以根据va_arg(ap,type)取出参数
示例
/* vsnprintf example */
#include <stdio.h>
#include <stdarg.h>
void PrintFError ( const char * format, ... )
{
char buffer[256];
va_list args;
va_start (args, format);
vsnprintf (buffer,256,format, args);
perror (buffer);
va_end (args);
}
int main ()
{
FILE * pFile;
char szFileName[]="myfile.txt";
pFile = fopen (szFileName,"r");
if (pFile == NULL)
//可变参数...为空也可以
//PrintFError("Error opening");这样也可以调用成功的。
PrintFError ("Error opening '%s'",szFileName);
else
{
// file successfully open
fclose (pFile);
}
return 0;
}
stat函数讲解
头文件:
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *file_name, struct stat *buf);
函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno
错误代码:
ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长
stat结构体
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
先前所描述的st_mode 则定义了下列数种情况:
S_IFMT 0170000 文件类型的位遮罩
S_IFSOCK 0140000 scoket
S_IFLNK 0120000 符号连接
S_IFREG 0100000 一般文件
S_IFBLK 0060000 区块装置
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符装置
S_IFIFO 0010000 先进先出
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
上述的文件类型在POSIX中定义了检查这些类型的宏定义:
S_ISLNK (st_mode) 判断是否为符号连接
S_ISREG (st_mode) 是否为一般文件
S_ISDIR (st_mode) 是否为目录
S_ISCHR (st_mode) 是否为字符装置文件
S_ISBLK (s3e) 是否为先进先出
S_ISSOCK (st_mode) 是否为socket
若一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名。