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:
Začínáme s
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):
- Nastal čas na kakao...
- Tak nejdřív kakao ochutnáme...
- Programovací jazyk C: velmi, velmi stručně
- Objective C: to si vysvětlíme podrobněji
- Co jsme si o Objective C ještě neřekli...
- Nastal čas na kakao - Vznik a zánik objektů
- Nastal čas na kakao - Kopírování objektů
- Nastal čas na kakao - Skryté podtřídy
- Nastal čas na kakao - Základní služby objektů
- Nastal čas na kakao - Jak správně psát v Objective C
- Nastal čas na kakao - Jak správně importovat
- Nastal čas na kakao - Podtřídy, delegáti, vkládání, jak se to rýmuje?
- Nastal čas na kakao - Využití kategorií namísto dědičnosti
- Nastal čas na kakao - Vkládání objektů a přesměrování zpráv
- Nastal čas na kakao - Inicializace a rušení objektů
- Nastal čas na kakao - Metody initWith... a designovaný inicializátor
- Nastal čas na kakao - Inicializace: tipy a triky
- Nastal čas na kakao - Accesory: přístup k proměnným instancí
- Nastal čas na kakao - Šedá je teorie, zelený je strom života...
- Nastal čas na kakao - Více o XCode: inspektory
- Nastal čas na kakao - Aplikace RSS2: datový model
- Nastal čas na kakao - Aplikace RSS: implementace datového modelu
- Nastal čas na kakao - Aplikace RSS: parsování XML
- Nastal čas na kakao - Interface Builder a uživatelské rozhraní
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Druhý kontrolér a dokončení aplikace
- Nastal čas na kakao - Drobná vylepšení a zdokonalení...
- Nastal čas na kakao - Ladění
- Nastal čas na kakao - Třídy Foundation Kitu
- Nastal čas na kakao - Třídy Foundation Kitu (2)
- Nastal čas na kakao - Textové řetězce: NS(Mutable)String
- Nastal čas na kakao - Čísla, binární data a další...
- Nastal čas na kakao - Archivace objektů
- Nastal čas na kakao - Trocha magie, aneb distribuované objekty
- Nastal čas na kakao - Málem bychom zapomněli: NSAutoreleasePool
- Nastal čas na kakao - Zpracování výjimek: NSException
- Nastal čas na kakao - NSInvocation a černá magie
- Nastal čas na kakao - Kakao v Tygrovi
- Nastal čas na kakao - Notifikace: nepřímé předávání zpráv
- Nastal čas na kakao - NSUserDefaults
- Nastal čas na kakao - Co nového ve Foundation Kitu
- Nastal čas na kakao – s Intelem, s Intelem, jedeme do...
- Co nového v Xcode
- Začínáme s AppKitem
- Jak MVC v Kakau vypadá doopravdy?
- Jak MVC v Kakau vypadá doopravdy: dokončení
- Přehled tříd AppKitu
- Nastal čas na kakao - Přehled tříd AppKitu 2
- Přehled tříd AppKitu 3: zbývající třídy GUI
- Přehled tříd AppKitu 4: textový systém
- Nastal čas na kakao - Přehled tříd AppKitu 5: hlavně grafika
- Přehled tříd AppKitu 6: dokumentový systém
- Přehled tříd AppKitu 7: dokončení
- Pojmenované vlastnosti objektů
- Pojmenované vlastnosti objektů: implementace
- Pojmenované vlastnosti objektů: relace 1:N
- Pojmenované vlastnosti objektů: řazení jmen a agregační funkce
- Sledování změn objektů
- Sledování změn objektů – ukázka
- Sledování změn objektů – zdrojový kód
- Sledování změn objektů: kód modelu
- Sledování změn objektů: přímý přístup
- Kontroléry a vazby
- Vázání vazeb
- Další vazby s jednoduchým kontrolérem
- Implementace a použití převodu hodnot
- Validace hodnot
- Validace a chyby, a jedna hezká vazba...
- Práce s polem objektů
- Základní vazby NSArrayControlleru
- Převodníky, přepínače, placeholdery
- Mírná vylepšení v mezích zákona
- Objective C 2.0 - novinky z Leoparda
- NSTreeController
- Programování v Cocoa - Pár tipů a triků
- Programování v Cocoa - Základy kreslení
- Kterak nakreslit modrý obdélník...
- Další služby pro kreslení
- Obrázky a písmenka...
- Události a myš
- Lepší práce s myší
- Události klávesnice
- Input Management
- Příkazy a schránka
- Další události
- Táhni a padni
- Byli jsme na tahu; nyní padneme.
- Zvolme si, jak vhodit
- Drobnosti a chybičky
- Speciální případy tahání či házení
- Kterak táhnout něco, co neexistuje?
- Jak na sítě...
- NSURLConnection
- Safari za minutu
- Služby WebKitu
- Kakao v Leopardu
- Druhé Objective C
- Druhé Objective C: různé drobnosti
- Druhé Objective C: kategorie a protokoly
- Druhé Objective C: nový příkaz cyklu
- Druhé Objective C: atributy a accesory
- Druhé Objective C: atributy a accesory
- 64 je dvakrát 32
- Ubicumque dulce est, ibi et acidum invenies...
- Irbis: že prý žádné novinky?
- Blok sem, blok tam, nám už je to všechno jasné...
- Bloky jsou i v AppKitu
- Irbis a Foundation Kit
- Kde jsou má data?
- Kde jsou má data? V NSCache!
- Soubor, jméno, URL, jak se to rýmuje...
- Další podpora NSURL
- Zabíjení!
- A máme tady i...OS!
- Systémové prvky GUI
- Programování pro iOS 1. díl - Rozdíly mezi "i" a "Mac"
- Programování pro iOS - 2. Začínáme programovat
- Programování pro iOS - 3. základní ovladače a propojení GUI s kódem
- Programování pro iOS - 4. Varovná hlášení
- Programování pro iOS - 5. Rámce a jejich řídicí objekty
- Programování pro iOS - 6. Ukládání dat
- Programování pro iOS - 7. Správa paměti a starý restík
- Programování pro iOS - 8. Dokončení aplikace
- Programování pro iOS - 9. Jak dostat aplikaci do iPhone
- Programování pro iOS - 10. Instalace aplikace do cizího iPhone
- Programování pro iOS - 11. Jak dostat aplikaci do libovolného iPhone
- Programování pro iOS - 12. Touching!
- Programování pro iOS - 13. Kreslíme na iPhone
- Programování pro iOS - 14. Udělejme gesto
- Programování pro iOS - 15. Další gesta
- Programování pro iOS - 16. Více prstů, více zábavy
- Programování pro iOS - 17. Podpora standardních gest
- Programování pro iOS - 18. Recognizery v iOS
- Programování pro iOS - 19. Další standardní recognizery
- Programování pro iOS - 20. Co nového v iOSu
- Programování pro iOS - 21. "Multitasking"
- Programování pro iOS - 22. Nulla est honesta avaritia nisi temporis
- Programování pro iOS - 23. Jak se aktivovat, jsme-li v pozadí
- Programování pro iOS - 24. Zbývající drobnosti
- Programování pro iOS - 25. Řídicí objekty rámců
- Programování pro iOS - 26. Jak se dělá UIViewController
- Programování pro iOS - 27. Kde vzít rámce
- Programování pro iOS - 28. Základní služby
- Programování pro iOS - 29. Práce s rámci
- Programování pro iOS - 30. Rotace zařízení
- Programování pro iOS - 31. Správa paměti v rámcích
- Programování pro iOS - 32. Řídicí objekt pro tabulky
- Programování pro iOS - 33. Řídicí objekt pro strom
- Programování pro iOS - 33. Více o UINavigationControlleru
- Programování pro iOS - 35. Ještě jednou UINavigationController
- Programování pro iOS - 36. Po navigátoru taby
- Programování pro iOS - 37. Více o UITabBarControlleru
- Programování pro iOS - 38. Dokončení UITabBarControlleru
- Programování pro iOS - 39. UIPopoverController
- Programování pro iOS - 40. Další triky UIPopoverControlleru
- Programování pro iOS - 41. Zbývající služby UIPopoverControlleru
- Programování pro iOS - 42. UISplitViewController
- Programujeme v
iTunesXcode 4 - Programování pro iOS - 44. Předvolby Xcode 4
- Programování pro iOS - 45. Práce v Xcode 4
- Xcode 4: projekt a cíle
- Xcode 4: práce s cíli
- Xcode 4: Build Settings
- Xcode 4: Build Phases
- Xcode4: Build Phases podruhé
- Xcode 4: Co jsou to Build Rules?
- Xcode4: taje editoru
- Xcode4: automatické doplňování v editoru
- XIBy chyby
- Více o XIBech
- Editor XIBů
- Inspektory pro XIBy
- Vazby mezi objekty v XIBech
- Vazby mezi objekty v kódu
- Paletky Xcode pro XIBy
- Xcode 4: levý sloupec
- Xcode 4: okno Organizer
- Xcode 4: okno Organizer, část druhá
- Xcode 4: co je to Workspace?
- Xcode 4: základy schémat
- Xcode 4: akční schémata