0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

关于字符串硬核讲解

FPGA之家 来源:FPGA之家 作者:FPGA之家 2022-06-26 10:42 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

1 暴力破解法

在主串A中查找模式串B的出现位置,其中如果A的长度是n,B的长度是m,则n > m。当我们暴力匹配时,在主串A中匹配起始位置分别是 0、1、2….n-m 且长度为 m 的 n-m+1 个子串。

db273a1e-f4e9-11ec-ba43-dac502259ad0.png暴力匹配
对应代码是:
#include
#include
intcnt=0;
intindex(chars[],charsub[])
{
inti=0;
intj=0;
while(i<strlen(s))
{
if(s[i]==sub[j])
{//单个字符相等的话i和j都向后搜索
i++;
j++;
}
else
{//有字符不匹配的话,i从上一次的下一个位置开始,模式串j再从0开始
i=i-j+1;
j=0;
}
if(j==strlen(sub))
{
cnt++;
returni-strlen(sub)+1;
}
}
return-1;
}
intmain()
{
// s="abcdabefgabefa",sub="abe",返回 5。
chars[20],sub[10];
gets(s);
gets(sub);
printf("%d
",cnt);
printf("%d
",index(s,sub));
return0;
}

如果主串是bbb…bbb,模式串是bbbbc,那每个串都要比较m次,一共是(n-m+1)*m次。时间复杂度很大 = O(n*m),一般简单匹配时候可用此法。

2 Rabin-Karp 算法

算法思路:对主串的 n-m+1 个子串分别求哈希值,然后跟模板串的哈希值对比,如果一样再逐个对比字符串是否一样。

db39bb3a-f4e9-11ec-ba43-dac502259ad0.pngRabin-Karp算法
但是中间数据的Hash值计算是可以优化的,我们以简单的字符串匹配举例,把a-z映射到0~25上。然后按照26进制计算一个串的哈希值,比如:
db46d590-f4e9-11ec-ba43-dac502259ad0.pngHash计算
但是你会发现相邻的两个子串数据之间是有重叠的,比如dababc重叠了ab。这样哈希下一个数据的Hash值其实可以借鉴下上一个数据的值推导得出:
db57640a-f4e9-11ec-ba43-dac502259ad0.png优化计算哈希值
RK算法的时间复杂度包含两部分,第一部分是遍历所有子串计算Hash值,时间复杂度是O(n)。第二部分是比较哈希值,这部分时间复杂度也是O(n)。

这个算法的核心就是尽量减少哈希值相等的情况下数据不一样从而进行的比较,所以哈希算法要尽可能的好,如果你感觉用123对应字母abc容易碰撞,那用素数去匹配也是OK的,反正目的是一样的, 你可以认为这是一种取巧的办法来处理字符串匹配问题。

3 Boyer-Moore 算法。

Boyer Moore算法是一种非常高效的字符串匹配算法,它的性能是著名的 KMP 算法的 3 到 4 倍。它不太好理解,但确是工程中使用最多的字符串匹配算法。以前我们匹配字符串的时候是一个个从前往后挪动来逐次比较,BM 算法核心思想是在模式串中某个字符与主串不能匹配时,将模式串往后多滑动几位,来减少不必要的字符比较

db631f7a-f4e9-11ec-ba43-dac502259ad0.png移动比较对比
整体而言BM算法还是挺复杂的相比前面两种,主要包含坏字符规则好后缀规则

3.1 坏字符规则

坏字符规则意思是根据模式串从后往前匹配,当我们发现某个字符没法匹配的时候。我们把这个没有匹配的主串中的字符叫作坏字符

db6dcf10-f4e9-11ec-ba43-dac502259ad0.png坏字符
找到坏字符c后,在模式串中继续查找发现c跟模式串任何字符无法匹配,则可以直接将模式串往后移动3位。继续从模式串尾部对比。
db77731c-f4e9-11ec-ba43-dac502259ad0.png移动2格
此时发现坏字符是g,但在模式串中有个g存在,不能再往后移动3个了,移动的位置是2个。再继续匹配。那有啥规律呢?

发送不匹配时,坏字符对应的模式串字符下标位置Si,如果坏字符在模式串中存在,取从后往前最先出现的坏字符下标记为Xi(取第一个是怕挪动太大咯),如果坏字符在模式串中不存在则Xi = -1。此时模式串往后移动位数= Si - Xi

db88aa4c-f4e9-11ec-ba43-dac502259ad0.png坏字符移动规则
如果碰到极致的主串=cccdcccdcccd,模式串=cccc,那此时时间复杂度是O(n/m)。
db9c903e-f4e9-11ec-ba43-dac502259ad0.png最优解
但是不要高兴太早!下面这种情况可能导致模式串不往后移动,反而往前移动哦!
dbb73bc8-f4e9-11ec-ba43-dac502259ad0.png往前移动?
所以此时BM算法还需要用到好后缀规则

3.2 坏字符代码

为避免每次都拿怀字符从模式串中遍历查找,此时用到散列表将模式串中每个字符及其下标存起来,方便迅速查找。

接下来说下散列表规则,比如一个字符是一个字节,用大小为256的数组记录每个字符在模式串出现位置,数组中存储的是模式串出现的位置,数组下表是字符对应的ASCII值。

dbc14226-f4e9-11ec-ba43-dac502259ad0.png哈希规则 坏字符规则:
//全局变量 SIZE
privatestaticfinalintSIZE=256;
//b=模式串数组,m是模式串数组长度,sl是哈希表,默认-1
privatevoidgenerateBC(char[]b,intm,int[]sl){
for(inti=0;i< SIZE; i++) {
    sl[i] = -1;//初始化sl
}
for(inti=0;i< m; ++i) {
    intascii=(int)b[i];
sl[ascii]=i;
}
}

接下来先不考虑好后缀规则跟坏字符的负数情况,先大致写出 BM 算法代码。

dbd90ad2-f4e9-11ec-ba43-dac502259ad0.png坏字符BM
publicintbm(char[]a,intn,char[]b,intm){
//记录模式串中每个字符最后出现的位置
int[]sl=newint[SIZE];
//构建坏字符哈希表
generateBC(b,m,sl);
//i表示主串与模式串对齐的第一个字符
inti=0;
while(i<= n - m) {
    intj;
for(j=m-1;j>=0;j--){
if(a[i+j]!=b[j])break;
}
if(j< 0){
//匹配成功,返回主串与模式串第一个匹配的字符的位置
returni;
}
//将模式串往后滑动j-bc[(int)a[i+j]]位
i=i+(j-sl[(int)a[i+j]]);
}
return-1;
}

3.3 好后缀规则

好后缀跟坏后缀道理类似,从后往前匹配,直到遇到不匹配的字符x,那主串x之前的就叫好后缀

dbe9e0e6-f4e9-11ec-ba43-dac502259ad0.png好后缀定义
此时移动的规则如下:
  1. 如果好后缀在模式串中找到了,用x框起来,然后将x框跟好后缀对齐继续匹配。

    dbf9aeae-f4e9-11ec-ba43-dac502259ad0.png找到了移动规则
  2. 找不到的时候,如果直接移动长度是模式串m位,那极有可能过度了!而过度移动存在的原因就是,比如你找了好后缀u,u在模式串中整体没找到,但是u的子串d是可以跟模式串匹配上的啊。

    dc0d6386-f4e9-11ec-ba43-dac502259ad0.png过度移动

所以此时还要看好后缀的后缀子串是否跟模式串中的前缀子串匹配,从好后缀串的后后缀子串中找个最长能跟模式串的前缀子串匹配的然后滑动到一起,比如上面的d。

然后分别计算坏字符往后滑动位数跟好后缀往后滑动此时,两者取其大作为模式串往后滑动位数,这种情况下还可以避免坏字符的负数情况。

3.4 好后缀代码

好后缀的核心其实就在于两点

  1. 在模式串中,查找跟好后缀匹配的另一个子串。

  2. 在好后缀的后缀子串中,查找最长的、能跟模式串前缀子串匹配的后缀子串。

3.4.1 预处理工作

上面两个核心点可以在代码层面用暴力解决,但太耗时!我们可以在匹配前通过预处理模式串,预先计算好模式串的每个后缀子串,对应的另一个可匹配子串的位置。

先看如何表示模式串中不同的后缀子串,因为后缀子串的最后个字符下标为m-1,我们只需记录后缀子串长度即可,通过长度可以确定一个唯一的后缀子串。

dc202c50-f4e9-11ec-ba43-dac502259ad0.png子串表示
再引入关键的变量suffix数组。suffix 数组的index表示后缀子串的长度。下标对应的数组值存储的是
好后缀在模式串中匹配的起始下标值:
dc2e78f0-f4e9-11ec-ba43-dac502259ad0.pngsuffix数组定义
比如此处后缀子串c在模式串中另一个匹配开始位置为2, 后缀子串bc在模式串中另一个匹配开始位置为1 后缀子串dbc在模式串中另一个匹配开始位置为0, 后缀子串cdbc在模式串中只出现了一次,所以为-1。
dc404bf2-f4e9-11ec-ba43-dac502259ad0.pngprefix 数组
这里需注意,我们不仅要在模式串中查找跟好后缀匹配的另一个子串,还要在好后缀的后缀子串中查找最长的能跟模式串前缀子串匹配的后缀子串。比如下面:
dc5200a4-f4e9-11ec-ba43-dac502259ad0.png最长模式匹配

suffix只能查找跟好后缀匹配的另一个子串。但还需要个 boolean 类型的prefix数组来记录模式串的后缀子串是否能匹配模式串的前缀子串。

接下来重点看下如何填充suffixprefix数组,拿下标从 0 到 i 的子串与整个模式串,求公共后缀子串,其中i=[0,m-2]。如果公共后缀子串的长度是 k,就suffix[k]=j,其中 j 表示公共后缀子串的起始下标。如果 j = 0,说明公共后缀子串也是模式串的前缀子串,此时 prefix[k]=true。

dc615478-f4e9-11ec-ba43-dac502259ad0.pngsuffix跟prefix数组
//b=模式串,m=模式串长度,suffix,prefix数组如上定义
privatevoidgenerateGS(char[]b,intm,int[]suffix,boolean[]prefix){
//初始化
for(inti=0;i< m; i++){
suffix[i]=-1;
prefix[i]=false;
}
//b[0,i]
for(inti=0;i< m - 1;i++){
intj=i;
//公共后缀子串长度
intk=0;
//与b[0, m-1]求公共后缀子串,并且会有覆盖现象产生。
while(j>=0&&b[j]==b[m-1-k]){
--j;
++k;
//j+1表示公共后缀子串在b[0,i]中的起始下标
suffix[k]=j+1;
}
//如果公共后缀子串也是模式串的前缀子串
if(j==-1)prefix[k]=true;
}
}
3.4.2 正式代码

有了suffixprefix数组后,看下移动规则。假设好后缀串长度=k,如果k != 0,说明有好后缀,接下来通过suffix[k]的值来判断如何移动。

  1. suffix[k] != -1,不等于时说明匹配上了,模式串后移 j-suffix[k]+1 位,其中 j 表示坏字符对应的模式串中的字符下标。

  2. suffix[k] = -1,等于时说明好后缀没匹配上,那就看下子串的匹配情况,好后缀的后缀子串长度是 b[r, m-1],其中 r = [j+2,m-1],后缀子串长度 k=m-r,如果 prefix[k] = true,说明长度为 k 的后缀子串有可匹配的前缀子串,这样我们可以把模式串后移 r 位。

  3. 如果都没匹配上,那就直接将模式串后移m位。

    // a跟n 分别表示主串跟主串长度。
    // b跟m 分别表示模式串跟模式串长度。
    publicintbm(char[]a,intn,char[]b,intm){
    //用来记录模式串中每个字符最后出现的位置
    int[]sl=newint[SIZE];
    //构建坏字符哈希表
    generateBC(b,m,sl);
    int[]suffix=newint[m];
    boolean[]prefix=newboolean[m];
    //构建suffix跟prefix数组
    generateGS(b,m,suffix,prefix);
    inti=0;//j表示主串与模式串匹配的第一个字符
    while(i<= n - m) {
        intj;
    //模式串从后往前匹配
    for(j=m-1;j>=0;--j){
    //坏字符对应模式串中的下标是j
    if(a[i+j]!=b[j])break;
    }
    if(j< 0){
    //匹配OK,返回主串与模式串第一个匹配的字符的位置
    returni;
    }
    //坏字符计算所得需移动长度
    intx=j-sl[(int)a[i+j]];
    inty=0;
    //j< m-1  说明有好的匹配上了
    if(j< m-1){
    y=moveByGS(j,m,suffix,prefix);
    }
    i=i+Math.max(x,y);
    }
    return-1;
    }
    
    //j=坏字符对应的模式串中的字符下标
    //m=模式串长度
    privateintmoveByGS(intj,intm,int[]suffix,boolean[]prefix){
    //好后缀长度
    intk=m-1-j;
    if(suffix[k]!=-1){
    //好后缀可以匹配上,返回需移动长度
    returnj-suffix[k]+1;
    }
    //有匹配到好后缀子串的模式串前缀子串
    for(intr=j+2;r<= m-1;++r){
    if(prefix[m-r]==true){
    returnr;
    }
    }
    //没找到直接移动最大值
    returnm;
    }
    

3.5 复杂度分析

整个BM算法用到了额外的 sl、suffix、prefix三个数组,其中sl数组大小跟字符集大小有关,suffix 数组和 prefix 数组的大小跟模式串长度 m 有关。如果处理字符集很大的字符串匹配问题,bc 数组对内存的消耗就会比较多。

因为好后缀和坏字符规则是独立的,如果我们运行的环境对内存要求苛刻,可以只使用好后缀规则,不使用坏字符规则,这样就可以避免 bc 数组过多的内存消耗。不过,单纯使用好后缀规则的 BM 算法效率就会下降一些了。

BM 算法的时间复杂度分析起来是非常复杂,一般在3n~5n之间。

4 KMP 算法

KMP算法跟BM算法类似,从前往后匹配,把能匹配上的叫好前缀,不能匹配上的叫坏字符

dc6aee3e-f4e9-11ec-ba43-dac502259ad0.pngKMP匹配定义
遇到坏字符后就要进行主串好前缀后缀子串跟模式串的前缀子串进行对比,问题是对于已经比对过的好前缀,能否找到一种规律,将模式串一次性滑动很多位?
dc7b45d6-f4e9-11ec-ba43-dac502259ad0.png暴力破解

思路是将主串中好前缀的后缀子串和模式串中好前缀的前缀子串进行对比,获取模式串中最大可以匹配的前缀子串。一般把好前缀的所有后缀子串中,最长的可匹配前缀子串的那个后缀子串,叫作最长可匹配后缀子串。对应的前缀子串,叫作最长可匹配前缀子串。假如现在最长可匹配后缀子串 = u,最长可匹配前缀子串 = v,获得uv的长度为k,此时在主串中坏字符位置为i,模式串中为j,接下来将模式串后移j-k位,然后将待比较的模式串位置j = j-k进行比较。

dc86fca0-f4e9-11ec-ba43-dac502259ad0.pngKMP算法移动

4.1 Next 数组存在意义

那最长可匹配前缀跟后缀我们用模式串就可以求解了。仿照BM算法,预先计算好就行。在KMP算法中提前构造个next数组。其中next数组的下标用来存储前缀子串最后一个数据的index,对应的value保存的是这个字符串的后缀子串集合跟前缀子串集合的交集。

干说可能不太好理解,我们以"abababca"为例。它的部分匹配表(Partial Match Table)数组如下:

dc92760c-f4e9-11ec-ba43-dac502259ad0.pngNext数组
接下来对value值的获取进行解释,如果字符串A和B,存在A=BS,其中S是任意的非空字符串,那就称B为A的前缀。例如”what”的前缀包括{"w","wh","wha"},我们把所有前缀组成的字符串的前缀集合。同样可以定义后缀A=SB, 其中S是任意的非空字符串,那就称B为A的后缀,例如"Potter"的后缀包括{"otter", "tter", "ter", "er", "r"},然后把所有后缀组成字符串的后缀集合。要注意字符串本身并不是自己的后缀

PMT数组中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。例如,对于"aba",它的前缀集合为{"a", "ab"},后缀集合为{"ba", "a"}。两个集合的交集为{"a"},那么长度最长的元素就是字符串"a"了,长度为1,所以"aba"的Next数组value = 1,同理对于"ababa",它的前缀集合为{"a", "ab", "aba", "abab"},它的后缀集合为{"baba", "aba", "ba", "a"}, 两个集合的交集为{"a", "aba"},其中最长的元素为"aba",长度为3。

我们以主串"ababababca"中查找模式串"abababca"为例,如果在j处字符不匹配了,那在模式串[0,j-1]的数据串"ababab"中,前缀集合跟后缀集合的交集最大值就是长度为4的"abab"。

dc9b1582-f4e9-11ec-ba43-dac502259ad0.pngPMT数组使用方法
基于此就可以使用PMT加速字符串的查找了。我们看到如果是在j位失配,那么影响j 指针回溯的位置的其实是第 j−1 位的 PMT 值,但是编程中为了方便一般不直接使用PMT数组而是使用Next数组,Next数组的value其实就是存储的这个前缀的最长可以匹配前缀子串的结尾字符下标,其中如果匹配不到用-1代替。
dca6e6aa-f4e9-11ec-ba43-dac502259ad0.pngNext数组使用

4.2 KMP 匹配代码

// a =主串,n=主串长度。b =模式串,m =模式串长度
publicstaticintkmp(char[]a,intn,char[]b,intm){
int[]next=getNexts(b,m);
intj=0;
for(inti=0;i< n; ++i) {
    while(j>0&&a[i]!=b[j]){
j=next[j-1]+1;//发现不一样则保持i不变j进行移动
}
if(a[i]==b[j]){
++j;
}
if(j==m){//找到匹配模式串的了
returni-m+1;
}
}
return-1;
}

至此你会发现只要搞明白了PMT存在的意义,然后顺着思路推Next数组即可。

4.3 Next 数组求解

当要计算next[i]时,前面计算过的next[0~i-1]是否可以被用来快速推导出next[i]呢?

情况一:如果next[i-1] = k-1,那此时b[0,i-1]的最长可匹配前缀子串是b[0,k-1],如果b[0,i-1]的下个字符b[i]跟b[0,k-1]的下个字符b[k]相等,那next[i] = k。

dcb9405c-f4e9-11ec-ba43-dac502259ad0.png
情况二:假设b[0,i]最长可用后缀子串是b[r,i],那b[r,i-1]肯定是b[0,i-1]的可匹配后缀子串,但不一定是最长可匹配后缀子串。比如字符串b = "dexdecdexdex",此时最长可匹配后缀子串是"dex",b去掉最后的'x'成为B,此时虽然"de"是B的可匹配后缀子串,但"dexde"才是最长后缀子串!也就是说b[0, i-1]最长可匹配后缀子串对应的模式串的前缀子串的下一个字符并不等于 b[i]。
dcc496e6-f4e9-11ec-ba43-dac502259ad0.png
那此时看下b[0,i-1]的次长可匹配后缀子串b[x,i-1]对应的可匹配前缀子串b[0,i-1-x] 的下个字符b[i-x] 是否等于b[i],相等那b[0,i]的最长可匹配后缀子串是b[x,i]。
dcd1be84-f4e9-11ec-ba43-dac502259ad0.png

那我们来求 b[0, i-1]的次长可匹配后缀子串呢?次长可匹配后缀子串一定被包含在最长可匹配后缀子串中,而最长可匹配后缀子串又对应最长可匹配前缀子串 b[0, y]。此时查找 b[0, i-1]的次长可匹配后缀子串变成了查找b[0, y]的最长匹配后缀子串的问题。

按此思路考察完所有的 b[0, i-1]的可匹配后缀子串 b[y, i-1],直到找到一个可匹配的后缀子串,它对应的前缀子串的下一个字符等于 b[i],那这个 b[y, i]就是 b[0, i]的最长可匹配后缀子串。

dcdf81d6-f4e9-11ec-ba43-dac502259ad0.png
//b=模式串,m=模式串的长度
privatestaticint[]getNexts(char[]b,intm){
int[]next=newint[m];
next[0]=-1;
intk=-1;
for(inti=1;i< m; ++i) {
    while(k!=-1&&b[k+1]!=b[i]){
k=next[k];
//因为前一个的最长串的下一个字符不与最后一个相等,需要找前一个的次长串,
//问题就变成了求0到next(k)的最长串,如果下个字符与最后一个不等,
//继续求次长串,也就是下一个next(k),直到找到,或者完全没有
//最好结合前面的图来看
}
if(b[k+1]==b[i]){
++k;//字符串相等则看下一个
}
next[i]=k;//数组赋值
}
returnnext;
}

KMP空间复杂度:该算法只需要一个额外的 next 数组,数组的大小跟模式串相同。所以空间复杂度是 O(m),m 表示模式串的长度。
KMP时间复杂度:next 数组计算的时间复杂度是 O(m) + 匹配时候时间复杂度是 O(n) = O(m+n)

至此,常见的字符串匹配算法正式讲解完毕,其实前面说的都是一个主串,一个模式串。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 字符串
    +关注

    关注

    1

    文章

    596

    浏览量

    23212

原文标题:字符串硬核讲解

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    求助 LabVIEW 字符串比较

    请教大神 ,用一个字符串和多个字符串比较程序应该怎么做。 比如:A字符串和B字符串组(B组字符串个数不定可以是一个也可以是10个) 比较 A
    发表于 03-02 17:24

    打开工程后工程中的字体没有显示,如字符串,数字等控件不能预览显示字体?

    打开工程后工程中的字体没有显示,如字符串,数字等控件不能预览显示字体?
    发表于 02-25 17:39

    字符串控件与静态字符串控件中预览字符显示乱码,如何修改显示正常?

    字符串控件与静态字符串控件中预览字符显示乱码,如何修改显示正常?
    发表于 01-20 17:17

    字符串,数字控件如何控制背景颜色和前景字体颜色?

    字符串,数字控件如何控制背景颜色和前景字体颜色?
    发表于 01-20 15:12

    Linux下怎么让中文字符串按照拼音排序?

    求教 Linux 下怎么让中文字符串按照拼音排序?
    发表于 01-06 07:40

    字符串关联数字变量如何使用?我们的地址都是16位数据,可以使用16位数字变量显示字符串吗?

    字符串关联数字变量如何使用?我们的地址都是16位数据,可以使用16位数字变量显示字符串吗?
    发表于 12-15 08:24

    求助,关于cubemx + nano 4.1.1 + STM32F405时钟的问题求解

    NANO 4.1.1版本的MDK工程,mian里代码写的是一秒打印一次字符串,但是出现的效果了,一秒钟一次性打印了10次字符串 看起来似乎是有关时钟配置的问题,因为一秒钟刚好打印十次字符串,然后我尝试
    发表于 09-16 06:05

    如何使用 NuMaker 板和 Mbed OS 上的连接字符串连接到 Azure IoT?

    使用 NuMaker 板和 Mbed OS 上的连接字符串连接到 Azure IoT
    发表于 09-04 07:46

    非对称密钥生成和转换规格详解

    当前章节将说明系统目前支持的算法及其对应的规格。密钥生成有两种指定规格的方式,分别是: 字符串参数:以字符串的形式描述开发者需要生成的密钥规格。 密钥参数:使用密钥的详细密码学信息,构造密钥对象
    发表于 09-01 07:50

    LM3466 多 LED 电流平衡器技术手册

    到电源的数或每个 LED 的正向电压 字符串。 如果任何 LED 灯在运行过程中打开,LM3466 会自动平衡通过所有剩余活动 LED 灯的电源电流。 如 因此,即使一些 LED
    的头像 发表于 08-29 14:27 1167次阅读
    LM3466 多<b class='flag-5'>串</b> LED 电流平衡器技术手册

    labview如何生成一个带字符串返回的dll

    labview如何生成一个dll,如下图,要求一个输入,类型是字符串,返回类型也是字符串
    发表于 08-28 23:20

    在Python中字符串逆序有几种方式,代码是什么

    对于一个给定的字符串,逆序输出,这个任务对于python来说是一种很简单的操作,毕竟强大的列表和字符串处理的一些列函数足以应付这些问题 了,今天总结了一下python中对于字符串的逆序输出的几种常用
    的头像 发表于 08-28 14:44 1277次阅读

    SQL 通用数据类型

    如何与存储的数据进行交互。 下面的表格列出了 SQL 中通用的数据类型: 数据类型 描述 CHARACTER(n) 字符/字符串。固定长度 n。 VARCHAR(n) 或 CHARACTER VARYING(n) 字符/
    的头像 发表于 08-18 09:46 856次阅读

    为啥51单片机能搞,峰岹的就会报错呢?

    如图图1是stc系列单片机的代码,发送字符串都可以,但是图二峰岹的代码发送字符串就不行,会报错
    发表于 07-09 13:39

    harmony-utils之StrUtil,字符串工具类

    harmony-utils之StrUtil,字符串工具类 harmony-utils 简介与说明 [harmony-utils] 一款功能丰富且极易上手的HarmonyOS工具库,借助众多实用工具类
    的头像 发表于 07-03 11:32 775次阅读