我们不需要字符串类型

标签: 程序员 array C++ string | 发表时间:2013-12-01 21:53 | 作者:zzzworm
出处:http://blog.jobbole.com

字符串是应该作为内置类型还是仅仅作为字符数组的一个别名呢?考虑到实现细节的可选性,我并不认为需要对字符串进行类型特化。在C++看来,字符串和“vector”容器基本上是一样的,除了某些特殊操作,例如:大小写转换,需要依赖容器元素“char”类型(而不是作用于容器本身)。

 

什么是字符串?

字符串除了是一系列的字符组成,没有什么特别的。更确切地说,程序中的字符串是特定字符集的字符集合。这里的字符并不总是图象字符,它可以包含可打印字符,连接字符,或者控制字符,那么这又有什么不同吗?

考虑计算字符串的长度,它应该返回的是字符串中字形字符、连接符号的总数还是应该返回字符串中字符占用空间的长度?两个字面等价但是内部存储不同的的字符串应该返回相同的长度吗?考虑字符串规范化的复杂程度和应用相同规则来计算‘length’长度听起来很荒唐可笑。不同场景下字符串的长度很难统一计算,而且这还依赖于字符渲染引擎。唯一有意义的是返回字符串存储空间大小——而这和计算字符数组的长度是一致的。

我们可以通过对字符串进行索引和取下标操作。那么我们应该使用字符字面索引还是字符存储索引?另外,考虑到组合Unicode字符串,没有统一的标准来衡量哪些字符是字面显示字符,哪些是控制字符。字符的组合种类很多(不受限制),因此没有固定的字符类型来定义一个“逻辑”字符。因此字符串的操作应该针对存储字符地址——这又和字符数组没有区别了。

 

C++中的不同

C++中的string和vector只有一个明显的区别是:string是以null结尾的。并且string提供c_str方法返回内部字符串存储指针。(C++11定义了string来表明这是存储字符串的有效方式)。

对C++来说,如果string不提供c_str方法,那么string类就基本没有存在的必要(相对于vector)。然而,这是也不是一个必须的特性,提供出来只是为了方便将string进行转换,从而方便调用早期C风格的字符串指针API。怪异的是,C++标准库也使用了类似的接口,ofstream的构造函数需要传递的是一个‘const char*’指针而不是string类型。(在C++11中修复了该问题)

使用null作为字符串结束符也是一个糟糕的选择,导致在C函数库中,一些函数如:strcat, strcpy并不安全。使用C风格的字符串是一件令人生畏且容易出错的差事。现代风格的API接口已经很少依赖使用null作为字符串结束,这些函数通常都要求提供字符串的长度作为一个参数。

导致C++中的string和vector有所不同,这是因为历史包袱,而大多数程序员都不需要关心它的存在。

 

字符代理和变长字符编码

前述的讨论基于这样一个假设:字符串存储中一个存储元素编码一个字符。而通常采用这种编码方式是效率低下的,使用变长字符编码可以解决这个问题:使用不同数量的字节来表示一个字符。例如:在UTF-16中,一个字符可以由2个字节或者4个字节进行存储。而不存储字符的单元作为存储序列的一部分,被叫做字符代理。

字符代理和连接字符不同。字符代理在字符集中没有意义:它只是用来填充编码占位。对字符的到操作依赖以实际存储元素位置。将编码字符串当作一系列的字符来操作,通常很麻烦而且容易导致未知语义。编码字符串的length应该返回什么值呢?是编码字符的个数还是存储元素的个数?

目前的方法是,将编码字符串作为一种特殊字符类型,并提供一定程度的抽象,你可要存储各种类型的字符,也可以将其作为一个字符序列操作。length返回字符的个数,而与底层编码方式无关(或者通过其他方法返回)。

设计这个类的挑战在于效率。基本操作如索引字符变成了一个线性复杂度操作。需要先对字符串进行解码,从开始扫描,重新组织字符代理,并计算真实的字符个数。即便是简单的前向扫描也依赖以循环和下一个字符状态的解析。而这种操作负载在所有的基本操作都会被累积,比如拆分,翻译和正则表达式匹配。

目前(内置字符串类型)的语言并没有按这种方式操作字符串,考虑效率问题,这使得采用这种方式变得没有吸引力。而在字符域,加载字符,解码字符和对字符串进行处理则简单得多。这种方式会消耗更多内存,但是我认为这对于世界上现有的字符集来说并不是一个主要问题——尽管存在大量的字符集,但是相较其他集合则小得多。

 

函数库的支持

字符串有许多相对于简单数组的特殊操作:规范化、字符转换、正则表达式运算、字符解析、格式化、裁剪、编码等等。相对地,任何类型的“vector”都有一些特殊操作:数字可以累加,求平均,计算中位数。向量可以做变换,简化和栅格化。

值得探讨的是,一些集合运算是应该作为一个成员函数还是独立函数。如果上述操作作为一个成员函数,那么需要特地提供一个”string”类型。而上述操作提供为独立函数的话,使用原始”array”数组类型就可以工作了。显然,上述操作都可以写成独立函数,没有那个函数需要特别的处理,只需要提供array接口就可以了。

不过有一个语法上的特例,如果我把”str.toUpperCase()”提取为独立函数显得有点怪异。D语言则完全统一了函数调用语法。我预计C++也会跟随这一趋势,许多操作函数已经被当作独立函数提供而不是采用成员函数。似乎发展也倾向于独立函数。

如果独立函数可行,那么就没有必要提取一个string类。字符串操作可以写成作用于字符数组的独立函数。

 

字符串代表什么?

如果你的字符串不仅仅使用ASCI字符,通常可以考虑使用Unicode字符集,但是,也有可能在你的代码中,只使用了ascii码或者是latin-1编码。不过大多数字符串都不会仅限于此。有些语言,比如PHP,允许你在全局范围设定编码方式。使用string做标记,通常都不会做太多变化(译:我猜测作者的意思应该是大多数语言已经内置了string的编码方式,而且不允许调整)。

我们假定字符集使用ascii编码,以ascii编码的字符串使用一个模版类string。为了标识不同于其他字符集,我们把这个字符串类型标识为“char ascii”。一旦我们做了这样的设定,我们就不希望再感受到string的类型了,它工作起来就和数组很相似了。

回到刚才谈到的变长编码:如果你使用UTF-16编码字符,并且需要使用字符代理。现在string变得含义模糊了,string应该被当做unicode字符组合还是真实的utf16编码值?(沿用刚才的实现)使用一个类型别名标识比较合适,我们假定为“type utf16:binary 16bit”,并作为一个数组。现在歧义消除了,字符串是编码值的集合,而不是字符。

 

仅仅是一个typedef?

现在我觉得不需要定义一个特殊的string类型,如果需要string类型,可以仅仅使用一个数组的别名。但是string作为基础类型被大量使用,这也导致了许多问题。一些情况下需要着重考虑字符编码,使用特定类型的数组就会比较安全。同时也需要一个富字符串处理函数库,但是不应该作为一个字符串类型(string)提供。

你能举例有什么情况下需要专门的string类型,或者这样做会更有效吗?

我们不需要字符串类型,首发于 博客 - 伯乐在线

相关 [需要 字符串 类型] 推荐:

我们不需要字符串类型

- - 博客 - 伯乐在线
字符串是应该作为内置类型还是仅仅作为字符数组的一个别名呢. 考虑到实现细节的可选性,我并不认为需要对字符串进行类型特化. 在C++看来,字符串和“vector”容器基本上是一样的,除了某些特殊操作,例如:大小写转换,需要依赖容器元素“char”类型(而不是作用于容器本身). 字符串除了是一系列的字符组成,没有什么特别的.

为什么黑客偏爱字符串数据类型呢【译】

- - 博客园_首页
    字符串数据类型是经常在代码里用于存储硬编码(直接做为固定内容写入了程序,类似于常量)的密钥. 这些可以通用的文字密钥用于连接字符串或特定业务密钥(如优惠券代码,许可证密钥等). 事实上,绝大多数存在于开发应用内的字符串数据类型的敏感数据,让黑客颇感兴趣. 在这篇文章中,我们将介绍一些黑客们过去时常存储在字符串里敏感信息技术.

字符串匹配那些事(一)

- jiessie - 搜索技术博客-淘宝
本系列文章主要介绍几种常用的字符串比较算法,包括但不限于蛮力匹配算法,KMP算法,BM算法,Horspool算法,Sunday算法,fastsearch算法,KR算法等等. 本文主要介绍KMP算法和BM算法,它们分别是前缀匹配和后缀匹配的经典算法. 所谓前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从左到右;所谓后缀匹配是指:模式串和母串的的比较从右到左,模式串的移动从左到右.

字符串匹配的Boyer-Moore算法

- - 阮一峰的网络日志
上一篇文章,我介绍了 KMP算法. 但是,它并不是效率最高的算法,实际采用并不多. 各种文本编辑器的"查找"功能(Ctrl+F),大多采用 Boyer-Moore算法. Boyer-Moore算法不仅效率高,而且构思巧妙,容易理解. 1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了这种算法.

JavaScript中的字符串操作

- - CSDN博客推荐文章
JavaScript中的字符串操作.    字符串在JavaScript中几乎无处不在,在你处理用户的输入数据的时候,在读取或设置DOM对象的属性时,在操作cookie时,当然还有更多.... JavaScript的核心部分提供了一组属性和方法用于通用的字符串操作,如分割字符串,改变字符串的大小写,操作子字符串等.

字符串匹配的KMP算法

- - 博客园_知识库
   字符串匹配是计算机的基本任务之一.   举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD".   许多算法可以完成这个任务, Knuth-Morris-Pratt算法(简称KMP)是最常用的之一. 它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth.

字符串相似算法-Jaro-Winkler Distance

- - 开源软件 - ITeye博客
Jaro-Winkler Distance 算法. 这是一种计算两个字符串之间相似度的方法,想必都听过Edit Distance,Jaro-inkler Distance 是Jaro Distance的一个扩展,而Jaro Distance(Jaro 1989;1995)据说是用来判定健康记录上两个名字是否相同,也有说是是用于人口普查,具体干什么就不管了,让我们先来看一下Jaro Distance的定义.

HTML字符实体(Character Entities),转义字符串(Escape Sequence) 为什么要用转义字符串?

- - CSDN博客推荐文章
HTML字符实体(Character Entities),转义字符串(Escape Sequence). HTML中<,>,&等有特殊含义(<,>,用于链接签,&用于转义),不能直接使用. 这些符号是不显示在我们最终看到的网页里的,那如果我们希望在网页中显示这些符号,该怎么办呢. 这就要说到HTML转义字符串(Escape Sequence)了.

geohash:用字符串实现附近地点搜索 - idv2

- 猪头小队长 - tech.idv2.com
上回说到了用经纬度范围实现附近地点搜索. 一些小型应用中这样做没问题,但在大型应用中它有个显著的缺点:速度慢. 慢的原因有两个, 第一是范围比较的索引利用率并不高,第二是SQL语句极其不稳定(不同的当前位置会产生完全不同的SQL查询),很难缓存. 可以考虑使用geohash算法. geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串.