数组矩阵广义表:C++字符串常用操作示例代码
1. 基本介绍
在程序设计中,字符串操作是必不可缺的,无论是工程设计还是算法设计均离不开字符串,字符串是由一个个单独的字符构成的串,其数据结构是线性的,常以ASCII码表示,同时只要设定得当,其展示任何一种编码也都是可以的。
字符串有很多的操作,也有非常多的扩展算法,本文从设计的角度介绍这些基本的字符串操作以及其实现代码,本文实现的大多数代码诸如C和C++中的头文件<string.h>(C++则是<cstring>)已经封装好了相应的函数和方法可以直接使用。
2. 获取字符串长度
顾名思义,指获取一个字符串的长度,在C语言中我们可以直接用strlen(str)来表示,其实现思路可以直接使用一个循环,对每一个字符进行计数,当循环遇到字符’\0’即结束符时循环结束,返回这个循环,示例代码如下:
#include<stdio.h> int _strlen( char str[]){ int i=0; for (i=0;str[i]!= '\0' ;i++){} return i; } int main(){ char *str = "Hello My DotCpp.com" ; int len = _strlen(str); printf ( "%d" ,len); return 0; } |
输出19
3. 字符位置获取
给定一个字符,获取这个字符串中首次出现这个字符的位置,如果没有找到则给与一个错误信号,如给定一个hello,要求找出l的位置,那么将会找到位置3 ,C语言中可以使用strchr(str,c)表示,实现示例代码如下:
#include<stdio.h> int _charAt( char str[], char c){ int i=0; for (i=0;str[i]!= '\0' &&str[i]!=c;i++){} return i; } int main(){ char *str = "Hello My DotCpp.com" ; int way = _charAt(str, 'l' ); printf ( "%d" ,way); return 0; } |
输出3
扩展练习:如果需要你创建一个函数,获取这个字符串中所有出现这个字符的位置,又该如何去设计呢?
4. 拆分子串操作substr
顾名思义,对一个字符串进行拆分,也可以称之为对一个字符串的某一段进行截取,如一个字符串的长度有0~n,改操作就是取其中i~j的位置,使其重新生成一个新的字符串,获取的就是这个字符串,在C语言中没有相关的操作,在不同的教程中这样的操作也有不同的命名,本文将此操作命名未substr(在某些别的资料中substr操作则为查找操作),本实现示例代码如下(注意拆分时需要补充结束符’\0’):
#include<stdio.h> char *_substr( char str[], int i, int j){ int pos=0; char *backup; while (i<j){ backup[pos++] = str[i++]; } backup[pos]= '\0' ; return backup; } int main(){ char *str = "Hello My DotCpp.com" ; char *newstr = _substr(str,0,5); printf ( "%s" ,newstr); return 0; } |
输出Hello
5. 拆分子串操作prefix
如同上文的操作,截取操作变为了只截取字符串的前m个字符,组成一个全新的字符串,本实现示例代码如下(注意拆分时需要补充结束符’\0’):。
#include<stdio.h> char *_prefix( char str[], int m){ int pos=0,i; char *backup; for (i=0 ;i<m ;i++){ backup[pos++] = str[i]; } backup[pos]= '\0' ; return backup; } int main(){ char *str = "Hello My DotCpp.com" ; char *newstr = _prefix(str,5); printf ( "%s" ,newstr); return 0; } |
输出Hello
6. 拆分子串操作suffix
如同上文的操作,截取操作变为了只截取字符串的后m个字符,组成一个全新的字符串,本实现示例代码如下(注意拆分时需要补充结束符’\0’):
这里需要稍微注意一下,在创建字符串的时候,由于各种标准的C对语法的支持不太一样,这里采用较为旧的方式实现,即直接分配一个相应的内存空间,这与上面的做法稍微不同,如果采用char *backup的创建方式,将会产生内存错误问题,这个问题原理较为晦涩,有能力的同学可以参考资料自行理解,这里为了避免冲突简化了操作。
#include<stdio.h> char *_suffix( char str[], int m){ int len=0; for (;str[len]!= '\0' ;len++){} //获取字符串总长度(避免使用其他封装函数,自行设计时可以使用strlen替代) printf ( "%d\n" ,len-m); int pos=0,i; char backup[500]; for (i=len-m ;i<len ;i++){ backup[pos++] = str[i]; } backup[pos]= '\0' ; return backup; } int main(){ char *str = "Hello My DotCpp.com" ; char *newstr = _suffix(str,3); printf ( "%s" ,newstr); return 0; } |
输出com
7.字符串连接操作
顾名思义,即将一个字符串链接到另一个字符串的尾部,我们可以创建一个函数,同时利用指针,分别先后全部遍历两个字符串,将其中一个字符串的结束符’\0’去除并链接另一个字符串直到遇到结束符’\0’即可,函数实现为:
#include<stdio.h> char *_strcat( char dest[], char src[]){ char * ret = dest; while (*dest!= '\0' ){dest++;} //将src内容复制在dest之后 while (*src){ *dest++ = *src++; } //在dest后面追加\0 *dest = '\0' ; return ret; } int main(){ char str[] = "Hello My DotCpp.com" ; char fixstr[] = "Welcome " ; _strcat(fixstr,str); printf ( "%s" ,fixstr); return 0; } |
输出Welcome Hello My DotCpp.com
8. 字符串比较操作
顾名思义,对两个字符字符字符串进行比较,常用于确认两字符串是否完全相等,部分高级用法可以扩展到利用大小差别进行容器的算法设计等,比较操作的内容就是对两个字符串进行比较,两个字符串完全相等时返回0,第一个字符串大于第二个字符串时返回一个正值,否则返回负值,实现代码为:
注意比较的时候要使用unsigned char而不要直接使用char,那是因为计算机编程语言中扩展了char的字符位,使字符位也拥有了含义,因此建议在核心的比较时使用unsigned char的类型。
#include<stdio.h> int _strcmp ( char * src, char * dst) { int ret = 0 ; while ( !(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) //两个内容相减,完全相等则会得到值 0,取反即为相等 ++src, ++dst; if ( ret < 0 ) ret = -1 ; else if ( ret > 0 ) ret = 1 ; return ret; } int main(){ char str[] = "Hello My DotCpp.com" ; char fixstr[] = "Welcome " ; int ans = _strcmp(fixstr,str); printf ( "%d" ,ans); return 0; } |
输出 1
9. 暴力匹配法
这并不是最理想的算法,但却这是字符串匹配算法中最容易理解的算法,算法核心为给定一个主串T和一个模式串P,求问是否P是属于T的一个字串,如:”Hello”中”llo”就是其中的一个字串,对于暴力匹配算法而言,我们可以利用两层循环进行比对,第一层循环中找寻T字符串中的每一个字符,第二层循环找寻的是每一个P字符,进入第二层循环时T字符串也会跟着进行字符前进,如果发生不匹配则产生一个回溯回到第一层循环的进入字符的下一个字符。
代码示例如下:
#include<iostream> #include<cstring> using namespace std; bool isBF( char str1[], char str2[]){ bool flag= false ; int len1 = strlen (str1); int len2 = strlen (str2); for ( int i=0;i<len1;i++){ for ( int j=0;j<len2;j++){ int pos=i; if ( str1[pos++] != str2[j]){ break ; } else { if (j=len2-1) flag= true ; } } } return flag; } int main(){ char str1[] = "HI this is my lesson." ; char str2[] = "is" ; cout<<isBF(str1,str2)<<endl; return 0; } |
输出1
综上假设字符串T的长度为n,字符串P的长度为m,则整个算法的时间复杂度为O( n * m ),而对于一个复杂的现实情况而言 n >> m >> 2 (即n远远大于m,m远远大于常数),这样的计算计算机的负担很重。