Nastal čas na kakao - Textové řetězce: NS(Mutable)String - MujMAC.cz - Apple, Mac OS X, Apple iPod

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:

Seriály

Více seriálů



Informace

Nastal čas na kakao - Textové řetězce: NS(Mutable)String

25. února 2005, 00.00 | Minule jsme si začali ukazovat, jak se pracuje s konkrétními objekty z knihovny Foundation Kit – seznámili jsme se především s beztypovými kontejnery NS(Mutable)Array, NS(Mutable/Counted)Set a NS(Mutable)Dictionary. Dnes se podíváme blíže na snad nejpoužívanější třídu vůbec – na třídu NS(Mutable)String.

Minule jsme si začali ukazovat, jak se pracuje s konkrétními objekty z knihovny Foundation Kit – seznámili jsme se především s beztypovými kontejnery NS(Mutable)Array, NS(Mutable/Counted)Set a NS(Mutable)Dictionary. Dnes se podíváme blíže na snad nejpoužívanější třídu vůbec – na třídu NS(Mutable)String.

Třída NSString representuje zcela obecný textový řetězec, složený z libovolných znaků; jak je v Cocoa u základních objektů zvykem, objekty třídy NSString jsou neměnné, máme však k dispozici její podtřídu NSMutableString, jež nabízí textové řetězce, jejichž obsah můžeme měnit podle potřeby.

Z hlediska programátorského rozhraní můžeme všechny textové řetězce považovat za unicodové (implementace samozřejmě může vypadat jinak, ale o tom je právě objektový systém – konkrétní implementace je nám lhostejná, pokud třídy a jejich instance korektně dodržují API). Žádná explicitní omezení pro textové řetězce v Cocoa samozřejmě nejsou: řetězec může být libovolně dlouhý, jeho obsahem může být naprosto cokoli včetně znaků, jejichž číslo ve znakové tabulce je 0, a tak dále.

Řadu příkladů práce s textovými řetězci jsme již viděli: minule jsme kupříkladu jsme pomocí třídy NSMutableString generovali výstupní data, NSString pak byl mnohokrát použit mj. pro načítání vstupních souborů i pro údaje z argumentů příkazového řádku... Dnes si ukážeme bohatství služeb, jež Foundation Kit pro textové řetězce nabízí, trochu podrobněji.

Vytváření textových řetězců

Nejprve se podíváme na nejběžnější způsoby, jimiž v Kakau instance tříd NSString a NSMutableString vytváříme; ukážeme si je přímo na konkrétních příkladech:

id a=@"Toto je statický objekt třídy NSString";
char *xx="Můžeme samozřejmě využít i proměnné \"char *\"";
id b=[NSMutableString stringWithUTF8String:xx];
char *yy="I\0když\0obsahují\0nulové\0znaky\0!"
id c=[NSString stringWithUTF8String:yy length:30];

Za samostatnou zmínku možná stojí služba stringWithUTF8String: ve starších versích systému se na jejím místě užívalo služby stringWithCString:, její nevýhodou však bylo to, že korektně pracovala pouze se znaky z dolní poloviny tabulky ASCII. Novější varianta předpokládá kódování znaků v UTF8; to je pro znaky z dolní poloviny tabulky ASCII samozřejmě totéž, lze však pracovat i s libovolnými národními či jinými znaky z celé tabulky Unicode. Služba stringWithCString: se proto považuje za zastaralou, a v nových programech bychom jí už neměli využívat.

Podobně tomu je se službou stringWithContentsOfFile: (již jsme pro jednoduchost využili v minulém příkladu) – není-li soubor zrovna ve formátu UTF s úvodní značkou (kterou lze automaticky detektovat), může nastat problém s kódováním národních znaků. Pokud však jde o UTF nebo víme-li, že soubor obsahuje text nevyužívající speciálních znaků, služba je k dispozici – jak pro lokální soubor, tak i pro vzdálený soubor, k němuž přistupujeme prostřednictvím Internetu:

id d=[NSString stringWithContentsOfFile:@"/tmp/something.text"];
id e=[NSString stringWithContentsOfURL:
       [NSURL URLWithString:@"http://www.ocs.cz"]];

Některé další šikovné služby pro vytvoření nového objektu třídy NSString zahrnují využití formátu typu printf (rozšířeného o kombinaci %@, jež vypíše obsah libovolného objektu) či získání lokalizovaného řetězce s automatickým využitím překladových tabulek pro aktuální jazyk (jsou-li samozřejmě součástí aplikace):

id f=[NSString stringWithFormat:@"total:%d, %s, %@, %5.3f\n",
       1,"ahoj",a,3.14159];
id g=[NSString localizedStringWithFormat:@"%d files",ff];
// poslední příklad vytvoří např. při aktivní češtině a
// odpovídající položce v tabulce řetězec "15 souborů".

Všechny možnosti jsou díky dědičnosti samozřejmě plně k dispozici i ve třídě NSMutableString; v ní navíc zřejmě dost často využijeme i triviální zprávu string:

id s=[NSMutableString string];

jež vytvoří prázdný textový řetězec, do nějž můžeme přidat další znaky (metoda string je k dispozici i ve třídě NSString, ovšem tam nemá v praxi valný význam – chceme-li již vytvořit prázdný neměnný textový řetězec, je lepší použít konstantu @"").

Řetězce často generují i jiné třídy – např. libovolný objekt Cocoa vrátí instanci třídy NSString, obsahující jeho popis, na základě zprávy description. Jiným hezkým příkladem je NSArray – objekty této třídy umějí vygenerovat řetězec, daný kombinací všech obsažených prvků a libovolného oddělovače:

NSArray *a=[NSArray arrayWithObjects:@"A",@"B",@"C",nil];
NSLog(@"%@",[a componentsJoinedByString:@" nebo "]);
// vypíše "A nebo B nebo C"
NSLog(@"DOS path: %@",[a componentsJoinedByString:@"\\"]);
// vypíše "DOS path: A\B\C"

Práce se jmény souborů

Poslední příklad je samozřejmě netypický: DOSovské cesty s jejich šílenými obrácenými lomítky nikoho nezajímají; zajímavější obvykle je práce se jmény souborů v korektním lokálním formátu – a na to nabízí Foundation Kit řadu obecných služeb. Nejde jen o to, že jsou pohodlné; další výhoda je i přenositelnost: užijeme-li týchž služeb v GNUStepu pod Windows, budou korektně generovat cesty podle tamních standardů.

Nejběžnější služby pro práci se jmény souborů by mohly být tyto – předpokládáme samozřejmě běh v Mac OS X, a proto užíváme pro explicitní zápis cesty unixové standardy:

NSString *p=@"/Users/oc/Apps/Test.app";
NSLog(@"%@",[p lastPathComponent]);
// vypíše "Test.app"
NSLog(@"%@",[p pathExtension]);
// vypíše "app"
NSLog(@"%@",[p stringByAppendingPathComponent:@"Czech.lproj"]);
// vypíše "/Users/oc/Apps/Test.app/Czech.lproj"
NSLog(@"%@",[p stringByDeletingLastPathComponent]);
// vypíše "/Users/oc/Apps"
NSLog(@"%@",[p stringByAbbreviatingWithTildeInPath]);
// pro uživatele "oc" vypíše "~/Apps/Test.app"
NSString *p=@"~/Apps/Test.app";
NSLog(@"%@",[p stringByExpandingTildeInPath]);
// pro uživatele Steve vypíše "/Users/Steve/Apps/Test.app"
NSString *p=@"/oc/RootTemp";
NSLog(@"%@",[p stringByResolvingSymlinksInPath]);
// u mě vypíše "/private/tmp", protože
// /oc/RootTemp je link ("zástupce") složky /private/tmp
NSString *p=@"~/../oc/./RootTemp/./TmpFile";
NSLog(@"%@",[p stringByStandardizingPath]);
// vypíše "/Users/oc/RootTemp/TmpFile"

Běžné služby

Základní služby pro práci s řetězci samozřejmě zahrnují zjištění jeho délky zprávou length, vynětí požadovaného znaku zprávou characterAtIndex:, převody na standardní typy jazyka C – zprávy intValue, floatValue, doubleValue – a pak nejrůznější kombinace a rozklady – ukažme si několik příkladů, využívajících řetězce a-g, vytvořené v prvním příkladu:

NSLog(@"%@",[g stringByAppendingString:g]);
// vypíše "15 souborů15 souborů"
NSLog(@"%@",[g stringByAppendingFormat:@" je prostě %@",g]);
// vypíše "15 souborů je prostě 15 souborů"
NSArray a=[e componentsSeparatedByString:@", "];
// vytvoří pole @"total:1",@"ahoj",@"Toto ... NSString",@"3.142"
NSLog(@"%@",[c substringFromIndex:29]);
// vypíše "!"
[b deleteCharactersInRange:(NSRange){8,8}];
// b obsahuje "Můžeme proměnné "char *""
[b appendString:@" použít"];
// b obsahuje "Můžeme proměnné "char *" použít"
[b insertString:@"snadno " atIndex:7];
// b obsahuje "Můžeme snadno proměnné "char *" použít"

Pro označování částí řetězců a pro vyhledávání slouží typ NSRange – již jsme se s ním zběžně setkali v minulém dílu, je to docela obyčejná struktura, obsahující dvě čísla, pozici a délku:

NSLog(@"%@",[a substringFromRange:NSMakeRange(8,8)]);
// vypíše "statický"
NSRange r=[a rangeOfString:@"je"];
NSLog(@"\"je\" je na pozici %d, před ním je \"%@\"",
  r.location,[a substringToIndex:r.location]);
// vypíše ""je" je na pozici 5, před ním je "Toto ""

Prostřednictvím přepínačů si můžeme vyžádat i hledání odzadu, hledání bez ohledu na velikost písmen nebo hledání pouze od zadané pozice; rozsah prohledávaného řetězce také můžeme omezit. Pro základní a nejčastěji potřebná porovnávání jsou samozřejmě k dispozici hotové metody:

if ([a hasPrefix:@"Toto"]) ... // platí
if ([c hasSuffix:@"!"]) ... // platí
if ([d isEqual:e]) ... // neplatí

Zajímavá je i možnost vyžádat si nejdelší společný prefix dvou řetězců; i zde máme možnost volit zda se má nebo nemá brát v úvahu velikost písmen:

NSLog(@"%@",[a commonPrefixWithString:e
  options:NSCaseInsensitiveSearch]);
// vypíše "Tot"

Kódování znaků

Prozatím jsme se příliš nezabývali vnitřním kódováním řetězce; jen jsme si řekli, že – jak je ostatně v objektovém prostředí samozřejmé – nám do vnitřního kódování nic není, a zajímají nás pouze zprávy, které je objekt schopen zpracovat. Základní kódovou tabulkou pro třídu NSString je standardní tabulka Unicode v tom smyslu, že řetězce reprezentované objekty třídy NSString mohou obsahovat libovolné znaky z této tabulky, a že metody pro přímý přístup do řetězce (např. metoda characterAtIndex:) operují právě s šestnáctibitovými kódy znaků podle standardu Unicode. Pro práci s dalšími kódovými tabulkami – jež můžeme potřebovat třeba při importu či exportu souborů z a do jiných prostředí – máme k dispozici předdefinovaný typ NSStringEncoding, který reprezentuje kódování, a následující metody:

// vypíšeme všechny kódové tabulky, jež jsou k dispozici
NSStringEncoding *en=[NSString availableStringEncodings];
while (en) NSLog(@"%@",[NSString localizedNameOfStringEncoding:en++]);
// zjistíme, které kódování odpovídá běžným Céčkovým řetězcům
en=[NSString defaultCStringEncoding];
// ověříme, lze-li do něj převést string d bez ztráty informace
if ([d canBeConvertedToEncoding:en])
  // a ano-li, převedeme jej:
  newd=[d dataUsingEncoding:en];
else {
  // ne-li, vyhledáme nejúspornější bezztrátové kódování
  en=[d smallestEncoding];
  // a použijeme jej:
  newd=[d dataUsingEncoding:en];
}

kde newd je instance třídy NSData – obecný stream bytů, jež můžeme kupříkladu zapsat do souboru pomocí standardní zprávy "[newd writeToFile:filename atomically:NO]".

Tím samozřejmě možnosti třídy NSString zdaleka nekončí; na úrovni tohoto článku by však nemělo smysl podrobně popisovat všechny metody. Jen se zmíníme o tom, že k dispozici jsou dokonce i takové věci, jako převody textového řetězce do (a z) korektního formátu pro URL (stringByAddingPercentEscapesUsingEncoding: a stringByReplacingPercentEscapesUsingEncoding:) či dělení textů na slova a odstavce (getLineStart:end:contentsEnd:forRange:). To už jsou ale natolik specializované služby, že případné zájemce musíme odkázat na standardní dokumentaci...

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Začínáme s  

 

 

 

Nejčtenější články
Nejlépe hodnocené články
Apple kurzy

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: