wstring::find() 不适用于非拉丁符号?
wstring::find() doesn't work with non-latin symbols?
我的代码中有一个宽字符字符串(std::wstring),我需要在其中搜索宽字符。
我使用find()函数:
wcin >> str;
wcout << ((str.find(L'ф') != wstring::npos)? L"EXIST":L"NONE");
L'ф'
是一个西里尔字母。
但是find()在同一个调用中总是返回npos
。在使用拉丁字母的情况下,find()可以正常工作。
这个函数有问题吗?还是我做错了什么?
乌利希期刊指南
我使用MinGW并以UTF-8格式保存源代码。我也用setlocale(LC_ALL, "");
设置区域设置。代码相同的wcout << L'ф';
工作正常。但同样的
wchar_t w;
wcin >> w;
wcout << w;
正确工作。
真奇怪。早些时候,我使用setlocale()对编码没有任何问题。
源文件的编码和执行环境的编码可能大不相同。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控制台上运行良好(使用 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
这可能是编码问题。wcin
使用不同于编译器/源代码的编码。试着在控制台/wcin中输入这个参数——它会工作的。试着通过wcout打印这个字符——它会显示一个不同的字符,或者根本不显示字符。
没有平台独立的方法来绕过这个问题,但是如果您在windows上,您可以手动更改控制台编码,可以使用chchp
命令行命令或通过编程方式使用SetConsoleCP()
(输入)和SetConsoleOutputCP()
(输出)。
你也可以改变你的源文件/编译器的编码。如何做到这一点取决于您的编辑器/编译器。如果您正在使用MSVC,下面的答案可能会对您有所帮助:https://stackoverflow.com/a/1660901/2128694
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 将无符号char*转换为std::istream*C++
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- vscode g++链路故障:体系结构x86_64的未定义符号
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 使用gcc从静态链接的文件中查找可选符号
- C++中无符号字符溢出
- 使用无符号字符数组有效存储内存
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- VC++本机单元测试,找不到调试符号
- 为什么我必须在C++中添加一个赋值符号来声明一个数组
- 检查TCHAR数组输入是否为带符号整数C++
- 用符号版本替换对函数的所有调用
- 未解析的外部符号_MsiLocateComponentW@12.
- 未定义的符号:符号引用错误.没有输出写入主
- 符号"符号"的偏移不一致
- 未定义的符号 - 符号查找错误