我的代码中有一个宽字符串(std :: wstring),我需要在其中搜索宽字符。
我使用find()函数:
wcin >> str;
wcout << ((str.find(L'ф') != wstring::npos)? L"EXIST":L"NONE");
L'ф'
是西里尔字母。
但同一个调用中的find()始终返回npos
。在拉丁字母的情况下,find()可以正常工作。
这个功能有问题吗? 或者我做错了什么?
UPD
我使用MinGW并以UTF-8保存源代码。
我还使用setlocale(LC_ALL, "");
设置了区域设置。
相同的代码wcout << L'ф';
可以直接地工作。
但同样的
wchar_t w;
wcin >> w;
wcout << w;
工作不正确。
很奇怪。之前我使用setlocale()编码没有问题。
答案 0 :(得分:3)
源文件的编码和执行环境的编码可能大不相同。 C ++不保证任何这一点。您可以通过输出字符串文字的十六进制值来检查:
std::wcout << std::hex << L"ф";
在C ++ 11之前,您可以使用十六进制值在源代码中使用非ASCII字符:
"\x05" "five"
C ++ 11增加了指定其Unicode值的功能,在您的情况下将是
L"\u03A6"
如果您要使用完整的C ++ 11(并且您的环境确保这些编码为UTF- *),您可以使用char
,char16_t
或char32_t
中的任何一个,并做:
const char* phi_utf8 = "\u03A6";
const char16_t* phi_utf16 = u"\u03A6";
const char32_t* phi_utf16 = U"\u03A6";
答案 1 :(得分:1)
您必须设置控制台的编码。
这有效:
#include <iostream>
#include <string>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
using namespace std;
int main()
{
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stdin), _O_U16TEXT);
wstring str;
wcin >> str;
wcout << ((str.find(L'ф') != wstring::npos)? L"EXIST":L"NONE");
system("pause");
return 0;
}
答案 2 :(得分:1)
std::wstring::find()
运行正常。但是你必须正确读取输入字符串。
以下代码在Windows控制台上运行正常(使用ReadConsoleW()
Win32 API读取输入的Unicode字符串):
#include <exception>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <windows.h>
using namespace std;
class Win32Error : public runtime_error
{
public:
Win32Error(const char* message, DWORD error)
: runtime_error(message)
, m_error(error)
{}
DWORD Error() const
{
return m_error;
}
private:
DWORD m_error;
};
void ThrowLastWin32(const char* message)
{
const DWORD error = GetLastError();
throw Win32Error(message, error);
}
void Test()
{
const HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (hStdIn == INVALID_HANDLE_VALUE)
ThrowLastWin32("GetStdHandle failed.");
static const int kBufferLen = 200;
wchar_t buffer[kBufferLen];
DWORD numRead = 0;
if (! ReadConsoleW(hStdIn, buffer, kBufferLen, &numRead, nullptr))
ThrowLastWin32("ReadConsoleW failed.");
const wstring str(buffer, numRead - 2);
static const wchar_t kEf = 0x0444;
wcout << ((str.find(kEf) != wstring::npos) ? L"EXIST" : L"NONE");
}
int main()
{
static const int kExitOk = 0;
static const int kExitError = 1;
try
{
Test();
return kExitOk;
}
catch(const Win32Error& e)
{
cerr << "\n*** ERROR: " << e.what() << '\n';
cerr << " (GetLastError returned " << e.Error() << ")\n";
return kExitError;
}
catch(const exception& e)
{
cerr << "\n*** ERROR: " << e.what() << '\n';
return kExitError;
}
}
输出:
C:\TEMP>test.exe abc NONE C:\TEMP>test.exe abcфabc EXIST
答案 3 :(得分:0)
这可能是编码问题。 wcin
使用与编译器/源代码不同的编码。尝试在控制台/ wcin中输入ф - 它会起作用。尝试通过wcout打印ф - 它将显示不同的字符或根本没有字符。
没有独立于平台的方法来规避这一点,但是如果您在Windows上,则可以使用chchp
命令行命令或使用SetConsoleCP()
(输入)以编程方式手动更改控制台编码, SetConsoleOutputCP()
(输出)。
您还可以更改源文件/编译器的编码。如何完成取决于您的编辑器/编译器。如果您使用的是MSVC,这个答案可能会对您有所帮助:https://stackoverflow.com/a/1660901/2128694