2013-04-03 5 views
5

Ho una stringa di caratteri ampi (std :: wstring) nel mio codice, e ho bisogno di cercare caratteri ampi in esso.wstring :: find() non funziona con i simboli non latini?

Io uso la funzione find() per esso:

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

L'ф' è una lettera cirillico.

Ma find() nella stessa chiamata restituisce sempre npos. In un caso con lettere latine find() funziona correttamente.

Si tratta di un problema di questa funzione? Oppure faccio qualcosa in modo errato?

UPD

Io uso MinGW e risparmi Fonte in UTF-8. Ho anche impostato la locale con setlocale(LC_ALL, "");. Codice stesso wcout << L'ф'; funziona in modo cooruito. Ma lo stesso

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

non funziona correttamente.

È strano. In precedenza non ho avuto problemi con la codifica, usando setlocale().

+0

Suppongo che questo non può essere fatto corretta direttamente e questa funzione tornerà utile: http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx – BlackCat

+0

Perché? 'basic_string :: find()' funziona con chart, cioè per un caso di wstring - con un wcahr_t. "L'ф" è un wchar_t, non è vero? –

risposta

3

La codifica del file sorgente e la codifica dell'ambiente di esecuzione possono essere molto diversi. C++ non fornisce garanzie su tutto ciò. È possibile controllare questo emettendo il valore esadecimale della vostra stringa letterale:

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

Prima di C++ 11, è possibile utilizzare caratteri non ASCII nel codice sorgente utilizzando i loro valori esadecimali:

"\x05" "five" 

C++ 11 aggiunge la possibilità di specificare il loro valore Unicode, che nel tuo caso sarebbe

L"\u03A6" 

se si sta andando pieno C++ 11 (e il vostro ambiente assicura che questi sono codificati in UTF-*), puoi usare a NY di char, char16_t o char32_t, e fare:

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

Io uso MinGW, la console di Windows e salvo i miei sorgenti in UTF-8. Ma chiamo setlocale (LC_ALL, ""); prima di qualsiasi input/output. Presumo, previene problemi simili, non è vero? –

+0

No. Il problema non è il locale C globale del programma in esecuzione, ma la traduzione del compilatore dei byte che costituiscono il carattere phi nel file sorgente. Questa traduzione è l'implementazione definita quindi non portatile. – rubenvb

1

È necessario impostare la codifica della console.

Questo funziona:

#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

Quando provo su una console di Windows e digito una stringa di input e preme 'enter', il programma si blocca (devo premere' CTRL + C' per riprendere). –

+0

Sto usando Windows 7 e Visual Studio 2012 e funziona perfettamente. –

+0

Sto usando Windows 7 e VS2010 ... forse c'è un bug in VS2010 che è stato corretto nel 2012 (?). –

0

Questo è probabilmente un problema di codifica. wcin funziona con una codifica diversa da quella del compilatore/codice sorgente. Prova ad inserire ф nella console/wcin - funzionerà. Prova a stampare ф tramite wcout - mostrerà un carattere diverso o nessun carattere.

esiste una piattaforma modo indipendente per aggirare questo, ma se si è in Windows, è possibile modificare manualmente la codifica console, sia con il comando chchp di comando o di programmazione con SetConsoleCP() (ingresso) e SetConsoleOutputCP() (uscita).

È anche possibile modificare la codifica del file sorgente/del compilatore.Il modo in cui questo viene fatto dipende dal tuo editor/compilatore. Se si utilizza MSVC, questa risposta può essere d'aiuto: https://stackoverflow.com/a/1660901/2128694

+0

No, 'wcout << L'ф ';' funziona bene. –

1

std::wstring::find() funziona correttamente. Ma devi leggere correttamente la stringa di input.

Il seguente codice funziona bene su console di Windows (la stringa Unicode ingresso viene letta utilizzando 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; 
    }   
} 

uscita:

C:\TEMP>test.exe 
abc 
NONE 
C:\TEMP>test.exe 
abcфabc 
EXIST 
Problemi correlati