大小写转换和性能

前言

本文主要讨论最基本的一些大小写转换函数和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%。

http://blog.csdn.net/magictong/article/details/44756599

C++大小写转换和性能(C语言,C++,API,STL一共4种方法)的更多相关文章

  1. C++大小写转换和性能

    p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; f ...

  2. C语言清空输入缓冲区的N种方法对比

    转自C语言清空输入缓冲区的N种方法对比 C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int get ...

  3. R语言中样本平衡的几种方法

    R语言中样本平衡的几种方法 在对不平衡的分类数据集进行建模时,机器学习算法可能并不稳定,其预测结果甚至可能是有偏的,而预测精度此时也变得带有误导性.在不平衡的数据中,任一算法都没法从样本量少的类中获取 ...

  4. C语言数据结构-创建链表的四种方法

    结点类型: typedef int datatype; typedef struct NODE{ datatype data; struct NODE *next; }Node,*LinkList; ...

  5. C语言结构体定义的几种方法

    什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类.结构体可以被声明为变量.指针或数组等,用以实现较复杂的数据 ...

  6. C语言结构体初始化的四种方法(转载)

    原文:https://blog.csdn.net/ericbar/article/details/79567108 定义 struct InitMember { int first: double s ...

  7. C语言提高代码效率的几种方法

    一段完美的代码不仅在于找到一个给定的问题的解决方案,但在它的简单性,有效性,紧凑性和效率(内存).设计的代码比实际执行更难.因此,每一个程序员当用C语言开发时,都应该保持这些基本的东西在头脑中.本文向 ...

  8. C语言播放声音最简单的两种方法

    1. 假设仅须要播放波形文件wav格式的声音,非常easy.仅仅需一句话: PlaySound(TEXT("Data\\1.wav"), NULL, SND_FILENAME | ...

  9. C语言结构体初始化的四种方法

    定义 struct InitMember{    int first:    double second:    char* third:    float four;}; 方法一:定义时赋值 str ...

随机推荐

  1. 单点登录原理与简单实现--good

    一.单系统登录机制 1.http无状态协议 web应用采用browser/server架构,http作为通信协议.http是无状态协议,浏览器的每一次请求,服务器会独立处理,不与之前或之后的请求产生关 ...

  2. struts2和velocity整合问题

    以下是我第一次使用velocity的时候写的 2012-03-12 话说struts真够懒的,都把velocity-1.6.4.jar放到他自己的lib里边了,就不给放全了,搞得新手太郁闷了.stru ...

  3. JSP页面中taglib的uri设置

    今天遇到这样一个问题,使用JAVA做了个WEB应用,其中用到一个自定义标签.该标签的class文件与tld(tld文件中,uri定义为:http://wallimn.iteye.com/myfuncs ...

  4. docker入门1: Dockerfile介绍

    Dockerfile是为快速构建docker image而设计的,当你使用dockerbuild 命令的时候,docker 会读取当前目录下的命名为Dockerfile(首字母大写)的纯文本文件并执行 ...

  5. CUDA页锁定内存(Pinned Memory)

    对CUDA架构而言,主机端的内存被分为两种,一种是可分页内存(pageable memroy)和页锁定内存(page-lock或 pinned).可分页内存是由操作系统API malloc()在主机上 ...

  6. R 语言基本操作(基本信息的查看、与本地文件系统交互、编译器版本升级)

    0. 信息及路径的查看 getwd() ⇒ 查看路径: setwd() ⇒ 设置路径: .libPaths() ⇒ R 语言库所在的位置: sessionInfo() ⇒ 查询版本及系统和库等信息: ...

  7. Cocos2dx 温馨提示(十)三种缓存类演示

    在介绍了三级缓存,首先,我们必须弄清楚的一个问题:什么是纹理?它的通俗的解释,质感是它的含义的图片. 当图像加载到内存中后,,它是存在于纹理的形式.由于从这里可以看出.纹理事实上就是一块内存.这块内存 ...

  8. ElasticSearch的基本用法与集群搭建 good

    一.简介 ElasticSearch和Solr都是基于Lucene的搜索引擎,不过ElasticSearch天生支持分布式,而Solr是4.0版本后的SolrCloud才是分布式版本,Solr的分布式 ...

  9. WPF 3D动态加载模型文件

    原文:WPF 3D动态加载模型文件 这篇文章需要读者对WPF 3D有一个基本了解,至少看过官方的MSDN例子. 一般来说关于WPF使用3D的例子,都是下面的流程: 1.美工用3DMAX做好模型,生成一 ...

  10. 如何直接访问WEB-INF下列文件

    <servlet> <servlet-name>HE</servlet-name> <jsp-file>/WEB-INF/u_member/Login. ...