2011-12-31 73 views
3

前段时间我听到有关如何创建模板化字符串类的讨论,您不应该使用strcmp,strcpy和strlen作为可以使用UTF8和UTF16的模板化字符串类。从我记得的,你想使用algorithm.h中的函数,但是,我不记得实现是如何的,或者它为什么如此。有人可以解释一下使用什么函数,如何使用它们,为什么?模板化字符串类使用strcmp,strcpy和strlen

模板化串类的例子是如

String<UTF8> utf8String; 
String<UTF16> utf16String; 

东西例如这是UTF8将是一个无符号的字符和UTF16是一个无符号短。

+0

头部被命名为'algorithm',而不是'algorithm.h'。另外,如果你做了很多C++编程,熟悉标准库会很有帮助,所以你不必问什么是可用的,所以你会更容易识别任何随机的情况,在这种情况下库算法是完美的。我看到很多代码是不应该写的,但作者并不知道标准库有一个算法。 http://en.cppreference.com/w/cpp/algorithm – bames53 2011-12-31 09:32:58

回答

6

首先,C++不需要额外的字符串类。可能已经有数百或数千个已经开发出来的太多的字符串类,而且你的情况也不会改善。除非你完全是为了你的熏陶而做这件事,否则你应该考虑漫长而艰难,然后决定不写一个新的。

可以使用std::basic_string<char>保持UTF-8代码单元序列,std::basic_string<char16_t>保持UTF-16代码单元序列,std::basic_string<char32_t>保持UTF-32代码单元序列等C++甚至提供了这些类型的短,方便的名称: string,u16stringu32stringbasic_string已经通过提供用于复制,比较和获取字符串长度的成员函数解决了您在此处提出的问题,该字符串适用于您对其进行模板化的任何代码单元。

我想不出有什么好的理由,因为新代码并没有与遗留代码进行交互,而是使用其他任何东西作为字符串的规范存储类型。即使你使用其他的遗留代码进行交互,如果该接口的表面面积不大,你应该仍然可以使用其中一种标准类型,而不是其他任何东西,当然如果你使用遗留代码无论如何,你都会使用这种遗留类型,而不是编写自己的新类型。


虽这么说,你不能strcmpstrcpy,并strlen您的模板字符串类型使用的原因是,他们都在空终止字节序列进行操作。如果您的代码单元大于一个字节,则可能有字节在实际终止空值代码单元(假设您根本不应该使用空终止)之前为零。考虑字符串“Hello”的UTF-16表示字节(在一个小端机器上)。

48 00 65 00 6c 00 6c 00 6f 00 

由于UTF-16使用16个编码单元,字符 'H' 最终存储为两个字节48 00。通过假定第一个空字节为结尾来操作上述字节序列的函数将假定第一个字符的后半部分标记整个字符串的结尾。这显然是行不通的。

因此,strcmp,strcpystrlen都是可以更一般地实现的算法的专用版本。由于它们只能与字节序列一起工作,并且您需要使用代码单元序列,其中代码单元可能大于一个字节,因此您需要使用可以与任何代码单元一起使用的通用算法。标准库提供了许多通用算法可供您使用。这里是我的建议来取代这些str*函数。

strcmp比较两个代码单元序列,如果两个序列相等,则返回0;如果第一个按字典顺序小于第二个,则返回正数;否则返回负数。标准库包含通用算法lexicographical_compare,它的功能几乎相同,只是如果第一个序列按字典顺序小于第二个序列,否则返回true,否则返回false。

strcpy复制一系列代码单元。您可以使用标准库的copy算法。

strlen需要一个指向代码单元的指针并在发现空值之前计算代码单元的数量。如果你需要这个函数,而不是只告诉你字符串中代码单元数量的函数,你可以通过传递空值作为找到的值来使用算法find来实现它。如果您想要查找序列的实际长度,那么您的课程应提供一个size方法,该方法可直接访问您的课程在内部使用的任何方法来存储该尺寸。

str*函数不同,我建议的算法需要两个迭代器来划分代码单元序列;一个指向序列中的第一个元素,另一个指向序列最后一个元素之后的位置。 str*函数只需要一个指向第一个元素的指针,然后假设该序列一直持续到它找到的第一个零值代码单元为止。当你实现你自己的模板化字符串类时,最好远离显式的空终止约定,并且只提供一个为你的字符串提供正确端点的方法。

+0

IMO最好留给非会员功能。我认为实现Unicode支持的好模式可能是迭代器适配器。你可能有一个需要一个UTF-8代码单元迭代器(例如来自'std :: string :: begin()')并充当代码点迭代器。然后你可以有一个迭代器适配器,它通过使用代码点迭代器来实现Unicode字形边界算法,并允许你迭代字形。然后需要在代码点或字形上工作的算法只需要适当修改的迭代器。实际上不需要更多的字符串类。 – bames53 2011-12-31 09:49:40

+0

我认为像priority_queue这样的容器适配器并不能算作一个全新的字符串类。它会比全新的字符串类更少冒犯,尽管它仍然表现出一些相同的问题。 – bames53 2011-12-31 10:33:49

+0

@DietmarKühl坦率地说,我不知道它有多少可以保护用户。例如。如果它允许面向代码点的访问,并且用户试图做一些应该在用户感知角色级别完成的事情,他们将能够做错误的事情。我认为平衡我喜欢一个标准的字符串类型到自定义类型可能提供的任何小安全。 – bames53 2011-12-31 10:45:47

2

您不能使用strcmp,strcpystrlen的原因是它们对长度由终止零字节指示的字符串进行操作。由于您的字符串可能包含零字节,因此您无法使用这些函数。

我只是准确地编码你想要的。你想要什么取决于你想要做什么。

1

在UTF16中,您可能会在字符串中间看到等于的字节; strcmp,strcpystrlen将返回错误的字符串结果,因为它们在假设字符串是零终止的情况下运行。

根据基于模板的迭代器,可以使用STL的副本,等于和距离来复制,比较和计算长度。

+0

虽然我看到std :: copy,但没有看到用于比较和计算的函数。您能否像原始问题中提到的那样详细说明这一点? – mmurphy 2011-12-31 06:34:30

+0

@mmurphy使用['lexicographical_compare'](http://www.sgi.com/tech/stl/lexicographical_compare.html)按字母顺序或['equal']进行比较(http://www.sgi.com/tech/ stl/equal.html)比较是否相等。使用['distance'](http://www.sgi.com/tech/stl/distance.html)计算指向字符串开始和结尾的两个迭代器之间的项目数。 – dasblinkenlight 2011-12-31 06:44:14