A podle jakeho standardu ty funkce pro praci s terminalem ve Windows jsou?
... presne tak, zadneho. Panove z MS si je vycucali z prstu.
Kazdopadne konzolovy vystup z Qt je lepsi delat pres Qt, nez se spolehat na funkce OS, ktere jsou z pohledu Qt nestandardni vsechny. Konkretne k tomu slouzi trida QTextStream, ktere se da predat stdout/stderr/popisovac souboru/etc. Kodovani se nastavuje pres setCodec().
S Windows command line muzou byt problemy taky, protoze ve vychozim stavu neumi zobrazit unicode, ale jenom lokalni codepage (u nas napr. 1250). Je potreba si v ni nastavit font, ktery unicode zvladne (ne-obrazkovy).
Viz: http://stackoverflow.com/questions/1259084/what-encoding-code-page-is-cmd-exe-using
Dalsi problem je, ze kompilator musi umet precist a spravne ulozit retezce ze zdrojaku. Pokud jich pouzivate vice (treba MSVC a GCC), muzou vzniknout problemy s kodovanim. MS kompilator predpoklada, ze delate v pribalenem IDE a vse je bud v UTF16 nebo v lokalni mutaci MS kodovani. U prenositelne aplikace tedy jakekoliv retezce s narodnimi znaky rozhodne nepatri do zdrojaku. Ty je lespi umistit do nejakeho jineho souboru, kde presne vite co se deje s jeho obsahem. Ve zdrojaku nechte ciste ASCII. Dost to zjednodussi lokalizaci programu a nestane se Vam, ze nekdo posle patch s rozbitymi retezci/kodovanim, na kterych si nasledne nektery kompilator vylame zuby :)
Drobny Qt uvod: http://www.youtube.com/wat ch?v=lz9deRYwNFY
PS: proc me to nechce vzit slovo ,,wat ch'' vcelku?
Díky za velmi objektivní příspěvek. Ten unicode ve Windows konzoli je challenge a zdá se to průstřelné až od Win7 (diskuze dole - změna fontu programátorsky). Nicméně díky za připomínku, že se radši nespoléhat, že kompilátor správně rozpozná a zpracuje unicode znaky v našem zdrojáku. Jediná diakritika v anglicky mluvící aplikaci je často pouze jméno českého programátora v About boxu. Na toto bude zřejmě dostatečné nahradit diakritické znaky ve zdrojáku "hexa-reprezentací". Pro opravdovou lokalizaci se pak asi nejlépe vrhnout na standardní přístup Qt (QObject::tr()).
Bits Last code point Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 7 U+007F 0xxxxxxx 11 U+07FF 110xxxxx 10xxxxxx 16 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx 21 U+1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 26 U+3FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 31 U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
viz Wiki
Jak? Jednoduše! Musíš si uvědomit, čím UTF-? jsou a čím nejsou! Je to způsob, jak kódovat číselné kódy unicode znaků do bajtů. No a unicode prostor má rozsah 000000-10FFFF. Z toho ti plynou dvě věci:
Mimochodem, ne 31 ale 32 bitová, jak jsem již psal. Neboť i když byl unicode prostor původně 31 bitový, nic to nemění na tom, že:
UTF-32 is the simplest Unicode encoding form. Each Unicode code point is represented directly by a single 32-bit code unit. (Unicode Standard 6.0)
Přesto ale:
As for all of the Unicode encoding forms, UTF-32 is restricted to representation of code points in the range 0-10FFFF - that is, the Unicode codespace. This guarantees interoperability with the UTF-16 and UTF-8 encoding forms. (Unicode Standard 6.0)
The original specification allowed for sequences of up to six bytes, covering numbers up to 31 bits (the original limit of the Universal Character Set). In November 2003 UTF-8 was restricted by RFC 3629 to four bytes covering only the range U+0000 to U+10FFFF, in order to match the constraints of the UTF-16 character encoding.
viz Wiki... :)
RFC 2044 (1996): 4 octets
RFC 2279 (1998): 6 octets
RFC 3629 (2003): 4 octets
#include <stdio.h> #include <windows.h> int main(void) { SetConsoleOutputCP(65001); printf("%s\n", "PĹ™Ăliš ĹľluĹĄouÄŤkĂ˝ kĹŻĹ"); /* UTF-8 */ printf("%S\n", L"Text"); /* UTF-16 */ return(0); }
Pozn.: když se nastaví např. Lucida Console, tak to funguje skvěle ;)
Pozn.: ekvivalentem funkčního volání SetConsoleOutputCP(65001) je příkaz "chcp 65001"
Zkoušel jsem. Nefunguje. Navíc se nedá specifikovat font, který chci. Alespoň indexu do tabulky, kde jsou pouze rozměry fontu, neříkám výběr. To je spíše změna velikosti fontu udělaná přes obludné API. (Microsoft zde propadá, ač je to nedokumentovaná funkce.)
Nicméně díky za link.
Ve Vistách a 7mičkách lze použít:
#include <windows.h> #include <strsafe.h> int main(void) { CONSOLE_FONT_INFOEX cfie; ZeroMemory(&cfie, sizeof(cfie)); cfie.cbSize = sizeof(cfie); cfie.dwFontSize.Y = -20; cfie.FontFamily = FF_DONTCARE; cfie.FontWeight = 400; StringCbCopyW(cfie.FaceName, sizeof(cfie.FaceName), L"Lucida Console"); SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfie); return(0); }
ve starších verzích buď to harakiri, co tu někdo posílal jako odkaz, nebo ho nastavit jako výchozí font na daném zástupci a spoléhat, že ho nikdo nezmění.
P.S.: zkoušel jsem podporu UTF-16 v printf() a máte pravdu, konzole Windows fakt stojí za ........ zlámanou grešli, spolehlivě funguje skutečně pouze WriteConsoleW() :/
Kód
QString s(a+b+c+d+e+f+g);
std::cout << s;
je obecně špatně. Qt lze nakonfigurovat bez podpory STL, je tedy potřena zkontrolovat příslušný define, než si toto můžete v kódu dovolit (nebo si ručně přetížit daný operátor).
Předpoklad použití UTF-8 pro názvy souborů na linuxu je opět špatný. Proto např. v glib existují funkce typu g_filename_to/from_utf8. Qt se o to naštěstí postará samo, pokud použijete jeho funkce. Ale tvrdit, že funkci fopen předáte utf-8 je blbost.
UTF-16 se ve Windows používá až od Windows XP. Před tím to bylo UCS-2. Ale dobře, nemá smysl podporovat již delší dobu nepodporované verze, píšu to jen pro upřesnění.
Při použití wchar_t není standardem zaručeno použití UTF-16 či UTF-32 a je to jen vaše doměnka. Záleží na kompilátoru, jak váš řetězec vytvoří. K tomuhle budou v C++0x prefixy u a U a nové typy char16_t a char32_t.
Článek, zdá se, trochu zmatkuje i v případě paměťových nároků. Pro jednotlivé rozsahy a kódování by náročnost měla být tato:
unicode rozsah | UTF-8 | UTF-16 | UTF-32 -------------------------------------------------- 0000 0000 - 0000 007F | 1B | 2B | 4B 0000 0080 - 0000 07FF | 2B | 2B | 4B 0000 0800 - 0000 FFFF | 3B | 2B | 4B 0001 0000 - 0010 FFFF | 4B | 4B | 4B
UTF-8 je tedy horší než UTF-16 na rozsahu 0800-FFFF, a to pouze o jeden bajt.
Co se týče v článku zmíněné cyrilice, ta používá rozsah 0400-04FF. Její znaky tedy zaberou jak v UTF-8 tak v UTF-16 shodně dva bajty. Dokonce i na tu arabštinu (rozsah 0600-06FF) u obou vystačí ještě dva bajty.
Kdyby se vyškrtaly všechny řádky, které se netýkají Qt, zůstane - počítal jsem to! - osm řádků, které samy o sobě nedávají smysl. Plyne mi z toho, že celý článek nedává smysl.
Psát multiplatformní vícejazyčné aplikace čistě v Qt je velmi snadné, stačí využívat pro práci s textem prostředky Qt. Odpusťte si platformě závislé věci (WriteConsoleW) nebo věci s UTF nefungující (std) a uvidíte, že kód pro Linux i pro Windows může vypadat úplně stejně.
Napsal jsem stovky tisíc řádků v Qt aplikacích jak pro Linux tak pro Windows a zvěrstva jako je podmíněný překlad jsem nikdy neměl potřebu použít. Kód je stoprocentně shodný pro obě platformy.
Nelze nez souhlasit uz veta:
"Pro zjištění skutečného počtu znaků můžeme použít například funkci mbstowcs()."
Tato funkce ma hlavni funkci na prevod char->wchar_t a vydavato za funkci na zjisteni delky misto funkce primo pro toto urcene wcslen().
V clanek narazi na zajimave tema, nu obsahove je na dve veci. Jak napsal P.Bravenec tak nelze nez souhlasit. Kod co je v ukazkach je slabe receno divne.
K panu Bravencovi: Dal jste si článek do souvislosti s Qt, což bohužel zapřičinila redakce, která změnila můj název článku zřejmě během jazykové korektury aniž by mě o tom informovala a aniž bych měl možnost to ovlivnit. Původně to mělo být o unicode a jeho použití napříč platformami. Již včera jsem informoval redakci, že měnit větu v článku je ok, ale název? A bez vědomí autora?
A teď druhá věc: Jestli jste nepoužíval podmíněný překlad, tak pochybuju, že jste opravdu programátor, nebo možná děláte jen GUI. Qt je užasné a používáme jej ve firmě (jeden kód pro všechny platformy), avšak jsou věci, které v Qt nenapíšete. Například nespustíte child process třídou QProcess s elevací práv procesu na Windows. Qt to neumí, Linux neví co to je a je nutno použít funkce ShellExecuteEx a podmíněného překladu.
Pan Karel2: Děkuji za přípomínku ohledně wcslen a mbstowcs, avšak mbstowcs lze opravdu použít ekvivalentním způsobem jak wcslen. Nicméně máte pravdu, že wcslen se hodí lépe. Jestli se Vám článek nelíbí, jak píšete, napište svůj. Je na světě hodně kecalů, ale málo mužů činu. Já jsem s článkem spokojen, neboť mi v diskuzi poskytl mnoho nových impulzů v některých problematických otázkách a platformách (Windows).
Máte pravdu. Primárně dělám vše v Linuxu. V linuxu aplikace i překládám (mingw) a taky mi zde běží všechny serverové části (často v Qt, pouze konzolové aplikace). Pro Windows mi naštěstí stačí psát jen GUI aplikace, kde jsem opravdu neměl nikdy potřebu sáhnout po podmíněném překladu. Pro zadávání řetězců mi pak stačí používat trUtf8(), případně tr() spolu s nástroji pro překlad. Pokud potřebuji zadat nějaké platformě závislé věci (cesty k souborům a podobně), řešívám to přes konfigurační dialogy.
Jinak mně kdysi tady na rootu název článku nezměnili... a připadám si jako trouba ještě dnes :-)
Pro programování v C++ ve Windows platí:
"text" - ANSI („neunicode“) text (pro české Windows cp-1250)
L"text" - utf-16 text
Dále v knihovně tchar.h je nastaveno spousta maker, které na základě toho, zda je nebo není definováno UNICODE mapují typy/funkce na ANSI/UTF-16 variantu
_T("text") - pokud je definováno UNICODE, pak L"text" (UTF-16), jinak "text" (ANSI)
TCHAR - pokud je definováno UNICODE, pak wchar_t, jinak v (podobně: LPCTSTR, LPTSTR, PCTSTR, PTCHAR)
_tcslen, _tcscmp, _tcsdup, ...
V Linuxu jsem to nezkoušel, tam je vše UTF-8 (tj. bez problémů).