Emanuel Gauler Asked: 2020-03-18 05:23:58 +0800 CST 2020-03-18 05:23:58 +0800 CST 2020-03-18 05:23:58 +0800 CST 为什么 cout 不显示带有波浪号的元音或使用 gcc 4.9.4 的“ñ”? 772 我不知道为什么会这样。每当它处理 a 的字符时string,它string有带重音的元音或ñ转换它们并且不能正确显示。 c++ 4 Answers Voted Joaquin Pereira 2020-03-18T06:41:55+08:002020-03-18T06:41:55+08:00 这是由于您的程序正在运行的语言环境;一个要定位的例子是: #include <iostream> using namespace std; setlocale(LC_ALL, "es_ES"); int main() { cout << "áéíóú\n"; return 0; } 您可以在以下位置查看更多信息: C中的定位函数 Trauma 2020-03-18T11:34:38+08:002020-03-18T11:34:38+08:00 为了快速理解: std::string( "ab" ).size( ); => 2; std::string( "ññ" ).size( ); => 4; 您不能将 UTF-8 字符显示为 ascii 字节。 您唯一的解决方案是从 1 到 1 检查字符在 ASCII(7 位)中是否有效。如果任何字符不符合该规则,则您必须返回超过 1 个字节。 所有 UTF-8 字符都将第 8 位设置为 1,因此检查很简单: if( character & 128 ) { 如果您发现任何符合上述条件的字符,您将面临 UTF-8。 在这种类型的字符之前,您必须使用一些库将其提取并将其转换为字符串,以显示后者。 请记住,您可以在一行中找到多个 UTF-8 ,因此只要检查成功,您就不能采取简单的方法将字符添加到辅助字符串中。您还可能遇到无效的 UTF-8序列。 我认为 Windows 为这些东西提供了功能。在 Linux 上,您可以使用ICU 编辑 在阅读这个问题之前,我从来不需要从... 中提取单个字符::std::string;-) 在经历了一些意想不到的烦恼template< >之后,我制作了这个,它允许您遍历UTF-8 字符串的各个字符,无论它们是在 aconst char *VAR="..."还是::std::string( "..." ). 这不是世界上最酷的东西,但它说明了检查字符是否为 UTF-8 的过程,以及如何根据字符的宽度来处理它们。它没有考虑 UTF-8 编码中可能出现的错误,它仅用于训练目的: // utf8iterator.hpp #ifndef UTF8ITERATOR_HPP #define UTF8ITERATOR_HPP #include <cstddef> template< typename T > struct utf8iterator { T ptr; ::size_t size; char bytes[5]; utf8iterator( const T &p ) : ptr( p ), size( 0 ) { bytes[4] = 0; } utf8iterator &operator=( const T &iter ) { ptr = iter; size = 0; return *this; } bool operator==( const utf8iterator< T > &other ) const noexcept { return ptr == other.ptr; } bool operator!=( const utf8iterator< T > &other ) const noexcept { return ptr != other.ptr; } ::size_t calculateSize( ) const { if( ( *ptr & 248 ) == 240 ) { return 4; } else if( ( *ptr & 240 ) == 224 ) { return 3; } else if( ( *ptr & 224 ) == 192 ) return 2; return 1; } utf8iterator &operator++( ) { if( size ) { ptr += size; size = 0; } else ptr += calculateSize( ); return *this; } utf8iterator operator++( int ) { utf8iterator tmp( *this ); if( size ) { ptr += size; size = 0; } else ptr += calculateSize( ); return tmp; } void update( ) { ::size_t c; T iter( ptr ); size = calculateSize( ); for( c = 0; c != size; ++c ) { bytes[c] = *iter; ++iter; } if( size != 4 ) bytes[size] = 0; } operator const char *( ) { if( !size ) update( ); return bytes; } }; #endif 一个小的测试/示例程序,展示了它的用途: // main.cpp #include <iostream> #include <string> #include "utf8iterator.hpp" int main( void ) { const char *test = "abcdeññ"; std::string str( test ); utf8iterator< const char * > charIter( test ); utf8iterator< std::string::iterator > strIter( str.begin( ) ); while( *charIter ) { std::cout << charIter << ": "; std::cout << charIter.size << "\n"; ++charIter; } while( strIter != str.end( ) ) { std::cout << strIter << ": "; std::cout << strIter.size << "\n"; ++strIter; } std::cout << std::endl; return 0; } 用 编译后g++ -I . -std=c++11 -Wall -pedantic main.cpp,显示如下结果: a:1 b:1 c:1 d:1 e:1 ñ:2 ñ:2 a:1 b:1 c:1 d:1 e:1 ñ:2 ñ:2 正确显示单个字符,char *无论它们占用std::string多少字节。 Best Answer Angel Angel 2020-03-19T01:01:44+08:002020-03-19T01:01:44+08:00 我不知道你是否解决了这个问题,但我看到这样的评论: 我使用了 gnu++11 的 std::locale,然后使用 cout.imbue(locale(""); 它仍然错误地向我显示字符...... 您可以使用以下内容以您想要的方式显示它: #include <iostream> #include <locale> #include <string> using namespace std; int main() { // your code goes here ios_base::sync_with_stdio(false); wcout.imbue(locale("en_US.UTF-8")); for (auto const&t : wstring (L"áéíóú")){ wcout << t; } return 0; } testIdeone 信息: wstring wstring (L"áéíóú") wcout wcout << t; sync_with_stdio ios_base::sync_with_stdio(false); Angel Moreno 2020-04-04T06:22:35+08:002020-04-04T06:22:35+08:00 您可以遍历 UTF-8 字符串的“字节”并将这些字节输出到其他地方。 您永远不能做的是在您正在迭代的那些字节之间“交错”字符/字节(在这种情况下是行尾:“endl”),因为有些字符由两个字节组成(ñ,á等)并且不是“可分离的”。 为了更好地理解我上面所说的,此代码仅适用于小于 0x800 的(unicode)字符(小于 8*256,'ñ'、'á' 小于 1*256): #include <iostream> using namespace std; int main() { for (auto const&l : string("áaéeiíóúñ")) { cout << l; if ((l&0xc0)!=0xc0) cout << endl; } } 离开: á a é e i í ó ú ñ 我只在输出“字节”之间的“某些情况下”交错换行。
这是由于您的程序正在运行的语言环境;一个要定位的例子是:
您可以在以下位置查看更多信息:
C中的定位函数
为了快速理解:
您不能将 UTF-8 字符显示为 ascii 字节。
您唯一的解决方案是从 1 到 1 检查字符在 ASCII(7 位)中是否有效。如果任何字符不符合该规则,则您必须返回超过 1 个字节。
所有 UTF-8 字符都将第 8 位设置为 1,因此检查很简单:
如果您发现任何符合上述条件的字符,您将面临 UTF-8。
在这种类型的字符之前,您必须使用一些库将其提取并将其转换为字符串,以显示后者。
请记住,您可以在一行中找到多个 UTF-8 ,因此只要检查成功,您就不能采取简单的方法将字符添加到辅助字符串中。您还可能遇到无效的 UTF-8序列。
我认为 Windows 为这些东西提供了功能。在 Linux 上,您可以使用ICU
编辑
在阅读这个问题之前,我从来不需要从... 中提取单个字符
::std::string
;-)在经历了一些意想不到的烦恼
template< >
之后,我制作了这个,它允许您遍历UTF-8 字符串的各个字符,无论它们是在 aconst char *VAR="..."
还是::std::string( "..." )
. 这不是世界上最酷的东西,但它说明了检查字符是否为 UTF-8 的过程,以及如何根据字符的宽度来处理它们。它没有考虑 UTF-8 编码中可能出现的错误,它仅用于训练目的:一个小的测试/示例程序,展示了它的用途:
用 编译后
g++ -I . -std=c++11 -Wall -pedantic main.cpp
,显示如下结果:正确显示单个字符,
char *
无论它们占用std::string
多少字节。我不知道你是否解决了这个问题,但我看到这样的评论:
我使用了 gnu++11 的 std::locale,然后使用 cout.imbue(locale(""); 它仍然错误地向我显示字符......
您可以使用以下内容以您想要的方式显示它:
testIdeone
信息:
wstring
wcout
sync_with_stdio
您可以遍历 UTF-8 字符串的“字节”并将这些字节输出到其他地方。
您永远不能做的是在您正在迭代的那些字节之间“交错”字符/字节(在这种情况下是行尾:“endl”),因为有些字符由两个字节组成(ñ,á等)并且不是“可分离的”。
为了更好地理解我上面所说的,此代码仅适用于小于 0x800 的(unicode)字符(小于 8*256,'ñ'、'á' 小于 1*256):
离开:
我只在输出“字节”之间的“某些情况下”交错换行。