Internacionalizace a lokalizace v C++
Minule jsme si povφdali o zßkladnφch problΘmech s nßrodnφm prost°edφm v programech v C++. P°itom jsme hovo°ili nejen o ΦeskΘm nßrodnφm prost°edφ, ale o problΘmech s nßrodnφm prost°edφm v∙bec. Dozv∞d∞li jsme se o t°φd∞ locale a o jejφ spoluprßci s objektov²mi datov²mi proudy. Dnes se podφvßme na dalÜφ ·lohy, kterΘ je t°eba v souvislosti s nßrodnφm prost°edφm °eÜit.
Podobn∞ jako v minulΘm dφlu i zde musφme zd∙raznit, ₧e mnoho p°ekladaΦ∙ dosud tyto nßstroje neimplementuje nebo je implementuje s chybami, proto nebu∩te p°ekvapeni, kdy₧ vßm zde uvedenΘ p°φklady nebudou fungovat. Je vÜak jistΘ, ₧e v dohlednΘ dob∞ se situace zm∞nφ û novΘ verze v²vojov²ch nßstroj∙ se budou muset p°izp∙sobit standardu. Koneckonc∙, nov∞jÜφ programovacφ jazyky, jako je Java nebo C#, nßrodnφ nastavenφ bez problΘm∙ zvlßdajφ, tak₧e C++ nem∙₧e z∙stat v²jimkou.
Z p°edchozφho dφlu vφme, ₧e p°i formßtovanΘm v²stupu do proudu s pou₧itφm nßrodnφho prost°edφ se znaky p°eklßdajφ do k≤dovßnφ, pou₧φvanΘho v danΘm systΘmu, pod Windows to znamenß p°eklad do k≤dovΘ strßnky 1250. To ale platφ i p°i neformßtovanΘm v²stupu. Podφvejme se na nßsledujφcφ p°φklad:
#include <fstream>
#include <iostream>
#include <locale>
#include <string>
#include <stdexcept>using namespace std;wchar_t cw[] = L"₧lu¥ouΦk² k∙≥ p°φÜern∞ ·p∞l ∩ßbelskΘ ≤dy";int main()
{
try {
wofstream f("data.dta");
f.imbue(locale("Czech_Czech Republic.1250"));
if(!f) throw runtime_error("chyba proudu");
f.write(cw, sizeof(cw)/sizeof(wchar_t));
f.close();
}
catch(runtime_error &e)
{
cerr << e.what();
}
return 0;
}
Zde uklßdßme data pomocφ metody write(), urΦenΘ pro neformßtovanΘ operace
û i ta ovÜem p°evede k≤dovßnφ Unicode do zadanΘ k≤dovΘ strßnky. M∙₧eme samoz°ejm∞
pou₧φt i k≤dovou strßnku 852, pak dostaneme soubor v k≤dovßnφ Latin 2. TotΘ₧
platφ i pro k≤dovßnφ ISO 8859-2 nebo pro ΦeÜtinu pro MacIntosh.
Poznamenejme, ₧e pou₧ijeme-li implicitnφ nßrodnφ prost°edφ "C" (nebo
vynechßme-li volßnφ metody imbue() û v²sledek bude t²₧), neulo₧φ se do souboru
data.dta nejspφÜ nic, nebo¥ proud nebude um∞t p°evΘst ΦeskΘ znaky z Unicode
do odpovφdajφcφ k≤dovΘ strßnky.
Jak zapsat Unicode do souboru
Ukazuje se tedy, ₧e pro ulo₧enφ textu v k≤dovßnφ Unicode se proudy moc nehodφ,
nebo¥ dneÜnφ implementace û alespo≥ pod Windows û neposkytujφ nßrodnφ prost°edφ
s k≤dovßnφm, kterΘ by to umo₧≥ovalo. (Mo₧nß takovΘ prost°edφ ve Windows existuje,
nßm se ho ale nepoda°ilo zatφm zjistit.) To znamenß, ₧e chceme-li do souboru
ulo₧it opravdu znaky v k≤dovßnφ Unicode, musφme sßhnout po osv∞dΦen²ch funkcφch
pro neformßtovan² zßpis z jazyka C, jako je fwrite(). K ulo₧enφ v∞ty o ₧lutΘm
koni do souboru data.dta m∙₧eme pou₧φt nßsledujφcφ program:
#include <cstdio>using namespace std;wchar_t cw[] = L"₧lu¥ouΦk² k∙≥ p°φÜern∞ ·p∞l ∩ßbelskΘ ≤dy";int main() // ZapφÜe Unicode
{
FILE *f = fopen("data.dta", "wb");
fwrite(cw, sizeof(wchar_t), sizeof(cw)/sizeof(wchar_t), f);
fclose(f);
return 0;
}
I zde ovÜem m∙₧eme narazit na problΘmy. Pokud budeme Φφst ulo₧enß data na stejnΘm poΦφtaΦi, jako jsme je zapisovali, bude vÜe v po°ßdku. M∙₧e se ovÜem stßt, ₧e se na zdrojovΘm a cφlovΘm poΦφtaΦi bude liÜit zp∙sob uklßdßnφ Φφsel do pam∞ti.
Mal² a velk² endißn
B∞₧n∞ se pou₧φvajφ dva zcela rovnocennΘ, ovÜem navzßjem nekompatibilnφ zp∙soby
ulo₧enφ dat v poΦφtaΦi, oznaΦovanΘ jako mal² a velk² endißn (little, resp.
big endian). Volba mezi nimi je zpravidla urΦena architekturou procesoru.
Osobnφ poΦφtaΦe pou₧φvajφ mal² endißn, ovÜem nap°φklad virtußlnφ stroj jazyka
Java pou₧φvß velk² endißn, a to bez ohledu na to, na jakΘm poΦφtaΦi ho spouÜtφme.
P°i malΘm endißnu se mΘn∞ v²znamnΘ bajty uklßdajφ na ni₧Üφ adresy, p°i velkΘm
endißnu se mΘn∞ v²znamnΘ bajty uklßdajφ na vyÜÜφ adresy. To znamenß, ₧e nap°.
dvoubajtovΘ Φφslo 0x1234 typu short se na poΦφtaΦi, pou₧φvß mal² endißn, ulo₧φ
v po°adφ 0x34, 0x12, zatφmco na poΦφtaΦi pou₧φvajφcφm velk² endißn se ulo₧φ
v po°adφ 0x12, 0x34. Poznamenejme, ₧e r∙znΘ uklßdßnφ se t²kß nejen cel²ch,
ale i reßln²ch Φφsel.
Typ wchar_t pat°φ mezi celoΦφselnΘ typy, tak₧e se ho problΘmy s endißnem takΘ
t²kajφ. Proto se dodr₧uje konvence, ₧e na poΦßtek souboru, obsahujφcφho Unicode,
se zapisuje znak s hodnotou \uFEFF. Pokud zde p°i Φtenφ najdeme znak \uFFFE,
znamenß to, ₧e soubor byl zapsßn v opaΦnΘm endißnu, ne₧ jak² pou₧φvß aktußlnφ
poΦφtaΦ, ₧e tedy p°i Φtenφ musφme prohodit po°adφ bajt∙ v ka₧dΘm p°eΦtenΘm
znaku.
S t°φdou locale jsme se zb∞₧n∞ seznßmili ji₧ v minulΘm dφlu. Ne₧ p∙jdeme dßle, podφvßme se na ni trochu blφ₧e. JednotlivΘ souΦßsti nßrodnφho prost°edφ jsou ve t°φd∞ locale zapouzd°eny do tzv. fazet, tedy t°φd, odvozen²ch od spoleΦnΘho p°edka û t°φdy locale::facet. Ne₧ si ale o nich n∞co povφme, podφvßme se na deklaraci t°φdy locale tak, jak ji najdeme ve standardu ISO 14882.
Deklarace t°φdy locale
namespace std {
class locale {
public:
// datovΘ typy:
class facet;
class id;
typedef int category;
static const category // SkuteΦnß implementace m∙₧e u₧φt
none = 0, // jinΘ hodnoty
collate = 0x010, ctype = 0x020,
monetary = 0x040, numeric = 0x080,
time = 0x100, messages = 0x200,
all = collate | ctype | monetary | numeric | time | messages;// konstrukce, destrukce a kopφrovßnφ:
locale() throw()
locale(const locale& other) throw()
explicit locale(const char* std_name);
locale(const locale& other, const char* std_name, category);
template <class Facet> locale(const locale& other, Facet* f);
locale(const locale& other, const locale& one, category);
~locale() throw(); // nenφ virtußlnφ
const locale& operator=(const locale& other) throw();
template <class Facet> locale combine(const locale& other);// operace s instancφ t°φdy locale:
basic_string<char> name() const;
bool operator==(const locale& other) const;
bool operator!=(const locale& other) const;
template <class charT, class Traits, class Allocator>
bool operator()(const basic_string<charT,Traits,Allocator>& s1,
const basic_string<charT,Traits,Allocator>& s2) const;// globßlnφ objekty t°φdy locale:
static locale global(const locale&);
static const locale& classic();
};
}
Tato deklarace neukazuje soukromΘ slo₧ky, kterΘ implementujφ chovßnφ instancφ.
(Ty nejsou uvedeny ani ve standardu).
Konstanty typu category û kategorie û urΦujφ kategorie nßrodnφho prost°edφ,
podobnΘ kategoriφm znßm²m z jazyka C.
Z konstruktor∙ zatφm znßme pouze jeden, jen₧ mß jako parametr znakov² °et∞zec
se jmΘnem nßrodnφho prost°edφ. V²znam kopφrovacφho konstruktoru je z°ejm².
Konstruktor
template <class Facet> locale(const locale& other, Facet* f);
umo₧≥uje vytvo°it novou instanci t°φdy locale, je₧ bude kopiφ instance other, bude vÜak obsahovat fazetu f. (V p°φpad∞ pot°eby nahradφ f jednu ze standardnφch fazet.) Konstruktor
locale(const locale& other, const locale& one, category cats);
slou₧φ k podobnΘmu ·Φelu: Vytvo°φ kopii instance other, avÜak fazety pro
kategorie definovanΘ parametrem cats p°evezme z instance one.
Poznamenejme, ₧e takto vytvo°enΘ instance t°φdy locale nemajφ jmΘno zavolßme-li
pro takto vytvo°enou instanci metodu name(), vrßtφ °et∞zec "*".
K porovnßvßnφ instancφ t°φdy locale slou₧φ operßtory == a !=. Operßtor ==
vracφ true, je-li lev² operand toto₧n² s prav²m, je-li jeden operand kopiφ
druhΘho nebo majφ-li oba stejnΘ jmΘno.
Statickß metoda locale::global() nastavφ instanci, p°edanou jako parametr,
jako globßlnφ nßrodnφ prost°edφ, podobn∞ jako funkce setlocale() z jazyka
C. Zßrove≥ vrßtφ instanci, p°edstavujφcφ p°edchozφ nßrodnφ prost°edφ.
Statickß metoda locale::classic() vrßtφ odkaz na instanci nßrodnφho prost°edφ,
urΦenΘho °et∞zcem "C".
K dalÜφm operacφm s instancemi t°φdy locale se jeÜt∞ dostaneme.
T°φda locale jako kontejner na fazety
U₧ jsme si °ekli, ₧e jednotlivΘ souΦßsti nßrodnφho prost°edφ jsou zapouzd°eny
do tzv. fazet. Deklarace t°φdy facet podle standardu jazyka vypadß takto:
namespace std {
class locale::facet {
protected:
explicit facet(size_t refs = 0);
virtual ~facet();
private:
facet(const facet&); // nenφ definovßn
void operator=(const facet&); // nenφ definovßn
};
}
VÜimn∞te si, ₧e tato t°φda neobsahuje ₧ßdnΘ ve°ejn∞ p°φstupnΘ slo₧ky. Nenφ
tedy urΦena k bezprost°ednφmu pou₧itφ, slou₧φ jen jako spoleΦn² p°edek pro
t°φdy, kterΘ budou skuteΦn∞ implementovat jednotlivΘ souΦßsti nßrodnφho prost°edφ.
Kopφrovacφ metody, tedy kopφrovacφ konstruktor a p°i°azovacφ operßtor, jsou
deklarovßny jako soukromΘ a nejdou definovßny. To zaruΦuje, ₧e instance ₧ßdnΘ
z odvozen²ch t°φd nebude mo₧nΘ kopφrovat.
Konstruktor mß jeden celoΦφseln² parametr, kter² urΦuje, zda se bude o zruÜenφ
fazety starat programßtor nebo t°φda locale. Implicitnφ hodnota 0 znamenß,
₧e se o ni bude starat instance t°φdy locale, je₧ bude fazetu vlastnit.
Standardn∞ obsahuje t°φda locale °adu fazet. Jsou definovßny prost°ednictvφm
Üablon a t°φda locale obsahuje jejich instance jak pro ÜirokΘ, tak pro ·zkΘ
znaky. Rozd∞lφme je do jednotliv²ch kategoriφ, v nßsledujφcφm p°ehledu T znamenß
jak char, tak i wchar_t, zatφmco C m∙₧e b²t i jak²koli jin² znakov² typ.
1. V kategorii °azenφ znak∙ (collate) najdeme fazety collate<T> a collate_byname<T>.
2. V kategorii klasifikace typ∙ (ctype) najdeme fazety ctype<T> a ctype_byname<T>.
3. V kategorii nßstroj∙ pro prßci s m∞nou (monetary) mßme fazety moneypunct<T,International>,
moneypunct_byname<T,International>, moneypunct_byname<T,true>,
money_get<C>, money_get<C,InputIterator>, money_put<C> a
money_put<C,OutputIterator>.
4. V kategorii formßtovßnφ Φφsel (numeric) najdeme fazety numpunct<T>,
numpunct_byname<T>, num_get<C,InputIterator> a num_put<C,OutputIterator>.
5. V kategorii formßtovßnφ Φasov²ch ·daj∙ (time) jsou fazety time_get<T,InputIterator>,
time_get_byname<T,InputIterator>, time_put<T,OutputIterator>a
time_put_byname<T,OutputIterator>.
6. Poslednφ je kategorie zprßv (messages). V nφ najdeme fazety messages<T>
a messages_byname<wchar_t>.
Fazeta s identifikßtorem xxx_byname poskytuje tytΘ₧ nßstroje jako fazeta s
identifikßtorem xxx, pouze mß navφc konstruktor s parametrem, kter²m je znakov²
°et∞zec obsahujφcφ jmΘno nßrodnφho prost°edφ.
Parametr International u fazet pro prßci s m∞nou je bu∩ true nebo false a
urΦuje, zda se budou pou₧φvat mezinßrodnφ zkratky pro m∞nu (CZK, CHF atd.).
Parametry OutputIterator, resp. InputIterator umo₧≥ujφ zadat buffer, do n∞ho₧
se bude v²stup vypisovat.
Poznamenejme, ₧e u₧ivatel si m∙₧e definovat i svΘ vlastnφ fazety a p°i vytvß°enφ
instance t°φdy locale pomocφ konstruktoru je do nφ p°idat.
V tomto Φlßnku se ovÜem zdaleka nedostaneme ke vÜem standardnφm fazetßm.
P°φstup k fazetßm
JednotlivΘ fazety danΘho nßrodnφho prost°edφ m∙₧eme pou₧φvat prost°ednictvφm
ÜablonovΘ funkce
template<class Facet> const Facet& use_facet(const locale&);
Tato funkce vracφ odkaz na po₧adovanou fazetu. Parametr Facet, udßvajφcφ typ fazety, se v deklaraci objevuje pouze jako typ vracenΘ hodnoty, proto musφme p°i volßnφ zadat tento parametr Üablony v₧dy uvßd∞t. (P°ekladaΦe, kterΘ explicitnφ specifikaci parametr∙ Üablon u funkcφ nepodporujφ, musφ nabφdnout zp∙sob, jak to obejφt). Parametrem funkce use_facet<>() je instance t°φdy locale, z nφ₧ chceme danou fazetu vzφt. Podφvejme se na p°φklad: V minulΘm dφlu jsme p°i p°evodu mezi Üirok²mi a ·zk²mi znaky pou₧φvali fazetu ctype<wchar_t> z instance lokßlnφho nastavenφ Kon p°φkazem
use_facet<ctype<wchar_t> >(Kon)
Proto₧e v²sledkem tohoto volßnφ je odkaz na po₧adovanou fazetu, mohli jsme ihned volat jejφ metodu narrow() p°φkazem
use_facet<ctype<wchar_t> >(Kon).narrow(
cw, cw+sizeof(cw)/sizeof(wchar_t), '*', cn);
Pokud po₧adovanß fazeta v danΘ instanci lokßlnφho nastavenφ chybφ, vyvolß tato metoda v²jimku typu std::bad_cast. Chceme-li zjistit, zda urΦitß instance t°φdy locale obsahuje jistou fazetu, pou₧ijeme Üablonovou funkci
template <class Facet> bool has_facet(const locale&) throw();
TakΘ p°i pou₧itφ tΘto funkce musφme uvßd∞t Üablonov² parametr, urΦujφcφ typ fazety. Parametrem tΘto funkce pak je instance t°φdy locale.
Nßrodnφ prost°edφ a datovΘ proudy
U₧ vφme, ₧e instanci t°φdy locale m∙₧eme p°ipojit k datovΘmu proudu, slou₧φ
k tomu metoda imbue(), definovanß ve t°φd∞ ios_base, kterß je spoleΦn²m p°edkem
vÜech proudov²ch t°φd. Datov² proud si uchovßvß kopii p°edanΘ instance, to
znamenß, ₧e p∙vodnφ instance m∙₧e po volßnφ metody imbue() zaniknout.
Chceme-li zφskat aktußlnφ nßrodnφ prost°edφ, kterΘ dan² proud pou₧φvß, zavolßme
metodu getloc(), je₧ je takΘ definovßna ve t°φd∞ ios_base.
Implicitn∞ je u vÜech proud∙ nastaveno prost°edφ "C".
Vra¥me se op∞t k problΘm∙m nßrodnφch nastavenφ. Jednou z nejjednoduÜÜφch ·loh, na kterΘ m∙₧eme narazit, je klasifikace znak∙ û zda jde o pφsmeno, Φφslici atd. û a p°evod mezi mal²mi a velk²mi pφsmeny.
P°evod mezi mal²mi a velk²mi pφsmeny
P°evod mal²ch pφsmen na velkß a naopak je snadn², omezφme-li se na anglickou
abecedu v k≤dovßnφ ASCII. Nßsledujφcφ verzi funkce toupper() napsal nejspφÜ
ka₧d², kdo se uΦil jazyk C nebo C++ :
char toupper(char c)
{
if((c >= 'a') && (c <= 'z'))
return c + 'A' - 'a';
else
return c;
}
Jakmile ovÜem vstoupφ do hry znaky nßrodnφch abeced, situace se zkomplikuje.
M∙₧eme narazit na nßsledujφcφ nesnßze:
1. Nßrodnφ prost°edφ nerozliÜuje malß a velkß pφsmena, to se t²kß nap°. hebrejÜtiny.
Pak ovÜem odpadajφ problΘmy s jejich vzßjemn²m p°evodem.
2. Vztah mezi mal²mi a velk²mi pφsmeny nemusφ b²t vzßjemn∞ jednoznaΦn². P°evodem
mal²ch pφsmen na velkß a zp∞t tak m∙₧e vzniknout dokonce jinΘ slovo. To se
t²kß nap°. francouzÜtiny, v nφ₧ se mohou u velk²ch pφsmen vynechßvat akcenty,
u mal²ch vÜak nikoli. Nap°. slovo äouô (kde) se p°i p°evodu na velkß pφsmena
m∙₧e zm∞nit v OU a po p°evodu zp∞t dostaneme äouô, co₧ znamenß äneboô.
3. K malΘmu pφsmenu neexistuje odpovφdajφcφ velkΘ pφsmeno. To se t²kß nap°.
n∞mΦiny, kde se znak ▀ (äostrΘ sô) p°i pou₧itφ velk²ch pφsmen nahrazuje dvojicφ
SS. Nap°φklad jmΘno jednoho ze nejznßm∞jÜφch n∞meck²ch matematik∙, kterΘ se
tradiΦn∞ pφÜe Gau▀, bychom pomocφ velk²ch pφsmen zapsali jako GAUSS. (Dv∞
s se takΘ pou₧φvajφ jako nßhrada ▀ ve znakov²ch sadßch, kterΘ tento znak neobsahujφ,
dnes se ovÜem Φasto pou₧φvajφ mφsto ▀ i v b∞₧nΘ n∞mΦin∞.)
Standardnφ knihovna jazyka C++ umo₧≥uje p°evod mezi mal²mi a velk²mi pφsmeny,
zalo₧en² na vzßjemn∞ jednoznaΦnΘ korespondenci, to znamenß, ₧e ne°eÜφ problΘmy
2 a 3. V ΦeÜtin∞ naÜt∞stφ na ₧ßdn² z t∞chto problΘm∙ nenarazφme.
K p°evodu mezi mal²mi a velk²mi pφsmeny pou₧ijeme fazetu ctype<wchat_t>,
kterß v podstat∞ pokr²vß vÜe, co um∞jφ funkce ze standardnφ hlaviΦky ctype.h
z jazyka C. Mßme-li znakov² °et∞zec
wchar_t cw[] = L"₧lu¥ouΦk² k∙≥ p°φÜern∞ ·p∞l ∩ßbelskΘ ≤dy";
m∙₧eme ho p°evΘst na velkß pφsmena p°φkazem
use_facet<ctype<wchar_t> >(L).toupper(cw, &cw[sizeof(cw)/sizeof(wchar_t)]);
Metoda toupper() mß dva parametry, prvnφ z nich je ukazatel na prvnφ prvek
p°evßd∞nΘho ·seku, druh² je ukazatel na poslednφ prvek tohoto ·seku. Tato
metoda vracφ ukazatel na prvnφ prvek p°evedenΘho ·seku.
Pokud odpovφdajφcφ znak neexistuje, tj. pokud n∞jak² znak nelze p°evΘst na
velkΘ pφsmeno, ponechß tato funkce nezm∞n∞n² p∙vodnφ znak.
Podφvejme se na p°φklad. Vezmeme °et∞zec
wchar_t CW[100] = L"Gau▀";;
a zkusφme ho v n∞meckΘm prost°edφ p°evΘst na velkß pφsmena:
locale LG("german");
use_facet<ctype<wchar_t> >(LC)
.toupper(cw, &cw[sizeof(cw)/sizeof(wchar_t)]);
V²sledkem bude °et∞zec "GAU▀". Prvnφ znak neÜlo p°evΘst, proto₧e 'G' je ji₧ samo o sob∞ velkΘ pφsmeno, poslednφ znak takΘ ne, nebo¥ k '▀' odpovφdajφcφ velkΘ pφsmeno neexistuje. Oba znaky tedy z∙staly nezm∞n∞ny.
Nßsledujφcφ program ukazuje p°evod ΦeskΘho i n∞meckΘho textu. Poznamenejme, ₧e na konzolu pod Windows se v n∞meckΘm prost°edφ pou₧φvß k≤dovß strßnka 850, zatφmco pro v²stup do oken se pou₧φvß k≤dovß strßnka 1252.
#include <locale>
#include <string>
#include <iostream>using namespace std;wchar_t cw[] = L"₧lu¥ouΦk² k∙≥ p°φÜern∞ ·p∞l ∩ßbelskΘ ≤dy";
wchar_t CW[100] = L"Gau▀";;int main(int argv, char *argc[])
{
locale LC("czech");
locale LG("German_Germany.1252");// M∞nφme Φesk² text
wcout.imbue(locale("Czech_Czech Republic.852"));
wcout << cw << endl;
use_facet<ctype<wchar_t> >(LC)
.toupper(cw, &cw[sizeof(cw)/sizeof(wchar_t)]);
wcout << cw << endl;// M∞nφme n∞meck² text
wcout.imbue(locale("German_Germany.850"));
wcout << CW << endl;
use_facet<ctype<wchar_t> >(LC).toupper(CW, &CW[4]);
wcout << CW << endl;
return 0;
}
Vedle metody, kterß zpracovßvß cel² ·sek °et∞zce, je ve fazet∞ ctype<>
k dispozici takΘ p°etφ₧enß verze, kterß konvertuje jedin² znak.
Pro p°evod na malß pφsmena je k dispozici analogickß dvojice metod jmΘnem
tolower().
Klasifikace znak∙
Fazeta ctype<> obsahuje metodu
bool is(mask m, charT c) const;
kterß umo₧≥uje testovat, zda p°edan² znak vyhovuje urΦitΘ masce, tj. zda
pat°φ do urΦitΘ kategorie. Tyto masky jsou definovßny jako bitovΘ p°φznaky,
Jde o hodnoty v²ΦtovΘho typu ctype_base::mask, pojmenovanΘ space, print, cntrl,
upper, lower, digit, punct, xdigit, alpha, alnum, graph. Po °ad∞ odpovφdajφ
bφl²m znak∙m, tisknuteln²m znak∙m, °φdicφm znak∙m, velk²m pφsmen∙m, mal²m
pφsmen∙m, interpunkΦnφm znamΘnk∙m, Üestnßctkov²m Φφslicφm, pφsmen∙m, alfanumerick²m
znak∙m a grafick²m znak∙m.
Ve skuteΦnosti se ale funkce is() pou₧φvß pom∞rn∞ mßlo, v hlaviΦkovΘm souboru
locale jsou toti₧ definovßny Üablony funkcφ s pov∞dom²mi jmΘny isspace(),
isprint(), iscntrl(), isupper(), islower(), isalpha(), isdigit(), ispunct(),
isxdigit(), isalnum() a isgraph(), kterΘ pokr²vajφ p°evß₧nou v∞tÜinu b∞₧n²ch
situacφ. Deklarace vÜech t∞chto funkcφ jsou stejnΘ, proto postaΦφ, kdy₧ si
uvedeme jen jednu z nich. V nßsledujφcφ Üablon∞ musφ b²t charT znakov² typ,
tedy bu∩ char nebo wchar_t:
template<class charT> bool isspace (charT c, const locale& loc);
Od stejnojmenn²ch funkcφ se standardnφ knihovny jazyka C se na prvnφ pohled liÜφ vlastn∞ jen tφm, ₧e majφ navφc jako druh² parametr instanci t°φdy locale. (Na rozdφl od analogick²ch funkcφ ze standardnφ knihovny jazyka C se tedy ne°φdφ globßln∞ nastavenou hodnotou nßrodnφho prost°edφ, ale pou₧φvajφ nßrodnφ prost°edφ, kterΘ jim p°edßme).
Upozorn∞nφ
Ukßzky k≤du v tomto Φlßnku jsme, podobn∞ jako v p°edchozφm dφlu, odladili
ve Visual C++ .NET. V mnoh²ch jin²ch p°ekladaΦφch pod Windows nejspφÜ nebudou
fungovat nebo budou fungovat jen omezen∞, nebo¥ problematice nßrodnφho prost°edφ
v∞nujφ tv∙rci p°ekladaΦ∙ pozornost a₧ na jednom z poslednφch mφstech.
Pokud budete pou₧φvat jinΘ prost°edφ ne₧ Windows, mohou se liÜit °et∞zce,
kterΘ urΦujφ jmΘna nßrodnφch prost°edφ. Ty je nutno hledat v dokumentaci (a
zpravidla se v nφ nehledajφ lehce).
P°φÜt∞ se podφvßme na abecednφ °azenφ a formßtovßnφ Φφsel.
Miroslav Virius