2013-03-11 14 views
6

Szukam porady na temat najlepszego sposobu przekonwertowania std::wstring na std::string - ale szybka i brudna konwersja do użycia jako klucz w obiekcie std::map<std::string, int>.C++ - std :: wstring to std :: string - szybka i brudna konwersja do użycia jako klucz w std :: map

Mapa jest dość duży, a to już dobrze zintegrowane z projektem już, i istnieje tylko kilka klawiszy, które wymagają tej konwersji więc myślę, że to będzie marnotrawstwem zmienić mapę na taki, który akceptuje std::wstring jako klucz.

Dane wyjściowe konwersji nie mają większego znaczenia, ale muszą być spójne, aby za każdym razem niezawodnie pobierać prawidłowe wartości z mapy.

Aplikacja jest aplikacją wyłącznie dla systemu Windows.

Czy jest jakiś znany proces, aby niezawodnie przeprowadzić przetwarzanie zgrubne w tym celu? A może najlepszym sposobem będzie zwykły, właściwy proces konwersji (jak opisano w tym pytaniu/odpowiedzi na pytanie: How to convert wstring into string?)?

Edit: Proszę pamiętać - utraty informacji jest w porządku tak długo, jak rzeczy są spójne. np. jeśli wrzucę kilka japońskich znaków i konsekwentnie konwertują na to samo (potencjalnie śmieci) std::string, jest to w porządku. To nigdy nie będzie wyświetlane, tylko jako klucz do wyciągnięcia wartości z mapy.

Dzięki!

+0

An [adapter] (http://en.wikipedia.org/wiki/Adapter_pattern)? – krlmlr

+2

Być może powinieneś przekonwertować 'std :: wstring' na [UTF-8] (http://en.wikipedia.org/wiki/UTF-8) i ustawić' std :: string' na tę wartość. Unikniesz w ten sposób bajtów "\ 0". –

+0

Dlaczego w ogóle używasz 'std :: wstring'? [Użyj wszędzie UTF8.] (Http://utf8everywhere.org/) –

Odpowiedz

7

Jeśli nie interesuje cię semantyczna treść, ale tylko treść jest porównywalna, po prostu zakotwiczę wewnętrzny aspekt [] w char [] o podwójnej wielkości i użyję go do zainicjowania ciągu znaków (na podstawie adresu/rozmiar w konstruktora)

std::wstring ws(L"ABCD€FG"); 
std::string s((const char*)&ws[0], sizeof(wchar_t)/sizeof(char)*ws.size()); 

teraz s jest niedostępny do zadrukowania (może zawierać znaki zerowe), ale jeszcze przypisania i porównywalne.

Yo może wrócić jako:

std::wstring nws((const wchar_t*)&s[0], sizeof(char)/sizeof(wchar_t)*s.size()); 

Teraz porównać

std::cout << (nws==ws) 

należy wydrukować 1.

Należy jednak zauważyć, że w ten sposób kolejność na mapie (wynik operator<) jest ... rozmyta z powodu obecności 0 i nie odzwierciedla żadnego z elementów semantycznych. Jednak wyszukiwanie wciąż działa, ponieważ - choć rozmyty - wciąż jest "porządkiem".

+1

To będzie rozpraszało OP: punktem oczywiście nie jest piękny wydruk, ale sprawdzenie, czy podczas cyklu nie dochodzi do utraty informacji. Niezależnie od tego, jaki wynik zmienia się w zależności od równości, gra tak samo. Zrobiłem krótsze i prostsze, nie wymagające dodatkowych nagłówków. To OP musi znaleźć najlepszego "upiększacza" dla swoich potrzeb (w tym zastąpienie couta MessageBoxem lub jakimkolwiek dialogiem wyświetlającym to, co chciałby) –

+2

Gdyby to była mapa nieuporządkowana, byłbym zaniepokojony zerowymi bajtami w ciągu. Jeśli funkcja hashowania ma specjalizację dla łańcuchów, może lub nie może respektować rzeczywistego rozmiaru std :: string, a zamiast tego zatrzymać się przy pierwszym bajcie zerowym. –

7

Możesz przekonwertować std :: wstring na utf-8 (używając WideCharToMultiByte lub coś podobnego do tego lib: http://utfcpp.sourceforge.net/), to znaczy kończącego łańcuch c, a następnie skonstruuj std :: string z niego. Ta konwersja będzie odwracalna.

+0

+1: dobre znalezisko. –

9

Jako wariant, chciałbym przejść do

std::wstring w(L"Some"); 
std::string s(w.begin(), w.end()); 

Może druga odpowiedź jest szybsza (w zależności od realizacji String iteratory), ale jest to bardziej std \ droga STL jak dla mnie. Ale tak, to straci kilka unikalnych znaków.

Powiązane problemy