我希望您能提供一个代码片段,用于输入Unicode文本、将另一个Unicode文本连接到第一个Unicode文本,最后输出结果。
附注:这个代码将有助于我解决与Unicode相关的另一个更大的问题。但在这之前,首要任务是完成我提出的要求。
补充说明:顺便说一下,当我运行可执行文件时,无法在命令行中输入任何Unicode符号。我该怎么做?
我之前也遇到过类似的问题,我的解决方法是使用 imbue
和 sync_with_stdio
。你可以尝试以下代码:
#include <iostream>
#include <locale>
#include <string>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
wcin.imbue(locale("en_US.UTF-8"));
wcout.imbue(locale("en_US.UTF-8"));
wstring s;
wstring t(L" la Polynésie française");
wcin >> s;
wcout << s << t << endl;
return 0;
}
wcin
和wcout
在Windows上不起作用,就像等效的C函数一样。只有本地API可用。 - Philipp根据您所说的Unicode类型不同,我猜测您只是在使用std::wstring
。在这种情况下,您可以使用std::wcin
和std::wcout
。
如果需要进行编码转换,则可以使用操作系统函数,例如Win32中的WideCharToMultiByte
和MultiByteToWideChar
,或者使用类似libiconv这样的库。
wcin
和wcout
在哪方面对您不起作用?它们无法显示控制台字体不支持的Unicode字符,但这是控制台而不是iostreams的错误。 - Ben VoigtReadConsoleW
/WriteConsoleW
。 - Philipp这里有一个例子展示了四种不同的方法,其中只有第三种(C conio
)和第四种(本地Windows API)有效(但仅在stdin/stdout未被重定向时有效)。请注意,您仍然需要一种包含您想要显示的字符的字体(Lucida Console至少支持希腊语和西里尔语)。请注意,这里的所有内容都是完全不可移植的,因为没有一种可移植的方式可以在终端上输入/输出Unicode字符串。
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#define STRICT
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <conio.h>
#include <windows.h>
void testIostream();
void testStdio();
void testConio();
void testWindows();
int wmain() {
testIostream();
testStdio();
testConio();
testWindows();
std::system("pause");
}
void testIostream() {
std::wstring first, second;
std::getline(std::wcin, first);
if (!std::wcin.good()) return;
std::getline(std::wcin, second);
if (!std::wcin.good()) return;
std::wcout << first << second << std::endl;
}
void testStdio() {
wchar_t buffer[0x1000];
if (!_getws_s(buffer)) return;
const std::wstring first = buffer;
if (!_getws_s(buffer)) return;
const std::wstring second = buffer;
const std::wstring result = first + second;
_putws(result.c_str());
}
void testConio() {
wchar_t buffer[0x1000];
std::size_t numRead = 0;
if (_cgetws_s(buffer, &numRead)) return;
const std::wstring first(buffer, numRead);
if (_cgetws_s(buffer, &numRead)) return;
const std::wstring second(buffer, numRead);
const std::wstring result = first + second + L'\n';
_cputws(result.c_str());
}
void testWindows() {
const HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
WCHAR buffer[0x1000];
DWORD numRead = 0;
if (!ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL)) return;
const std::wstring first(buffer, numRead - 2);
if (!ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL)) return;
const std::wstring second(buffer, numRead);
const std::wstring result = first + second;
const HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD numWritten = 0;
WriteConsoleW(stdOut, result.c_str(), result.size(), &numWritten, NULL);
}
conio
的方法。_O_U16TEXT
的方法,但似乎只能让wgets
将ReadFile
读取的(8位)数据解释为UTF-16编码。这个周末我会进一步调查此问题。wmain
声明为int wmain(int argc, wchar_t** argv)
(w
不是打字错误!)。 - Philipp如果您有实际文本(即逻辑字符的字符串),则插入到宽流中。宽流将自动编码您的字符以匹配区域设置编码所期望的位。 (如果您有编码位,流将解码这些位,然后重新编码以匹配区域设置。)
如果您知道自己有UTF编码的位(即旨在解码为逻辑字符字符串的位数组)并且您知道输出流的目标期望完全相同的位格式,则可以跳过解码和重新编码步骤,并将位按原样写入write()。仅当您知道双方使用相同的编码格式时才有效,这可能适用于不打算与其他语言环境中的进程通信的小型实用程序。
这取决于操作系统。如果您的操作系统理解,您可以简单地发送UTF-8序列。
ReadConsole
/WriteConsole
)才能处理Unicode文本。 - Philipp
cin
,cout
和其他所有内容,使用纯Windows函数ReadConsoleW
和WriteConsoleW
。C和C++标准在这方面只是有缺陷的。 - Philipp