wstring::find() не работает с нелатинскими символами?
В моем коде есть строка широких символов (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 ().
4 ответа
Кодировка вашего исходного файла и кодировка среды выполнения могут сильно отличаться. 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";
Вы должны установить кодировку консоли.
Это работает:
#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;
}
std::wstring::find()
работает отлично. Но вы должны правильно прочитать входную строку.
Следующий код прекрасно работает на консоли Windows (входная строка Unicode читается с использованием ReadConsoleW()
Win32 API):
#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
Это, вероятно, проблема с кодировкой. wcin
работает с кодировкой, отличной от кодировки / исходного кода вашего компилятора. Попробуйте ввести ф в консоли / wcin - это будет работать. Попробуйте распечатать ф через wcout - он покажет другой символ или совсем не будет.
Не существует независимого от платформы способа обойти это, но если вы работаете в Windows, вы можете вручную изменить кодировку консоли, либо с помощью chchp
командная строка или программно с SetConsoleCP()
(вход) и SetConsoleOutputCP()
(выход).
Вы также можете изменить кодировку вашего исходного файла / компилятора. Как это сделать, зависит от вашего редактора / компилятора. Если вы используете MSVC, этот ответ может помочь вам: /questions/11361677/spetsifikatsiya-ishodnoj-kodirovki-charset-v-msvc-naprimer-gcc-finput-charsetcharset/11361691#11361691