2017-01-08 8 views
6

Używam Borland C++ Builder 2009, a moja aplikacja jest tłumaczona na kilka języków, w tym polski.C++ towupper() nie konwertuje określonych znaków

Dla niewielkiego elementu funkcji używam towuppper(), aby zamonetować ciąg znaków, aby położyć nacisk na to, gdy po raz pierwszy został zignorowany przez użytkownika.

Oryginalny ciąg jest ładowany z dll językowej, do obiektu UTF16 wstring i przekonwertować tak:

int length = mystring.length() ; 
for (int x = 0 ; x < length ; x++) 
    { 
    mystring[x] = towupper(mystring[x]); 
    } 

To wszystko działa dobrze, z wyjątkiem Polski, gdzie dodaje się zdanie: „Rozumiem ryzykowność wykonania Tej Operacji”zamienia się w "ROZUMIEM RYZYKOWNO SC WYKONANIA tEJ Operacji" zamiast "ROZUMIEM RYZYKOWNO SC WYKONANIA tEJ Operacji"

(zauważ, że te dwa ostatnie znaki z napisem "ryzykowność" nie konwersji).

To nie jest tak, że nie ma dostępnych wielkoformatowych wariantów tego znaku w Unicode. Znak Unicode 346 rozwiązuje problem. http://www.fileformat.info/info/unicode/char/015a/index.htm

Czy jest to kwestia przestarzałej biblioteki w mojej przestarzałej instalacji kompilatora, czy też brakuje mi czegoś innego?

+0

Czy te znaki są znormalizowane, czy składają się z wielu połączonych jednostek kodu? – user2079303

+0

Nie powinna to być przestarzała biblioteka, ponieważ zarówno 'ś' jak i' Ś' były obecne w Unicode v.1.1, z 1993 roku.Jeśli tak, to błąd twórcy tej funkcji. – usr2564301

+0

Do czego jest ustawiony twój region C? "Wielkopostaciowa wersja ch lub niemodyfikowana ch, jeśli w bieżącym locale C nie jest wyświetlana żadna wielka wersja." Czy jesteś w locale w Unicode? 'std :: setlocale (LC_ALL," en_US.utf8 ");'? Z http://en.cppreference.com/w/cpp/string/wide/towupper kilka łatwych do odczytania dokumentów na temat funkcji znalezionej przez google. Jeśli to nie rozwiąże problemu, podaj [mcve] – Yakk

Odpowiedz

11

Implementacje towupper nie są wymagane przez standard C++ do przeprowadzania konwersji znaków Unicode. Nawet jeśli szerokie łańcuchy są ciągami Unicode. Nawet w przypadkach, gdy jednoprzekrojowy kod małoduszny tworzy kod jednopikselowy.

Ponadto towupper nie jest w stanie przeprowadzić poprawnej konwersji przypadku Unicode, nawet jeśli implementacja go obsługuje. Konwersja przypadku może faktycznie zmienić liczbę punktów kodowych w sekwencji znaków Unicode. I towupper nie jest w stanie tego zrobić.

Nie można nie można polegać na standardowej bibliotece C++ do rozwiązywania problemów Unicode tego rodzaju. Musisz przejść do dedykowanej biblioteki Unicode, takiej jak ICU.

+0

Dobra implementacja standardowej biblioteki nadal byłaby w stanie przeprowadzić konwersję przypadku, gdy liczba punktów kodowych się nie zmieniła. –

+1

@ M.M: Nawet jeśli implementacja zapewnia funkcje o szerokim zakresie znaków, które starają się implementować Unicode tak bardzo, jak to możliwe, nadal jest to obietnica, której nie można zatrzymać. Nierzetelne funkcje są * niewiarygodne *. Jeśli potrzebujesz Unicode do pracy, musisz go * faktycznie pracować *, a nie tylko pracować, chyba że nie. –

+1

@NicolBolas wszystko zależy od domeny problemu. Jeśli wiesz, że będziesz pracować z ograniczonym podzbiorem wszystkich możliwych języków, dobrze byłoby wiedzieć, czy proste podejście byłoby lub nie zadziałałoby w przypadku tych konkretnych języków. –

2

W systemie Windows to zadziała: EDYCJA Właśnie zdałem sobie sprawę, że używasz Borlanda, a nie Msvc.

#include <cctype> 
#include <clocale> 

int main(int argc, char** argv) 
{ 
    setlocale(LC_ALL, "polish"); 

    wchar_t c[2] = { L'ś', L'ć'}; 
    wchar_t c1 = _towupper_l(c[0], _get_current_locale()); 
    wchar_t c2 = _towupper_l(c[1], _get_current_locale()); 

    return 0: 
} 

Najpierw należy ustawić ustawienia narodowe na "polerowanie" za pomocą setlocale. A następnie użyj _towupper_l. Oto link, który mówi, jakie łańcuchy, odnosząc się do określonego języka, mogą być używane z setlocale.

EDIT: Zauważ, że jeśli mogę wydrukować wyniki:

_wprintf_l(L" c1 = %c, c2 = %c\n", _get_current_locale(), c1, c2); 

wyjście będzie:

c1 = S, c2 = C 

ale jeśli oglądam wartości C1 i C2 w moim debugera, mogę zobacz poprawne wyniki, z akcentami. Moja konsola po prostu nie wydrukuje takich znaków.

+0

Niekoniecznie znam lokalizację każdego zdania, które może zostać przekazane do procedury, a może nawet być wieloma językami w jednym zdaniu. Na początku używa się Unicode. – Peter

+1

@Peter Musisz zrozumieć, że na przykład w języku francuskim wielkie litery 'é' to' E', a nie 'É'. Ale w przypadku innych języków używających litery "é", wielką literą "é" jest "É", a nie "E". Tak więc nie wiem, czy to, o co prosisz, jest możliwe, ponieważ wielkie litery jednej litery są bardzo specyficzne dla języka. EDYCJA: W moim poście znajduje się link o tym, jakie ciągi mogą być przekazywane do 'setlocale'. – nikau6

+0

Widzę twój punkt widzenia. Dzięki.Myślę, że idealnym rozwiązaniem jest wtedy poprosić moich tłumaczy o dostarczenie dwóch strun. Małe litery i wielkie litery – Peter