Internacionalizace a lokalizace v C++

╙dy ₧lutΘho kon∞ 2.

╙dy ₧lutΘho kon∞ podruhΘ: Malß a velkß pφsmena

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.

NeformßtovanΘ proudy

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.

T°φda locale

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".

Znaky a jejich klasifikace

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∞

P°φÜt∞ se podφvßme na abecednφ °azenφ a formßtovßnφ Φφsel.

Miroslav Virius