详细谈谈iOS字符串翻转
前言
字符串翻转作为算法题已经是一个不能再基础的问题了,无非就是逆序遍历、双指针遍历、递归,代码也能分分钟写出来:
voidstrrev(char*str){ size_tstart=0; size_tend=start+strlen(str)-1; while(startOK,上面的代码放到LeetCode上绝对是能AC的,但是实际情况中能AC吗?答案肯定是不能的!一个靠谱的字符串翻转算法题放到LeetCode上至少是Medium的难度。
首先我们知道字符串有编码规则,比如我们常用的UTF-8,Windows早期采用的UTF-16(函数名有W后缀的API采用这种编码)等等...对于英文字母等ASCII字符的情况,UTF-8和ASCII编码都是一个字节,所以上述的方法没有太大问题。然而对于有中文的情况,一个中文字符在UTF-8中会占3个字节,如果单纯的按字节翻转就会出现乱码。
那怎么解决呢?
最简单的方法就是使用mbstowcs函数将char*类型的字符串转换为wchar_t类型的宽字符串,wchar_t这个类型在Linux、UNIX系统上占4个字节,在Windows上占2个字节。4个字节意味着字符将用UTF-32来编码,不管是汉字还是Emoji都能存放下来。但对于2个字节,也就是UTF-16,汉字是能表示,但是Emoji这类位于辅助平面码位的字符需要两个码元来表示,本文的方法就暂不适用了。
首先我们来看一下改进版的字符串翻转:
staticvoidstrrev2(char*str){ setlocale(LC_CTYPE,"UTF-8"); size_tlen=mbstowcs(NULL,str,0); wchar_t*wcs=(wchar_t*)calloc(len+1,sizeof(wchar_t)); mbstowcs(wcs,str,len+1); size_tstart=0; size_tend=start+len-1; while(start使用mbstowcs这类转换函数首先需要设置字符串的系统编码,不然函数无法确定你传入的char*是个什么东西,本文中不管是源码还是系统环境的stdI/O都采用UTF-8编码。
接下来我们调用一次mbstowcs不传入目标地址和字符长度,这可以让函数直接计算所需的wchar_t个数并返回回来以便我们申请内存。
然后就是基于wchar_t的一个常规字符串翻转了,最后别忘了转换回去,释放内存即可。
Bonus:Cocoa开发中的字符串翻转
作为iOS开发者,当然还要考虑OC中的解决方法了。
方案1:
通过API遍历子串,然后前向插入到新的NSMutableString中。
-(NSString*)my_stringByReversing{ NSMutableString*reversed=[NSMutableStringstringWithCapacity:self.length]; NSRangerange=NSMakeRange(0,self.length); [selfenumerateSubstringsInRange:range options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString*_Nullablesubstring,NSRangesubstringRange, NSRangeenclosingRange,BOOL*_Nonnullstop){ [reversedinsertString:substringatIndex:0]; }]; return[reversedcopy]; }这种方法是效果最好的,它会将ComposedEmoji(如