wstring :: find()不适用于非拉丁符号?

时间:2013-04-03 15:22:15

标签: c++ stl wstring setlocale

我的代码中有一个宽字符串(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 个答案:

答案 0 :(得分:3)

源文件的编码和执行环境的编码可能大不相同。 C ++不保证任何这一点。您可以通过输出字符串文字的十六进制值来检查:

std::wcout << std::hex << L"ф";

在C ++ 11之前,您可以使用十六进制值在源代码中使用非ASCII字符:

"\x05" "five"

C ++ 11增加了指定其Unicode值的功能,在您的情况下将是

L"\u03A6"

如果您要使用完整的C ++ 11(并且您的环境确保这些编码为UTF- *),您可以使用charchar16_tchar32_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