5

我的代码中有一个宽字符串(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'ф';的工作coorectly。但同样

wchar_t w;
wcin >> w;
wcout << w;

工作不正确。

它很奇怪。早些时候,我使用 setlocale() 对编码没有任何问题。

4

4 回答 4

3

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

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

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

"\x05" "five"

C++11 增加了指定它们的 Unicode 值的能力,在你的情况下是

L"\u03A6"

如果您要使用完整的 C++11(并且您的环境确保它们以 UTF-* 编码),您可以使用 、 或 中的任何一个charchar16_t然后char32_t执行以下操作:

const char* phi_utf8 = "\u03A6";
const char16_t* phi_utf16 = u"\u03A6";
const char32_t* phi_utf16 = U"\u03A6";
于 2013-04-03T15:47:44.633 回答
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;
}
于 2013-04-03T15:52:07.440 回答
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
于 2013-04-03T16:14:30.167 回答
0

这可能是一个编码问题。wcin使用与编译器/源代码不同的编码。尝试在控制台/wcin 中输入 ф - 它会起作用。尝试通过 wcout 打印 ф - 它会显示不同的字符或根本没有字符。

没有独立于平台的方法来规避这种情况,但是如果您在 Windows 上,则可以使用chchp命令行命令或以编程方式使用SetConsoleCP()(输入)和SetConsoleOutputCP()(输出)手动更改控制台编码。

您还可以更改源文件/编译器的编码。如何完成取决于您的编辑器/编译器。如果您使用的是 MSVC,此答案可能会对您有所帮助:https ://stackoverflow.com/a/1660901/2128694

于 2013-04-03T15:54:50.583 回答