我无法理解std::string和std::wstring之间的区别。我知道wstring支持宽字符,如unicode字符。我有以下问题:
我什么时候应该使用std::wstring而不是std::string?
std::string能否保存整个ASCII字符集,包括特殊字符?
EDCOX1?1是由所有流行的C++编译器支持的吗?
什么才是"宽性格"?
- ASCII字符集没有很多"特殊"字符,最奇特的字符可能是`(后引号)。std::string可以容纳大约0.025%的Unicode字符(通常为8位字符)
- 如果"特殊"是指128到255之间的字符,这取决于所使用的规范,则支持"是"。
- 关于宽字符和使用哪种类型的好信息可以在这里找到:programmers.stackexchange.com/questions/102205/…
- 好吧,既然我们是在2012年,utf8everywhere.org就被编写出来了。它几乎可以回答所有关于C++和Windows的关于权利和错误的问题。
- @msaltters:std::string可以容纳所有Unicode字符的100%,即使char_位是8。它取决于std::string的编码,在系统级别(除了Windows以外几乎所有地方都是这样)或应用程序级别上,它可能是utf-8。本机窄编码不支持Unicode?没问题,只是不要使用它,而是使用UTF-8。
- 关于基于winapi的应用程序,使用std::string非常不方便,因为您将经常进行转换(unicode<->ansi)。当然,您可以使用winapi函数的ansi别名,但它们只是将您的ansi编码参数隐式转换为unicode参数并调用基于unicode的"real"api代码的宏(请参阅J.Richter"Programming Windows"第5版)。
- 关于这个主题的伟大阅读:utf8everywhere.org
EDOCX1?0?EDOCX1?1?
std::string是在char上模板化的basic_string,在wchar_t上模板化的std::wstring。好的。char对wchar_t的比较
char应该包含一个字符,通常是一个8位字符。wchar_t应该具有广泛的特点,然后事情变得复杂起来:在Linux上,wchar_t是4个字节,而在Windows上是2个字节。好的。那Unicode呢?
问题是,char和wchar_t都不是直接与unicode联系在一起的。好的。在Linux上?
以Linux操作系统为例:我的Ubuntu系统已经支持Unicode。当我使用char字符串时,它是以utf-8(即unicode字符字符串)进行本机编码的。以下代码:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <cstring>
#include <iostream>
int main(int argc, char* argv[])
{
const char text[] ="olé" ;
std::cout <<"sizeof(char) :" << sizeof(char) << std::endl ;
std::cout <<"text :" << text << std::endl ;
std::cout <<"sizeof(text) :" << sizeof(text) << std::endl ;
std::cout <<"strlen(text) :" << strlen(text) << std::endl ;
std::cout <<"text(ordinals) :" ;
for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
{
std::cout <<"" << static_cast<unsigned int>(
static_cast<unsigned char>(text[i])
);
}
std::cout << std::endl << std::endl ;
// - - -
const wchar_t wtext[] = L"olé" ;
std::cout <<"sizeof(wchar_t) :" << sizeof(wchar_t) << std::endl ;
//std::cout <<"wtext :" << wtext << std::endl ; <- error
std::cout <<"wtext : UNABLE TO CONVERT NATIVELY." << std::endl ;
std::wcout << L"wtext :" << wtext << std::endl;
std::cout <<"sizeof(wtext) :" << sizeof(wtext) << std::endl ;
std::cout <<"wcslen(wtext) :" << wcslen(wtext) << std::endl ;
std::cout <<"wtext(ordinals) :" ;
for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
{
std::cout <<"" << static_cast<unsigned int>(
static_cast<unsigned short>(wtext[i])
);
}
std::cout << std::endl << std::endl ;
return 0;
} |
输出以下文本:好的。
1 2 3 4 5 6 7 8 9 10 11 12
| sizeof(char) : 1
text : olé
sizeof(text) : 5
strlen(text) : 4
text(ordinals) : 111 108 195 169
sizeof(wchar_t) : 4
wtext : UNABLE TO CONVERT NATIVELY.
wtext : ol?
sizeof(wtext) : 16
wcslen(wtext) : 3
wtext(ordinals) : 111 108 233 |
您将看到char中的"ol_"文本实际上由四个字符构成:110、108、195和169(不包括尾随的零)。(我让你把wchar_t代码作为练习来学习)好的。
因此,在Linux上使用char时,您通常会在不知道的情况下使用Unicode。由于std::string与char一起工作,所以std::string已经可以使用Unicode了。好的。
注意,与C字符串API一样,std::string将认为"ol_"字符串有4个字符,而不是3个字符。因此,在截断/播放Unicode字符时应该谨慎,因为在UTF-8中禁止某些字符组合。好的。在Windows上?
在Windows上,这有点不同。在unicode出现之前,win32必须支持许多与char和世界上生产的不同字符集/代码页一起工作的应用程序。好的。
所以他们的解决方案是一个有趣的解决方案:如果一个应用程序与char一起工作,那么char字符串将使用机器上的本地charset/codepage编码/打印/显示在GUI标签上。例如,"ol_"在法文本地化的窗口中是"ol_",但在西里尔文本地化的窗口(如果使用Windows-1251,则为"ol_")上则有所不同。因此,"历史应用程序"的工作方式通常还是老样子。好的。
对于基于Unicode的应用程序,Windows使用2字节宽的wchar_t,并用utf-16编码,utf-16是Unicode编码的2字节字符(或者至少是最兼容的ucs-2,几乎与iirc相同)。好的。
使用char的应用程序称为"多字节"(因为每个glyph由一个或多个chars组成),而使用wchar_t的应用程序称为"宽字符"(因为每个glyph由一个或两个wchar_t组成)。有关详细信息,请参阅MultiByteToWideChar和WideChartoMultiByte Win32转换API。好的。
因此,如果您在Windows上工作,您非常希望使用wchar_t(除非您使用一个隐藏它的框架,如gtk+或qt…)。事实是,在幕后,Windows与wchar_t字符串一起工作,因此即使是历史应用程序,在使用类似于SetWindowText()的API(低级API函数在win32 GUI上设置标签)时,也会将其char字符串转换为wchar_t。好的。内存问题?
UTF-32是每个字符4个字节,因此没有什么可添加的,只要一个UTF-8文本和UTF-16文本总是比一个UTF-32文本使用更少或相同的内存量(通常更少)。好的。
如果存在内存问题,那么您应该知道,与大多数西方语言相比,UTF-8文本使用的内存将少于相同的UTF-16文本。好的。
不过,对于其他语言(中文、日文等),使用的内存将与UTF-8相同,或者略大于UTF-16。好的。
总而言之,UTF-16通常每个字符使用2个字节,有时使用4个字节(除非您正在处理某种深奥的语言符号(Klingon?精灵?),而utf-8将花费1到4个字节。好的。
有关详细信息,请参阅http://en.wikipedia.org/wiki/utf-8 compared to utf-16。好的。结论
什么时候应该在std::string上使用std::wstring?好的。
在Linux上?几乎从不(§)。在Windows上?几乎总是(§)。跨平台代码?取决于你的工具箱…好的。
(§):除非使用工具箱/框架,否则好的。
std::string是否可以保存所有的ASCII字符集,包括特殊字符?好的。
注意:std::string适用于保存"二进制"缓冲区,而std::wstring不适用于这种缓冲区!好的。
在Linux上?对。在Windows上?只有特殊字符可用于Windows用户的当前区域设置。好的。
编辑(在Johann Gerell的评论之后):一个std::string足以处理所有基于char的字符串(每个char都是0到255之间的数字)。但是:好的。
ASCII应该从0到127。较高的chars不是ASCII码。
从0到127的char将正确保持。
从128到255的char将根据编码(Unicode、非Unicode等)有意义,但只要用UTF-8编码,它就能够保存所有Unicode标志符号。
几乎所有流行的C++编译器都支持EDCOX1 7吗?好的。
大多数情况下,除了移植到Windows的基于GCC的编译器。它在我的G+4.4.2(Linux下)工作,我在VisualC++ 6上使用了Win32上的Unicode API。好的。
什么是宽字符?好的。
在C/C++上,它是一个EDCOX1×0的字符类型,它比简单的EDCOX1×2字符类型大。它应该用于放置索引(如Unicode标志符号)大于255(或127,具体取决于…)的字符。好的。
好啊。
- 哼哼。我不知道Windows在这方面没有遵循POSIX规范。posix说wchar-t必须能够表示"编译环境支持的区域设置中指定的最大字符集的所有成员的不同宽字符代码"。
- @GNUD:也许在UTF-16出现之前,wchar-t应该足以处理所有的ucs-2字符(大多数是utf-16字符)。或者,也许微软除了POSIX还有其他的优先级,比如在不修改char在win32上的代码页用法的情况下,可以方便地访问unicode。
- @gnud:注意wchar_t的定义,在维基百科上引用:en.wikipedia.org/wiki/wchar_t…很明显,为什么窗户上的车遵循Unicode的要求…^ ^…
- 你的回答确实很好地解释了两种选择之间的差异。备注:UTF-8可以占用1-6字节,而不是像您写的那样占用1-4字节。另外,我想看到人们对这两种选择的看法。
- @sorin sbarnea:utf-8可能需要1-6字节,但显然标准将其限制为1-4字节。更多信息请参见en.wikipedia.org/wiki/utf8描述。
- 在Mac OS X上编译和执行代码的输出与Linux机器上的输出相同。
- @沃尔夫冈:谢谢你的信息。这并不出乎意料,因为MacOSX是一个Unix,所以这看起来很自然,它们采用了"char是一个utf-8"的方式来支持Unicode…对于Afaik,Windows没有遵循相同的道路的唯一原因是继续支持基于前Unicode字符集的旧应用程序。
- @paercebal utf-8不能占用6个字节。正是因为标准将其限制为4个字节。标准定义了一些东西,所以6个字节意味着根据定义,它不再是UTF-8了。
- @米海尼塔:埃多克斯1〔0〕。我同意。我非常同意你的意见,我已经在之前的评论中写道:@Sorin Sbarnea: UTF-8 could take 1-6 bytes, but apparently the standard limits it to 1-4.…^ ^…我想我这句话的目的是提醒人们,对4的限制是人为的,UTF-8所使用的编码对于1字节字符最多可以支持6个字节,即使标准决定将其限制为4。
- 我想做includestd::wstring ws;ws+=wchar(2591);/*25%shade character*/std::wcout<
- @吉姆·迈克尔斯:你想输出字符X0A1F(古穆赫语)。wchar_t可以包含该字符,因此您的字符串是正确的。如果wcout输出不正确,可能是因为输出控制台的字体未准备好使用gurmukhi符号(unicode.org/charts/pdf/u0a00.pdf)。
- 虽然这个例子在Linux和Windows上产生了不同的结果,但是C++程序包含了实现DE。关于olè是否编码为utf-8的NED行为。此外,您不能将wchar_t *本地流到std::cout的原因是类型不兼容,导致程序格式不正确,与编码的使用无关。值得指出的是,使用std::string还是std::wstring取决于您自己的编码偏好,而不是平台,特别是如果您希望代码是可移植的。
- @约翰莱德格林:是的。事实上,关键是要证明这一点。以东十一〔九〕的确。我给出了多个组合,如果不可能的话,解释了为什么在代码中,为了完整起见,没有提出你建议的观点…
- @约翰·莱德格伦:是的。但是,如果约束条件是"使用Unicode,而不是每个字符使用4个字节",那么平台几乎限制了您的选项,即Windows上的std::wstring和Linux上的std::string……(您可以尝试在Windows上使用utf-8 std::string,但是使用char *字符的winapi将无法理解您的utf-8字符串。)
- @无论平台支持什么样的paercebal都是完全任意的,而且不包括要点。如果在Windows上将所有字符串内部存储为utf-8,则必须将它们转换为ansi或utf-16并调用相应的win32函数,但如果知道utf-8字符串只是普通的ASCII字符串,则无需执行任何操作。平台并没有像环境那样规定如何使用字符串。
- @约翰莱德格伦:当然,平台决定了你如何使用字符串。在Windows上,您别无选择:char字符串具有特定的代码页/编码,因此必须决定如何使用std::string,无论是通过编写转换器,还是使用特定于代码页的函数。至于std::wstring,除非您使用转换接口,否则您知道编码必须是Windows版本的utf-16(上次我检查时,它是ucs-2),因此您如何解释该上下文中的字符。正如我看到的,这是"如何",而不是"环境"。但我们不要在词汇上浪费时间…
- Windows实际上使用了UTF-16,而且已经有相当长的一段时间了,旧版本的Windows确实使用了UCS-2,但现在已经不是这样了。我这里唯一的问题是得出的结论是,应该在Windows上使用std::wstring,因为它更适合于我认为是错误的Unicode Windows API。如果您唯一关心的是调用Unicode Windows API,而不是整理字符串,那么当然,但我不认为这是一般情况。
- @约翰·莱德格伦:埃多克斯1〔1〕:那么,我们同意。我用C++编写代码,而不是JavaScript。在运行时避免无用的编组或任何其他可能代价高昂的处理(当可以在编译时完成时),是该语言的核心。针对winapi和使用std::string进行编码只是不合理的浪费运行时资源。你发现这是错误的,没关系,因为这是你的观点。我自己的意思是,我不会在Windows上用pessimization编写代码,因为从Linux方面看,它看起来更好。
- GNUD:请参阅POSIX要求(实际上它是C++要求)不违反使用可变长度编码的这一伟大答案。
- 稍微更正一下,UTF-16编码每个字符可以占用2或4个字节。(见unicode.org/faq/utf_bom.html gen6)
- @是的。当我第一次谈到Windows上的宽字符时,我描述了Windows对它如何处理"unicode"(什么是ucs-2或utf-16?)第二次,我写了一个字符的大小:"总而言之,UTF-16每个字符最多使用2个字节(除非你要处理某种深奥的语言符号(克林贡语)?精灵?),而utf-8将花费1到4个字节。",这或多或少就是您所说的(关键字"主要")。我想在我的回答中应该澄清的是Windows在这个问题上的立场。
- 有趣的是,如果在wcout之前执行cout,则Unicode字符不会与wcout一起打印。但是,如果从wcout开始,cout甚至根本不打印,并且所有Unicode打印都正确。就好像伦敦银行同业拆借利率中保留了某种内部状态?
- @paercebal:请注意:其中一种外来语言是汉语btw。因此,中国在相当长一段时间前就决定支持BMP之外的一些代码点。
- "在Linux上使用char时,您通常会在不知道的情况下使用unicode。当std::string与char一起使用时,std::string已经准备好Unicode了。"——这应该伴随一个大警告"永远不要截断、限制、在字符串处获取char"。这可以从整个答案中理解,但应该非常清楚。
- 这是什么原因造成的?
- 123;123\\\x42、0x65、0x6、0x6、0x65、0x6E、0x20、0x20、0x20、0x6a、0x6a、0x6a、0x666a、0x61、0x61、0x65、0x6E、0x6E、0x666a、0x61、0x61、0x61、0x61、0x61、0x61、0x61、0x6E、0x61、0x61、0x61、0x61、0x6666a、0x61、0x20、0x20、0x20、0x69、0x61、0x61、0x61、0x61、0x61、0x61、0x61、0x61 0x2c,0x20,0x73,0x69,0x6e,0x20,0x76,0x65,0x72,0x67,0xfc,0x65,0x6e,0x7a,0x61,0x2c,0x20,0x6c,0x61,0x20,0x6d,0xe1,0x73,0x20,0x65,0x78,0x71,0x75,0x69,0x73,0x69,0x74,0x61,0x20,0x63,0x68,0x61,0x6d,0x70,0x61,0xf1,0x61,0x20,0x64,0x65,0x6c,0x20,0x6d,0x65,0x6e,0xfa,0x2e,0x00_
- @没什么,那只是一个字节序列。它不能解释为utf8,但似乎可以解释为utf16。或者一千个代码页中的任何一个。
- @paercebal我意识到这个注释线程和时间本身一样古老,但是出于性能原因坚持匹配winapi字符串格式是愚蠢的。API调用本身的成本将使转换成本相形见绌;UTF-16字符串所需的额外存储的性能成本可能会抵消任何与转换相关的潜在收益;如果您与其他API通信,则可能无论如何都需要进行转换。例如,请参见utf8everywhere.org/faq.cvt.perf。
- 对于以utf-8编码字符串形式输入的Windows程序,没有必要将Everyhing转换为wchar_t。仅在与WinAPI直接交互时转换。只要编译器使用UTF-8编码,我就看不出比char更倾向于wchar_t。和往常一样,这取决于需求。
- 现在,Windows10终于允许使用UTF-8作为本地字符集…
我建议避免在Windows或其他地方使用std::wstring,除非接口需要,或Windows API调用附近的任何地方以及作为句法糖的相应编码转换。
我的观点总结在http://utf8everywhere.org上,我是该网站的合著者。
除非您的应用程序是以API调用为中心的,例如主要是UI应用程序,否则建议将Unicode字符串存储在std::string中,并用utf-8编码,在API调用附近执行转换。本文概述的好处超过了转换的明显烦恼,特别是在复杂的应用程序中。对于多平台和库开发来说,这是双重的。
现在,回答你的问题:
一些薄弱的原因。它存在的历史原因,其中宽字符被认为是支持Unicode的正确方式。它现在用于接口那些更喜欢UTF-16字符串的API。我只在这些API调用的直接附近使用它们。
这与std::string无关。它可以保存您输入的任何编码。唯一的问题是你如何对待它的内容。我的建议是UTF-8,所以它能够正确地保存所有Unicode字符。这是Linux上的一种常见做法,但我认为Windows程序也应该这样做。
不。
宽字符是一个混淆的名称。在unicode的早期,人们相信一个字符可以用两个字节编码,因此就有了这个名称。今天,它代表"字符中任何两个字节长的部分"。UTF-16被看作是这样的字节对(即宽字符)的序列。UTF-16字符可以接受一对或两对。
所以,每个读者现在都应该对事实和情况有一个清晰的了解。如果没有,那么你就必须阅读Paercebal非常全面的答案[btw:谢谢!]
我的实用主义结论很简单:所有的C++(和STL)字符编码"实质上是破碎的和无用的"。不管是否归咎于微软,这也无济于事。
我的解决方案是,经过深入的调查,很多挫折和相应的经验如下:
接受,你必须自己负责编码和转换的工作(你会发现大部分工作都很琐碎)
对任何UTF-8编码的字符串使用std::string(只是一个typedef std::string UTF8String)
接受这样一个utf8string对象只是一个愚蠢但廉价的容器。永远不要直接访问和/或操作其中的字符(不搜索、替换等)。你可以,但你真的只是真的,真的不想浪费时间为多字节字符串编写文本操作算法!即使其他人已经做了这么愚蠢的事情,也不要这样做!顺其自然!(好吧,有些场景是有意义的……只需使用ICU图书馆。
对ucs-2编码字符串使用std::wstring(typedef std::wstring UCS2String)——这是一种折衷,是对win32 API引入的混乱局面的让步。UCS-2对我们大多数人来说已经足够了(稍后会有更多的讨论…)。
只要需要逐字符访问(读取、操作等),就使用UCS2字符串实例。任何基于字符的处理都应该在非多字节表示中完成。它简单、快速、简单。
添加两个实用程序函数以在utf-8和ucs-2之间来回转换:
1 2
| UCS2String ConvertToUCS2( const UTF8String &str );
UTF8String ConvertToUTF8( const UCS2String &str ); |
转换很简单,谷歌应该在这里提供帮助…
就是这样。在内存宝贵的地方使用utf8string,对于所有utf-8 I/O使用。在必须解析和/或操作字符串的地方使用ucs2string。您可以随时在这两种表示之间进行转换。
备选方案和改进
从&;到单字节字符编码(如ISO-8859-1)的转换可以通过简单的翻译表(如const wchar_t tt_iso88951[256] = {0,1,2,...};和从ucs2转换到&;的适当代码)来实现。
如果ucs-2不够,则切换到ucs-4(typedef std::basic_string UCS2String)
ICU或其他Unicode库?
先进的东西。
- Dang,不知道本地Unicode支持是不好的。
- @弗伦西,我很好奇你是否试过油嘴滑舌,如果试过,你有什么想法?
- @CarolineBeltran:我知道glib,但我从未使用过它,而且我可能永远也不会使用它,因为它相当局限于一个相当不特定的目标平台(unixoid系统…)。它的Windows端口基于外部win2unix层,并且不存在任何OSX兼容层。所有这些东西都是明确地指向错误的方向,至少对于我的代码(在这个架构级别上…);-)所以,glib不是一个选项。
- 我认为第2点和第3点大喊不要使用std::string来表示utf8。如果您仍然想保存在内存中,那么子类std::string,这样在使用substr、concat和length以及基本上任何干扰字符串操作功能的内容时,您至少会得到断言和警告。我个人建议对unicode字符串使用wstring,不管您是使用utf8、16或32还是ucs-2。你用这些做IO会更容易。即使是现在的UI组件也能正确处理Unicode字符串,因此只有在处理较旧的组件时才需要进行下转换。
- @Starshine&;@CarolineBeltran:也许…但是,子类化std::string只会导致对该问题的另一种看法,这只是另一种错误的"std::string",正如std::string本身一样。一个全面的解决方案将包含一个std::string,它在内存布局问题和字符序列问题之间有所不同。因此,对于一个开始,例如,std::string应该有一个方法size()和一个方法nchars()。
- 顺便说一下:即使是C++ 11X、C++ 14X,也没有任何未来的标准,也没有其他人关心这个问题。所以,C++中的I18N仍然是一个解决方案仍然被期待的东西…
- 噢,@starshine:请阅读完整答案。这不像你想的那么容易。
- @弗伦西:啊,也许我错过了。您的"utf8string"typedef如何带来一个全面的解决方案,它在内存布局问题和字符序列问题之间有所不同?它充其量只是一个重构工具,但不是一个解决方案。首先,祝你好运,迫使nchars()进入标准。第二,您如何确定第三方libs不会截断您的utf8序列?最后,utf8更难解析和调试。如果从一开始就使用wstring和ucs2或正确的utf16,那么调试器将显示正确的中文字符串,而不必用字节代码拼凑起来。
- @星光:UTF8Stringtypedef不是一个全面的解决方案。它只是一个实用的解决方案(在大多数情况下,大多数时候)。现在是时候让C++标准的人提供更好的解决方案了。基础知识(Unicode及其不同的编码方案,如utf8和ucs-2,在这里和这里停留),所以现在是正确的时间;-)
- @Starshine:请注意,我的解决方案将与UCS-2有相同的问题,例如,使用中文字符串时!所以,这真的只是一个务实的东西,没有全面的解决方案。
- 在UTF-8字符串(表示字符的字节序列的一部分永远不会被错误地解释为另一个字符)上,搜索、替换等等都可以正常工作。事实上,utf-16和utf-32并不能使这变得简单:实际上,这三种编码都是多字节编码,因为用户感知的字符(图形簇)可以是任意数量的Unicode码位长!实用的解决方案是对所有内容都使用UTF-8,并且只有在处理WindowsAPI时才转换为UTF-16。
- @丹尼尔:为什么你认为一个实用的解决方案会对所有东西都使用UTF-8?单字节搜索和替换代码可能不会对UTF-8字节序列造成太大危害,但也无法解决实际问题:p将UTF-8用于"一切"对于任何人来说都是错误的路径…将UTF-8用于存储和传输是可以的,但将它用于处理字符串将导致处理所有情况和组合所需代码的指数增长。也许吧。但也许所有基于字符的操作都可以重写来处理字形?可能不是,对吧?所以…
- @丹尼尔:"搜索、替换等"不仅在UTF-8字符串上可以很好地工作,不幸的是它更复杂,如utf8everywhere.org/misty.strlen——当然,utf-16和utf-32并不能使这更容易。那么?
- @frunsi:用utf-8搜索和替换和用utf-32一样好。正是因为正确的Unicode感知的文本处理无论如何都需要处理多个代码点"字符",使用像UTF-8这样的可变长度编码不会使字符串处理变得更加复杂。所以只要到处使用UTF-8就行了。普通的C字符串函数在UTF-8上可以正常工作(并对应于Unicode字符串上的顺序比较),如果您需要了解更多的语言,则无论如何都必须调用Unicode库,UTF-16/32无法将您从中保存下来。
- 在这种语言中令人震惊的疏忽得到纠正之前,请查看Glib::ustring,这是来自glibmm项目的一个围绕std::string的实际智能包装器,它将正常的string方法包装起来,并适当意识到字符串中可显示字符的数量(而不是编码字节/char)。
- std::string如何与UTF-8一起工作?我以为std::string使用char,它只有1个字节?
当你想有你的字符串存储在宽的特点。widedepends on the implementation。的Visual C + + defaults to 16位如果我记得正确,depending on the defaults全球目标。这里是32位长。Please笔记_ wchar t(宽character has to do with型)没有Unicode。这是我的商店,它merely移调the members of the character set the implementation supports为最大,其地点和模式,至少只要字符。你可以使用Unicode字符串的结束std::stringstore into the encoding utf-8太。但它不会明白the meaning of Unicode代码点。我不会给你str.size()the amount of your characters在逻辑串,but the amount of merely wchar t的字符或字符串_元/ wstring stored in that。for that reason,茶/ glib GTK开发的C + +类,有人在wrapper Glib::ustringthat can handle utf - 8。P></
如果你_ wchar t是32位长,那么你可以使用Unicode编码utf-32as an和商店,你可以使用Unicode字符串和handle(UTF - 32是固定的固定长度编码)。这将你的wstring'均值S函数然后返回s.size()wchar t the right amount of characters _布尔逻辑元素。P></
是的,我总是8位字符长least is which可以在商店,它的ASCII值的均值。
是的,在专业compilers EN支持。
- 我对2很好奇。我还以为7位在技术上也是有效的?或者需要能够存储超过7位的ASCII字符吗?
- 是的,杰夫。c89在其limits.h文档中为基本类型指定最小范围(对于无符号字符,最小值为0..255),并为整数类型指定纯二进制系统。后面是char,无符号char和有符号char的最小位长度为8。C++继承了这些规则。
- "这意味着您的wstring的.size()函数将返回正确数量的wchar_t元素和逻辑字符。"这并不完全准确,即使对于unicode也是如此。说代码点比说"逻辑字符"更准确,即使在UTF-32中,给定字符也可能由多个代码点组成。
- 你们本质上是说C++没有Unicode字符集的本机支持吗?
- "但它无法理解Unicode代码点的含义。"在Windows上,std::wstring也无法理解。
- @这取决于你如何定义"本地支持"。它能存储Unicode字符序列吗?当然。它是否提供了任何标准类,可以按照显示的字符数对这些序列进行操作,而不仅仅是简单地按字节数索引/查找/等等,从而可能破坏代码点序列并使事情严重出错?不,那太糟糕了。这是2017。我只能希望,因为我们终于获得了标准的文件系统和网络支持,所以实际的Unicode字符串可能在地平线上的某个地方隐约可见。
- @对于将编码的Unicode代码点存储到字节中的下划线支持很少被认为是"支持"。而且,是的,我同意在21世纪这种语言缺乏标准的Unicode支持是很可笑的。
- MihaiDanila至少有EDOCX1,1等,因为C++ 11用于UTF-NN和UTF-8之间的转换。然而,EDCOX1的2度被禁止,因为C++ 17…
性病::字符串的竞相使用UTF-8 characters to hold without any问题在所有。我做的heartily recommend interfacing with which this api' S使用UTF-8字符串as as the原生型阱。P></
for example,当我使用UTF-8 interfacing with the TCL interpreter队列。P></
专业商品is the length of the性病::字符串,is the number of characters周不在字符串。P></
- 胡安:你的意思是std::string可以容纳所有Unicode字符,但是长度报告不正确吗?是否有原因报告长度不正确?
- 使用UTF-8编码时,单个Unicode字符可能由多个字节组成。这就是为什么当使用标准ASCII集中的大部分字符时,UTF-8编码会更小。您需要使用特殊的函数(或滚动您自己的函数)来测量Unicode字符的数量。
- (特定于Windows)大多数函数都希望使用字节的字符串是ASCII,2字节是Unicode,旧版本的MBC。这意味着如果要存储8位Unicode,则必须将其转换为16位Unicode才能调用标准的Windows函数(除非您只使用ASCII部分)。
- 正如Greg和Joel(关于软件)所提到的,理解编码如何与您所处理的API一起工作是非常重要的。在Windows系统上,在8位和16位之间不断地来回更改编码可能不是最佳的。
- Std::String不仅会错误地报告长度,还会输出错误的字符串。如果某些Unicode字符以UTF-8表示为多个字节(std::string将其视为自己的字符),那么通常的std::string操作例程可能会输出几个奇怪的字符,这些字符是由对一个正确字符的错误解释造成的。
- 如果我想制作一个可以自由使用许多不同Unicode符号的程序(在Windows上工作),比如日语/中文字符、波兰语字母、西里尔文等,我应该使用什么?UTF-8足够吗?
- 米海丹妮拉说的。我强烈建议不要将std::string用于utf-8,尤其是在频繁执行字符串操作(如串联和子字符串)时。宽字符串可以占据很多位置,但是如果你认真对待多语言和多文化世界中的软件产品和数据,那么使用std::string就变得过时了,并且试图使用它只会将代码丢在各种奇怪的地方,大多数情况下函数看起来都是"正确的"。我已经在游戏开发领域工作了近10年,在许多不同的平台上,所以我知道我在说什么。
- 我建议更改答案以表明字符串只应被视为字节的容器,并且,如果字节是某种Unicode编码(UTF-8、UTF-16,…),那么您应该使用能够理解这一点的特定库。标准的基于字符串的API(长度、子字符串等)都将以多字节字符的形式出现严重故障。如果进行了此更新,我将删除我的否决票。
- 在标准C++中,跨平台的国际使用似乎没有任何好的选择。我最近为一个程序编写了一个文本驱动的图形用户界面,该程序具有自定义换行符、语义标记、国际字符…在研究了多种方法之后,我选择了使用UTF-8的std::strings来存储文本数据,但是编写了一个函数库来在字符和字节之间映射,执行常见的字符串函数,如文本插入、提取和搜索,以及为I/O执行到其他格式的转换。我来这里是想看看现在是否有更好的啊,似乎不是。
当你想在商店(Unicode)宽的特点。
是:(excluding 0 255 of them)。
是的。
这是一条introductory:http:////unicode.html www.joelonsoftware.com文章
- std::string可以保持0(如果调用c_str()方法,请小心)
- 严格来说,一个字符不能保证是8位。:)你在4中的链接是必读的,但我认为它不能回答这个问题。宽字符与Unicode完全无关。它只是一个更广泛的特征。(宽度取决于操作系统,但通常为16或32位)
- 宽!= Unicode!(尤其是在窗户上)
不满足于256个不同字符的应用程序可以使用宽字符(大于8位)或可变长度编码(在C++术语中的多字节编码),如UTF-8。宽字符通常比可变长度编码需要更多的空间,但处理速度更快。处理大量文本的多语言应用程序在处理文本时通常使用宽字符,但在将文本存储到磁盘时将其转换为UTF-8。
string和wstring之间的唯一区别是它们存储的字符的数据类型。字符串存储chars,其大小保证至少为8位,因此可以使用字符串进行处理,例如ASCII、ISO-8859-15或UTF-8文本。标准中没有提到字符集或编码。
实际上,每个编译器都使用前128个字符与ASCII对应的字符集。使用UTF-8编码的编译器也是如此。在使用UTF-8或其他可变长度编码的字符串时,需要注意的一点是,索引和长度是以字节而不是字符来度量的。
wstring的数据类型是wchar_t,其大小在标准中没有定义,除非它必须至少与char一样大,通常为16位或32位。wstring可用于处理实现定义的宽字符编码中的文本。因为标准中没有定义编码,所以在字符串和wstring之间转换并不容易。也不能假定wstring具有固定长度的编码。
如果您不需要多语言支持,那么只使用常规字符串就可以了。另一方面,如果您正在编写图形应用程序,通常情况下API只支持宽字符。然后您可能希望在处理文本时使用相同的宽字符。请记住,UTF-16是一种可变长度的编码,这意味着您不能假定length()返回字符数。如果API使用固定长度的编码(如ucs-2),则处理变得容易。在宽字符和UTF-8之间的转换很难以可移植的方式进行,但同样,您的用户界面API可能支持这种转换。
- 因此,改写第一段:需要超过256个字符的应用程序需要使用多字节编码或可能的_多字节编码。
- 不过,通常16位和32位编码(如ucs-2和ucs-4)不称为多字节编码。C++标准区分多字节编码和宽字符。宽字符表示法每个字符使用一个固定的数字(通常超过8)位。使用一个字节对最常见的字符进行编码,而使用多个字节对其余字符集进行编码的编码称为多字节编码。
- 抱歉,草率的评论。应该说是可变长度编码。UTF-16是一种可变长度的编码,就像UTF-8一样。假装这不是个坏主意。
- 这是一个很好的观点。没有理由不使用wstring来存储utf-16(而不是ucs-2),但是固定长度编码的便利性就丧失了。
当你想使用ASCII和Unicode字符串internationalisation not just for,帮助
是的,但它不好用。0
not any of that不感知
宽character is the of the Way编译器处理固定长度的特异性表现在Unicode字符,其中en is for 2字节字符,它是了解顾客的为4个字节。和+ 1)http:////unicode.html www.joelonsoftware.com文章
- 2。一个std::字符串可以容纳一个空字符。它还可以保存utf-8和宽字符。
- @胡安:那又把我弄糊涂了。如果std::string可以保留unicode字符,那么std::wstring有什么特别之处?
- @appu:std::string可以容纳utf-8 Unicode字符。有许多Unicode标准针对不同的字符宽度。utf8宽8位。在16位和32位宽分别有utf-16和utf-32
- 带有std::wstring。当使用固定长度编码时,每个Unicode字符可以是一个wchar-ut。例如,如果您选择使用Joel on软件方法作为greg的链接。那么wstring的长度就是字符串中的Unicode字符数。但它占用了更多的空间
- 我没有说它不能容纳0' ',我的意思是它不能很好地发挥作用,因为有些方法可能不会给您一个包含wstring所有数据的预期结果。对低票太苛刻了。
- 我无意冒犯。但我不同意你对1和2的回答。我可以从Joel的论点中看出,在Windows系统上工作时,您为什么要使用wchar_t。但是,常规char对于i18n也同样有效。
这里有一些很好的答案,但我认为关于Windows/Visual Studio,我可以添加一些东西。这是基于我对VS2015的经验。在Linux上,答案基本上是到处使用UTF-8编码的std::string。在windows/vs上,它变得更加复杂。这就是原因。Windows希望使用char存储的字符串使用区域设置代码页进行编码。这几乎总是ASCII字符集,后面跟着128个其他特殊字符,具体取决于您的位置。让我陈述这一点,不仅仅是在使用Windows API时,还有三个主要的地方,这些字符串与标准C++交互。这些是字符串文本,使用<<输出到std::cout并向std::fstream传递文件名。好的。
我将站在前面,我是一个程序员,而不是语言专家。我很感激USC2和UTF-16不一样,但就我的目的而言,它们非常接近,可以互换,我在这里就是这样使用的。我实际上不确定哪些窗口使用,但我一般也不需要知道。我已经在这个答案中说明了UCS2,所以如果我对这个问题的无知使任何人感到不安,那么我提前道歉,如果我有什么问题,我很乐意改变它。好的。字符串常量
如果您输入的字符串文本只包含代码页可以表示的字符,那么VS会将它们存储在您的文件中,并根据代码页对每个字符编码1个字节。请注意,如果您更改代码页或将源代码提供给使用不同代码页的其他开发人员,那么我认为(但尚未测试)字符最终会有所不同。如果您在使用不同代码页的计算机上运行代码,那么我不确定字符是否也会更改。好的。
如果您输入了任何不能由代码页表示的字符串文本,那么vs将要求您将文件保存为unicode。然后文件将被编码为UTF-8。这意味着所有非ASCII字符(包括代码页上的字符)将由2个或更多字节表示。这意味着如果将源代码提供给其他人,则源代码将看起来相同。但是,在将源代码传递给编译器之前,vs将utf-8编码文本转换为代码页编码文本,代码页中缺少的任何字符都将替换为?。好的。
确保在vs中正确表示unicode字符串文字的唯一方法是在字符串文字前面加上L,使其成为宽字符串文字。在这种情况下,VS会将文件中的UTF-8编码文本转换为UCS2。然后需要将这个字符串文字传递到std::wstring构造函数中,或者需要将其转换为utf-8并将其放入std::string中。或者,如果您想使用Windows API函数来编码它,可以使用代码页将其放入std::string中,但也可以不使用宽字符串文字。好的。性病:咳嗽
使用<<输出到控制台时,只能使用std::string,不能使用std::wstring,文本必须使用区域设置代码页编码。如果您有一个std::wstring,那么您必须使用一个Windows API函数转换它,并且代码页上没有的任何字符都将被?替换(也许您可以更改字符,我不记得了)。好的。std::fstream文件名
Windows操作系统使用ucs2/utf-16作为文件名,因此无论您的代码页是什么,您都可以使用任何Unicode字符的文件。但这意味着要访问或创建不在代码页上的字符文件,必须使用std::wstring。没有别的办法。这是微软对std::fstream的特定扩展,因此可能不会在其他系统上编译。如果使用std::string,则只能使用仅包含代码页上字符的文件名。好的。你的选择
如果您只是在Linux上工作,那么您可能还没有达到这个目标。只要在任何地方使用UTF-8 std::string。好的。
如果您只是在Windows上工作,请在任何地方使用ucs2 std::wstring。一些纯粹主义者可能会说,在需要的时候使用utf8然后转换,但是为什么要麻烦呢?好的。
如果你是跨平台的,那么坦白说就是一团糟。如果您试图在Windows上的任何地方使用UTF-8,那么您需要非常小心地处理字符串文本并将其输出到控制台。你可以很容易地破坏你的字符串。如果您在Linux上到处使用std::wstring,那么您可能无法访问std::fstream的广泛版本,因此您必须进行转换,但不存在损坏的风险。所以我个人认为这是一个更好的选择。很多人会不同意,但我不是唯一一个人——例如,这是wxwidgets所采取的路径。好的。
另一种选择是在Linux上将unicodestring类型化为std::string,在Windows上将std::wstring,并有一个名为uni()的宏,该宏在Windows上前缀为l,在Linux上不加前缀,然后代码好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>
#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
std::string result;
//Call WideCharToMultiByte to do the conversion
return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
return str;
}
#endif
int main()
{
unicodestring fileName(UNI("fileName"));
std::ofstream fout;
fout.open(fileName);
std::cout << formatForConsole(fileName) << std::endl;
return 0;
} |
我想在任何一个站台都可以。好的。答案
所以回答你的问题好的。
1)如果您是为Windows编程的,那么一直以来,如果是跨平台编程,那么可能一直都是,除非您想处理Windows上可能出现的损坏问题,或者用特定于平台的#ifdefs编写一些代码来解决这些差异,如果只是使用Linux,那么永远不会。好的。
2)是的。此外,在Linux上,您也可以将其用于所有Unicode。在Windows上,如果选择使用UTF-8手动编码,则只能将其用于所有Unicode。但是Windows API和标准C++类将期望使用本地代码页编码EDOCX1 1。这包括所有的ASCII加上另外128个字符,这些字符根据您的计算机设置要使用的代码页而改变。好的。
3)我相信是这样,但如果不是这样的话,它只是使用wchar_t而不是char的"std::basic_string"的简单typedef。好的。
4)宽字符是大于1字节标准char类型的字符类型。在Windows上是2字节,在Linux上是4字节。好的。好啊。
- 关于"但是,在将源代码传递给编译器之前,vs将utf-8编码文本转换为代码页编码文本,代码页中缺少的任何字符都将替换为?"."->我不认为编译器使用UTF-8编码时是这样的(使用/utf-8)。
- 我不知道这是一种选择。从这个链接docs.microsoft.com/en-us/cpp/build/reference/&hellip;在项目属性中似乎没有可选择的复选框,您必须将其添加为附加的命令行选项。好地点!
一个好问题!我认为数据编码(有时也涉及字符集)是一种内存表达式机制,用于将数据保存到文件或通过网络传输数据,因此我的回答如下:
1。什么时候应该在std::string上使用std::wstring?
如果编程平台或API函数是单字节的,并且我们想要处理或解析一些Unicode数据,例如从windows.reg文件或网络2字节流读取的数据,我们应该声明std::wstring变量,以便轻松处理它们。例如:wstring ws=l"中国A"(6个八位字节内存:0x4e2d 0x56fd 0x0061),我们可以用ws[0]得到字符"中",用ws[1]得到字符"国",用ws[2]得到字符"A"等。
2。std::string能否保存整个ASCII字符集,包括特殊字符?
对。但请注意:美国ASCII表示每个0x00~0xFF八位字节代表一个字符,包括可打印文本,如"123abc&;*uuamp;",而您所说的特殊字符,大多是作为"."打印的,避免混淆编辑器或终端。另外一些国家扩展自己的"ascii"字符集,例如中文,使用2个八位字节代表一个字符。
3、STD::WSCOPE是由所有流行的C++编译器支持的吗?
也许,或者大部分。我用过:VC++6和GCC 3.3,是的。
4。什么才是"宽性格"?
宽字符主要表示使用2个八位字节或4个八位字节来保存所有国家的字符。2个八位字节ucs2是一个代表性样本,而且,例如英语"a",它的内存是2个八位字节0x0061(而在ascii"a"中,它的内存是1个八位字节0x61)
上述模式1)As is for Greg,帮助wstring国际化,那当你释放你的产品会比在其他语言的英语P></
4)看看这个为宽字符http:/ / / /字宽_维基百科en.wikipedia.orgP></
当你使用should not characters宽?P></
当你写作在1990年的队列。P></
明显的,我被翻转,但这是真的,现在的第二十一世纪。自从ceased 127 characters have to be足够长。是的,你可以使用,但与headaches为什么打扰?P></
- @戴夫:我不知道UTF-8会产生什么样的头痛,它比宽字符(UTF-16)更大。在UTF-16中,您还可以使用多字符字符。
- 问题是,如果你不是说英语的国家,你应该使用wchar-u-t。更不用说,有些字母表的字符比你能放入一个字节的字符要多。我们在那里,在DOS上。精神分裂症的代码页,不,谢谢,不再……
- @Swift wchar_t的问题在于它的大小和含义是特定于操作系统的。它只是把旧问题换成新问题。而char是char,不管操作系统是什么(至少在类似的平台上)。所以我们不妨只使用UTF-8,把所有的东西打包成EDOCX1的2个序列,并哀叹C++如何完全独立于我们自己,而不需要任何标准的方法来测量、索引、查找等等。
- 如果你在C++中编写代码,你所描述的是最小的问题。宽字符WChcHyt是C++中的基本类型,但不是C语言,但它的二进制表示不是您定义的平台定义,而是运行时。所以字符可以是1字节或2字节长(至少),这取决于实际存储的字符串。Unicode UTF-16是固定大小的字符。问题是,wchar_t是文件系统名称(包括Windows)级别上特定平台支持的类型,而其他平台使用多字节字符
- @很快,你似乎完全倒退了。wchar_t是固定宽度的数据类型,因此一个10个wchar_t的数组将始终占用sizeof(wchar_t) * 10平台字节。而utf-16是一种可变宽度的编码方式,其中字符可以由1或2个16位码位组成(对于utf-8,可以是S/16/8/G)。
- @斯威夫特很抱歉,这是错误的,至少对于windows上的wchar_t。在Windows上,wchar_t是一种utf-16编码。简单测试:wchar_t*test=l"??";//code point U+20000在调试器中,您将看到一个由两个值组成的字符串:0xD840和0xDC00,这是字符的UTF-16编码。
- @StevenHollasch你保存了utf16,所以你得到了它。它是一种依赖于编译的基元类型,不强制转换或限制您试图分配给它的内容。API和编译器如何处理IST是未定义的,一般来说,它与Windows API定义的任何Unicode.wchar_t表示形式都不同,每个字符16位。所以你有一个代理-两个字符,代码是0x00dc和0x40d8。但将其视为Unicode数组的代码将正常工作,您将很难确定它是2个字符还是1个字符。在Linux上,wchar-t是32位的,您的代码不会引起问题。
- @Windows上字符串的stevenhollasch wchar_t表示将大于ffff的字符编码为特定的代理项对,另一个只接受一个wchar_t元素。因此,表示将与GNU编译器创建的表示不兼容(其中所有小于ffff的字符前面都有零个字)。wchar-t中存储的内容由程序员和编译器决定,而不是由某种协议决定。