2013-04-03 7 views
5

Mam ciąg znaków o szerokim spektrum (std :: wstring) w moim kodzie i muszę przeszukiwać w nim szeroki znak.wstring :: find() nie działa z symbolami innymi niż łacińskie?

używam find() funkcji do niego:

wcin >> str; 
    wcout << ((str.find(L'ф') != wstring::npos)? L"EXIST":L"NONE"); 

L'ф' jest cyrylica list.

Ale find() w tym samym wywołaniu zawsze zwraca npos. W przypadku liter łacińskich find() działa poprawnie.

Czy to jest problem tej funkcji? Czy źle coś zrobiłem?

UPD

używam MinGW i zapisać źródła w UTF-8. Ustawiam również ustawienia regionalne z setlocale(LC_ALL, "");. Kod ten sam wcout << L'ф'; działa współdziałająco. Ale ten sam

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

działa niepoprawnie.

To dziwne. Wcześniej nie miałem problemów z kodowaniem, używając setlocale().

+0

przypuszczam, że tego nie da się bezpośrednio zrobić poprawny i ta funkcja będzie przydatna: http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx – BlackCat

+0

Dlaczego? 'basic_string :: find()' działa z charT, to jest dla przypadku wstringa - z wcahr_t. "L'ф" to wchar_t, czyż nie? –

Odpowiedz

3

Kodowanie pliku źródłowego i kodowanie środowiska wykonawczego mogą być bardzo różne. C++ nie daje żadnych gwarancji co do tego. Można to sprawdzić poprzez wyprowadzanie szesnastkową wartość swojego łańcucha dosłowne:

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

Przed C++ 11, można używać znaków spoza ASCII w kodzie źródłowym za pomocą ich wartości hex:

"\x05" "five" 

C++ 11 dodaje możliwość określenia ich wartości Unicode, który w danym przypadku byłby

L"\u03A6" 

Jeśli masz zamiar pełen C++ 11 (i środowisko zapewnia te są kodowane w UTF- *) możesz użyć a ny z char, char16_t lub char32_t i zrobić:

const char* phi_utf8 = "\u03A6"; 
const char16_t* phi_utf16 = u"\u03A6"; 
const char32_t* phi_utf16 = U"\u03A6"; 
+0

Używam MinGW, konsoli Windows i zapisuję moje źródła w UTF-8. Ale nazywam setlocale (LC_ALL, ""); przed jakimkolwiek wejściem/wyjściem. Zakładam, że zapobiega podobnym problemom, prawda? –

+0

Nie. Problem nie dotyczy globalnego języka C uruchomionego programu, ale translacji bajtów kompilatora tworzących znak phi w pliku źródłowym. To tłumaczenie jest implementacją zdefiniowaną w ten sposób, a nie przenośną. – rubenvb

1

Musisz ustawić kodowanie konsoli.

to działa:

#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; 
} 
+0

Gdy próbuję tego w konsoli systemu Windows i wpisuję jakiś łańcuch wejściowy i wciskam 'enter', program po prostu się zawiesza (muszę wcisnąć' CTRL + C', aby wznowić). –

+0

Używam Windows 7 i Visual Studio 2012 i działa dobrze. –

+0

Używam Windows 7 i VS2010 ... może jest błąd w VS2010, który został naprawiony w 2012 (?). –

0

To pewnie kwestia kodowania. wcin działa z kodowaniem innym niż kod kompilatora/kodu źródłowego. Spróbuj wprowadzić ф w konsoli/wcin - to zadziała. Spróbuj wydrukować ф poprzez wcout - pokaże ona inną postać lub wcale.

Nie ma niezależny od platformy sposób na obejście tego, ale jeśli jesteś na oknach, można ręcznie zmienić kodowanie konsoli, albo z polecenia chchp poleceń lub programowo z SetConsoleCP() (wejście) i SetConsoleOutputCP() (wyjście).

Można również zmienić kodowanie pliku źródłowego/kompilatora.Sposób wykonania tej czynności zależy od edytora/edytora. Jeśli używasz MSVC, ta odpowiedź może pomóc: https://stackoverflow.com/a/1660901/2128694

+0

Nie, 'wcout << L'ф ';' działa poprawnie. –

1

działa dobrze. Ale musisz poprawnie odczytać ciąg wejściowy.

następujący kod działa poprawnie na konsoli Windows (wejście ciąg Unicode jest odczytywany za pomocą 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; 
    }   
} 

wyjściowa:

C:\TEMP>test.exe 
abc 
NONE 
C:\TEMP>test.exe 
abcфabc 
EXIST 
Powiązane problemy