p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; font-size: 10.5pt; font-family: "Calibri", "sans-serif" }
p.MsoHeader,li.MsoHeader,div.MsoHeader { margin: 0cm; margin-bottom: .0001pt; text-align: center; border: none; padding: 0cm; font-size: 9.0pt; font-family: "Calibri", "sans-serif" }
p.MsoFooter,li.MsoFooter,div.MsoFooter { margin: 0cm; margin-bottom: .0001pt; font-size: 9.0pt; font-family: "Calibri", "sans-serif" }
span.Char { }
span.Char0 { }
div.WordSection1 { }

大小写转换和性能

前言

本文主要讨论最基本的一些大小写转换函数和API,不讨论一些常见的字符串程序库里面的大小写转换接口,另外本文的落脚点是这些转换函数的性能和日常开发中遇到的一些问题。

不考虑范围

其实ctype.h里面有定义一套宏,就是不考虑字符是否落在A-Z,a-z范围,直接计算(直接用加减法或者使用位与或计算,差别不是很大)。显然这样的效率是最高的,但是使用可能是有问题的,遇到中文或者其他友邦的一些字符,可能就转换错了,当然如果已经提前确认过输入会落在A-Z,a-z范围,则是可以使用这种方法计算的。

#define _tolower(_Char)    ( (_Char)-'A'+'a' )

#define _toupper(_Char)    ( (_Char)-'a'+'A' )

C库(MS)

转小写

tolower

towlower

_tolower_l

_towlower_l

转大写

toupper

towupper

_toupper_l

_towupper_l

C库没有提供直接转换整个字符串的函数,都只能转换单个字符。另外要注意的是提供的towlower和towupper这两个函数效率出奇的低,为什么效率低没有去深究,反正tolower和toupper的参数是int,也可以用于宽字符版本,不知道为什么还提供towlower和towupper这两个函数。

C++库(MS)

转小写

errno_t _strlwr_s(char* str, size_t numberOfElements);

errno_t _wcslwr_s(wchar_t* str, size_t numberOfElements);

转大写

errno_t _strupr_s(char* str, size_t numberOfElements);

errno_t _wcsupr_s(wchar_t* str, size_t numberOfElements);

同时还提供了一套同名的模版函数,可以直接只传递字符数组名进行转换,原理是利用数组引用推导出了数组大小,再调用原始转换函数,微软在字符串处理函数里面,使用了很多类似的小技巧(crtdefs.h)。

注:带_s后缀的表示是安全转换。

__DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_0(errno_t, _wcslwr_s, __inout_ecount(_Size)wchar_t, _String)

#define __DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_0(_ReturnType, _FuncName,_DstType, _Dst) \

extern "C++" \

{ \

template <size_t _Size> \

inline \

_ReturnType __CRTDECL _FuncName(_DstType (&_Dst)[_Size])\

{ \

return _FuncName(_Dst, _Size);\

} \

}

Windows API

转小写

CharLower

CharLowerBuff

转大写

CharUpper

CharUpperBuff

WindowsAPI大部分都是一些宏,对应的多字节版本和宽字符版本在上面的API后面加上A和W。

STL库

STL里面的string没有提供专门的转换接口,但是借助STL里面的算法用类似下面的方法实现(转换函数可以自定义,也可以使用系统提供的函数),这个不多说。

transform(strCostInfo2.begin(), strCostInfo2.end(), strCostInfo2.begin(),::tolower);

transform(strCostInfo2.begin(), strCostInfo2.end(), strCostInfo2.begin(),::toupper);

自己实现(考虑范围)

//////////////////////////////////////////////////////////////////////////

static const char s_ch_a_minus_A = 'a' - 'A';

inline char ConvToUpperA(char chConv)

{

return (chConv >= 'a' && chConv <= 'z')? (chConv & 0xdf) : chConv;

}

inline wchar_t ConvToUpperW(wchar_t wchConv)

{

return (wchConv >= L'a' && wchConv<= L'z') ? (wchConv & 0x00df) : wchConv;

}

inline char ConvToLowerA(char chConv)

{

return (chConv >= 'A' && chConv <= 'Z')? (chConv | 0x20) : chConv;

}

inline wchar_t ConvToLowerW(wchar_t wchConv)

{

return (wchConv >= L'A' && wchConv<= L'Z') ? (wchConv | 0x0020) : wchConv;

}

inline void ConvStrToUpperA(char* strConv)

{

for (size_t i = 0; strConv[i] != '\0'; ++i)

{

//if(strConv[i] >= 'a'&& strConv[i] <= 'z')

//   strConv[i] &= 0xdf;

strConv[i] = ConvToUpperA(strConv[i]);

}

}

inline void ConvStrToUpperW(wchar_t* strConv)

{

for (size_t i = 0; strConv[i] != L'\0'; ++i)

{

//if(strConv[i] >=L'a' && strConv[i] <= L'z')

//   strConv[i] &= 0x00df;

strConv[i] = ConvToUpperW(strConv[i]);

}

}

inline void ConvStrToLowerA(char* strConv)

{

for (size_t i = 0; strConv[i] != '\0'; ++i)

{

//if(strConv[i] >= 'A'&& strConv[i] <= 'Z')

//   strConv[i]|= 0x20;

strConv[i] = ConvToLowerA(strConv[i]);

}

}

inline void ConvStrToLowerW(wchar_t* strConv)

{

for (size_t i = 0; strConv[i] != L'\0'; ++i)

{

//if(strConv[i] >=L'A' && strConv[i] <= L'Z')

//   strConv[i] |= 0x0020;

strConv[i] = ConvToLowerW(strConv[i]);

}

}

和直接转换的区别就在于只对A-Z,a-z范围的字符进行转换,有一定局限性,但是在大部分场景下是可用的,而且效率够好。

性能

说了这么多转换方法,其实我最关心的那种方法的效率最高,直接上测试程序和测试环境吧,让数据说话。

测试环境

Windows7 x64 SP1

AMD Phenom(tm) II X4 840T(4核)

10G内存

测试基本方法

对长度1024字节(不包括结尾0)的字符串进行大小写轮换转换,循环百万次,统计时间。

测试结果

====>大小写转换函数时间消耗(循环1000000次)<====

直接计算(不考虑范围):[1077] 毫秒

C库函数:[6193]毫秒

C++库函数:[5912]毫秒

STL算法库模版函数(自定义转换):[3557] 毫秒

STL算法库模版函数(系统转换):[6146] 毫秒

自定义的函数:[3791] 毫秒

Windows API:[13884] 毫秒

====>大小写转换函数时间消耗(循环1000000次)<====

直接计算(不考虑范围):[1076] 毫秒

C库函数:[6272]毫秒

C++库函数:[5865]毫秒

STL算法库模版函数(自定义转换):[3292] 毫秒

STL算法库模版函数(系统转换):[6053] 毫秒

自定义的函数:[3666] 毫秒

Windows API:[13790] 毫秒

多次测试结果表明,显然不考虑范围是最快的,但是可用场景太少,其次就是自定义的大小写转换函数了(像中文之类也没有大小写之说,只需要考虑有限的ascii字符),配合STL的容器和算法可以最大化效率。WindowsAPI的效率则比较低,当然效率低的原因并不是算法的问题,而是考虑的情况比较多,譬如要考虑本地化,考虑一些语种特殊的大小写转换问题等等。

在合适的场景下,使用自定义的大小写转换是完全足够,研究这个花了大约半天时间,问题源于一个URL处理函数的性能问题,经过统计发现,这个函数的大量计算消耗在了URL转小写上面,经过改造之后,性能轻松提升60%。

C++大小写转换和性能的更多相关文章

  1. C++大小写转换和性能(C语言,C++,API,STL一共4种方法)

    大小写转换和性能 前言 本文主要讨论最基本的一些大小写转换函数和API,不讨论一些常见的字符串程序库里面的大小写转换接口,另外本文的落脚点是这些转换函数的性能和日常开发中遇到的一些问题. 不考虑范围 ...

  2. Python 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)

    去空格及特殊符号 s.strip().lstrip().rstrip(',') 复制字符串 #strcpy(sStr1,sStr2) sStr1 = 'strcpy' sStr2 = sStr1 sS ...

  3. js中实现字母大小写转换

    js中实现字母大小写转换主要用到了四个js函数: 1.toLocaleUpperCase  2.toUpperCase3.toLocaleLowerCase4.toLowerCase 下面就这四个实现 ...

  4. IntelliJ IDEA大小写转换快捷键

    IntelliJ IDEA大小写转换快捷键 Ctr + Shift + u

  5. 黄聪:PHP字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、切割成数组等)

    一.字符串替换 str_replace("iwind", "kiki", "i love iwind, iwind said"); 将输出 ...

  6. 用vim处理字符的大小写转换

    转载: http://blog.csdn.net/ruixj/article/details/3765385 http://www.linuxsong.org/2010/09/vim-convert- ...

  7. php 字母大小写转换的函数

    分享下,在php编程中,将字母大小写进行转换的常用函数. 1.将字符串转换成小写strtolower(): 该函数将传入的字符串参数所有的字符都转换成小写,并以小定形式放回这个字符串 2.将字符转成大 ...

  8. 大小写转换,split分割

    一.大小写转换 1.定义和用法 toUpperCase() 方法用于把字符串转换为大写. toLowerCase() 方法用于把字符串转换为小写.    用法: stringObject.toUppe ...

  9. input输入字母自动大小写转换

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

随机推荐

  1. Bootstrap3 栅格系统-嵌套列

    为了使用内置的栅格系统将内容再次嵌套,可以通过添加一个新的 .row 元素和一系列 .col-sm-* 元素到已经存在的 .col-sm-* 元素内.被嵌套的行(row)所包含的列(column)的个 ...

  2. hive中的NULL(hive空值处理)

    HIVE表中默认将NULL存为\N,可查看表的源文件(hadoop fs -cat或者hadoop fs -text),文件中存储大量\N, 这样造成浪费大量空间.而且用java.python直接进入 ...

  3. HA机制下的Hadoop配置

    [版权申明:本文系作者原创,转载请注明出处] 文章出处:http://www.cnblogs.com/sdksdk0/p/5585355.html 作者: 朱培    ID:sdksdk0 ----- ...

  4. Mac上如何完美的转换epub至mobi供kindle观看

    网上有很多书籍资源的格式都是epub(我们不谈及pdf格式了,你懂得-),epub格式是无法直接在kindle上观赏的,除非你越狱kinde后,安装扩展插件 我们可以将epub转换为mobi格式,网上 ...

  5. (Java)微信之个人公众账号开发(一)——进入开发者模式

    本篇文章将教大家如何建立微信个人公众账号,(注意:后台全部是用javaweb相关技术开发),大家知道,现在微信公众账号分服务号和订阅号,现在我要讲的主要是个人微信公众账号的建立以及后台的开发,个人公众 ...

  6. Leetcode解题-链表(2.2.3)PartitionList

    题目:2.2.3 Partition List Given a linked list and a value x, partition it such that all nodes less tha ...

  7. Java程序员必须掌握的线程知识-Callable和Future

    Callable和Future出现的原因 创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需 ...

  8. char能表示(-128~127)

    char 的取值范围是 -128 ~127 注:数0的补码表示是唯一的: +0的补码=+0的反码=+0的原码=00000000 -0的补码=11111111+1=00000000(mod 2的8次方) ...

  9. 一个都不能少: DevOps的3大核心基础架构

    DevOps的涵盖面非常广,因为这个概念的火热,又有很多文章和技术都在把DevOps的帽子扣在自己头上,让很多人迷惑不解.其实,DevOps的知识体系如果从顶层上来分解,只有2块:方法论和工具链.方法 ...

  10. 带你深入理解STL之Deque容器

    在介绍STL的deque的容器之前,我们先来总结一下vector和list的优缺点.vector在内存中是分配一段连续的内存空间进行存储,其迭代器采用原生指针即可,因此其支持随机访问和存储,支持下标操 ...