home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 March / Chip_2001-03_cd1.bin / obsahy / Chip_txt / TXT / 131-133.TXT < prev    next >
Text File  |  2001-02-03  |  15KB  |  186 lines

  1. Programovßnφ v prost°edφ Cocoa (11)
  2. T°φdy Foundation Kitu II.
  3. Minule jsme se zaΦali na konkrΘtnφch p°φkladech seznamovat s pou₧itφm nejb∞₧n∞jÜφch t°φd Foundation Kitu. Dnes si ukß₧eme n∞kolik dalÜφch p°φklad∙.
  4.  
  5. NS(Mutable)Dictionary
  6. HaÜovacφ tabulky, je₧ Foundation Kit nabφzφ prost°ednictvφm t°φd NSDictionary a NSMutableDictionary, pat°φ mezi neju₧φvan∞jÜφ slu₧by v∙bec: jsou toti₧ nesmφrn∞ pohodlnΘ a flexibilnφ. P°ipome≥me si minul² p°φklad, ve kterΘm jsme vyu₧ili NSCountedSet pro frekvenΦnφ anal²zu danΘho textu. Dnes si ukß₧eme analogick² p°φklad, v n∞m₧ nßm poslou₧φ t°φda NSMutableDictionary pro vytvo°enφ rejst°φku. Podobn∞ jako minule si zßrove≥ ukß₧eme funkci a slu₧by n∞kolika dalÜφch t°φd û p°φkladem bude kompletnφ program.
  7. NßÜ progrßmek vytvo°φ kompletnφ index vÜech soubor∙ HTML v zadanΘ slo₧ce a ve vÜech slo₧kßch vno°en²ch û pro ka₧dΘ slovo ud∞lß seznam vÜech dokument∙, ve kter²ch je toto slovo vyu₧ito. Program bude o n∞co luxusn∞jÜφ ne₧ minul² p°φklad; obsahuje t°eba dek≤dovßnφ argument∙ p°φkazovΘho °ßdku. Nejprve se podφvßme na zdrojov² text (kompletnφ program zabere mΘn∞ ne₧ 60 °ßdk∙), a pak si n∞kterΘ p°φkazy vysv∞tlφme podrobn∞ji:
  8. int main (int argc, const char *argv[])
  9. {
  10.  NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
  11.  NSCharacterSet *wordDelims=[NSCharacterSet characterSetWithCharactersInString:@" ,.?!;:\"\'/-()0123456789*#@\\\r\n"];
  12.  NSFileManager *fm=[NSFileManager defaultManager];
  13.  NSUserDefaults *df=[NSUserDefaults standardUserDefaults];
  14.  NSString *ifolder=nil,*ofile=nil;
  15.  NSMutableDictionary *index=[NSMutableDictionary dictionary];
  16.  NSMutableString *output=[NSMutableString string];
  17.  int minword=3,totalf=0,totalw=0,totalb=0;
  18.  id en,o;
  19.  
  20.  ifolder=[df objectForKey:@"input"]; // *1*
  21.  ofile=[df objectForKey:@"output"];
  22.  if (o=[df objectForKey:@"minword"]) minword=[o intValue];
  23.  if (!ifolder || !ofile) {
  24.  printf("IndexHTML [-minword <min.word size>] -input <input folder> -output <output file>\n");
  25.  exit(0);
  26.  }
  27.  
  28.  for (en=[fm enumeratorAtPath:ifolder];o=[en nextObject];) if ([[o pathExtension] isEqual:@"html"]) { // *2*
  29.  NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
  30.  NS_DURING // *3*
  31.  NSString *fname=[o lastPathComponent];
  32.  NSAttributedString *htmlContents=[[[NSAttributedString alloc] initWithPath:[ifolder stringByAppendingPathComponent:o] documentAttributes:NULL] autorelease]; // *4*
  33.  NSString *contents=[htmlContents string];
  34.  NSScanner *sc=[NSScanner scannerWithString:contents];
  35.  
  36.  int len=[[en fileAttributes] fileSize],current=totalw,currentItems=[index count];
  37.  NSLog(@"Scanning \"%@\" (%d bytes)...",fname,len);
  38.  totalf++; totalb+=len;
  39.  while (![sc isAtEnd]) {
  40.  NSString *word;
  41.  [sc scanCharactersFromSet:wordDelims intoString:NULL]; // skip any delimiters
  42.  if ([sc scanUpToCharactersFromSet:wordDelims intoString:&word] && [word length]>minword) {
  43.  NSMutableSet *s=[index objectForKey:word]; // *5*
  44.  if (!s) [index setObject:s=[NSMutableSet set] forKey:word];
  45.  [s addObject:fname];
  46.  totalw++;
  47.  }
  48.  }
  49.  NSLog(@"...%d words (%d new items)",totalw-current,[index count]-currentItems);
  50.  NS_HANDLER
  51.  NSLog(@"*** aborted since %@",[localException reason]);
  52.  NS_ENDHANDLER
  53.  [pool release]; 
  54.  }
  55.  NSLog(@"Scanned %d files (%d words, %d bytes)",totalf,totalw,totalb);
  56.  for (en=[[[index allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator];o=[en nextObject];) // *6*
  57.  [output appendFormat:@"%@: %@\n",o,[[index objectForKey:o] allObjects]];
  58.  if (![output writeToFile:ofile atomically:NO]) NSLog(@"!!! Can't write %@",ofile);
  59.  NSLog(@"Index successfully written to \"%@\"",ofile);
  60.  
  61.  [pool release];
  62.  exit(0);
  63.  return 0;
  64. }
  65. Na °ßdku s komentß°em *1* zaΦφnß zpracovßnφ vstupnφch argument∙. Bylo by zbyteΦnΘ na tomto mφst∞ podrobn∞ popisovat slu₧by t°φdy NSUserDefaults. Za struΦnou zmφnku vÜak stojφ to, ₧e krom∞ dek≤dovßnφ p°φkazovΘho °ßdku zajiÜ¥uje p°φstup k velmi obecnΘ databßzi u₧ivatelsk²ch p°edvoleb. Bez dalÜφho programovßnφ mßme tedy k dispozici nejen p°φkazov² °ßdek, ale m∙₧eme i fixovat standardnφ hodnoty argument∙ v tΘto databßzi a nßÜ program je automaticky vyu₧ije.
  66. Hlavnφ d∙vod, proΦ se zde t°φdou NSUserDefaults v∙bec zab²vßme, vÜak je ilustrace jednΘ z velmi p°φjemn²ch vlastnostφ API Cocoa, kterou je d∙slednΘ vyu₧φvßnφ polymorfismu. VÜimn∞te si, ₧e pro zφskßnφ hodnoty po₧adovanΘho argumentu z objektu NSUserDefaults slou₧φ p°esn∞ stejnß zprßva (objectForKey:), jako pro zφskßnφ hodnoty po₧adovanΘho klφΦe z objektu NSDictionary (na °ßdku s komentß°em *5* nebo na °ßdku za komentß°em *6*). To p°inßÜφ dv∞ obrovskΘ v²hody:
  67. * doba pot°ebnß k nauΦenφ se API Cocoa je mnohem kratÜφ ne₧ doba pot°ebnß pro nauΦenφ se jin²ch û i daleko chudÜφch û API;
  68. * Φasto se hodφ i p°φmΘ vyu₧itφ polymorfismu pro v∞tÜφ flexibilitu k≤du.
  69. Obsah °ßdku *2* je vÜe, co pot°ebujeme pro vyhledßnφ vÜech soubor∙, je₧ budeme indexovat. Obsah p°φkazu for zajistφ prochßzenφ vÜech soubor∙ uvnit° slo₧ky ifolder a slo₧ek vno°en²ch, a nßsledujφcφ p°φkaz if z nich vybere jen soubory HTML.
  70. Makra NS_DURING (*3*), NS_HANDLER a NS_ENDHANDLER jsou v Cocoa standardnφ obsluhou v²jimek. FunkΦn∞ tedy odpovφdajφ kombinaci try/catch z C++, jsou vÜak mnohem efektivn∞jÜφ. V naÜem jednoduchΘm progrßmku slou₧φ k tomu, aby û pokud p°i zpracovßnφ n∞kterΘho souboru dojde k v²jimce û nebyl program ukonΦen, ale aby indexovßnφ pokraΦovalo dalÜφm souborem.
  71. Na °ßdku *4* pou₧φvßme t°φdu NSAttributedString, kterß dokß₧e korektn∞ naΦφst HTML soubor a vrßtit jeho textov² obsah jako standardnφ string (toho vyu₧ijeme hned na nßsledujφcφm °ßdku). Pro vyhledßnφ jednotliv²ch slov v jeho obsahu pou₧ijeme NSScanner p°esn∞ stejn∞ jako v minulΘm p°φkladu.
  72. T°i °ßdky od komentß°e *5* obsahujφ vlastnφ indexovßnφ. Jeho logika je jednoduchß: nejprve z objektu NSMutableDictionary (kter² je ulo₧en v prom∞nnΘ index) zφskßme objekt, jeho₧ klφΦem je danΘ slovo. Pokud takov² objekt dosud neexistuje (proto₧e jde o prvnφ v²skyt danΘho slova), vytvo°φme jej (jako prßzdn² NSMutableSet) a ihned jej û s dan²m slovem jako klφΦem û vlo₧φme do indexu (to je obsahem druhΘho °ßdku). T°etφ °ßdek je trivißlnφ, prost∞ do objektu NSMutableSet vlo₧φ jmΘno souboru, ve kterΘm jsme danΘ slovo nalezli.
  73. Je snad z°ejmΘ, ₧e tφmto zp∙sobem nakonec v prom∞nnΘ index vybudujeme skuteΦn² index, v n∞m₧ klφΦi budou jednotlivß slova a odpovφdajφcφmi hodnotami mno₧iny obsahujφcφ jmΘna vÜech dokument∙, ve kter²ch se danΘ slovo vyskytuje. Mimochodem, mal² kvφz pro pozornΘ Φtenß°e: proΦ jsme pro seznamy soubor∙ pou₧ili t°φdu NSMutableSet a ne t°φdu NSMutableArray?
  74. Mohli bychom sice index vypsat p°φmo (p°φkazem [index writeToFile:ofile...]), jen₧e pak by slova nebyla set°φd∞nß podle abecedy. Proto vytvo°φme NSMutableString, do kterΘho na pouh²ch dvou °ßdcφch (*6* a nßsledujφcφ) vygenerujeme v²stupnφ seznam slov a odpovφdajφcφch soubor∙ v abecednφm po°adφ. Srovnejme p°φkaz pro t°φd∞nφ (sortedArrayUsingSelector:) s obdobn²m p°φkazem z minulΘho p°φkladu  ûtentokrßt vyu₧φvßme dynamickΘho systΘmu Objective C a prost∞ uvedeme zprßvu, jejφ₧ pomocφ se majφ p°i t°φd∞nφ slova porovnßvat (je jφ standardnφ zprßva compare:, kterou v lze API Cocoa srovnat libovolnΘ dva objekty, nad nimi₧ je definovßna relace menÜφ/v∞tÜφ).
  75. Jak je vid∞t na v²pisu v HTML podob∞ Φlßnku na Chip CD, pro kompletnφ indexovßnφ cca t°φ megabajt∙ HTML textu staΦily necelΘ dv∞ minuty. V²sledek (samoz°ejm∞ jen z malΘ Φßsti) pak vidφme na obrßzku.
  76.  
  77. NS(Mutable)String
  78. ╪adu p°φklad∙ prßce s objekty t∞chto t°φd jsme ji₧ vid∞li. V minulΘm p°φkladu jsme pomocφ t°φdy NSMutableString generovali v²stupnφ data, NSString byl pou₧it pro naΦφtßnφ vstupnφch soubor∙ i pro ·daje z argument∙ p°φkazovΘho °ßdku... V tomto odstavci si ukß₧eme pßr dalÜφch slu₧eb podrobn∞ji.
  79. // mo₧nostφ vytvo°it °et∞zec je °ada:
  80. id a=@"Toto je statick² objekt t°φdy NSString";
  81. char *xx="M∙₧eme samoz°ejm∞ vyu₧φt i prom∞nnΘ \"char *\"";
  82. id b=[NSMutableString stringWithCString:xx];
  83. char *yy="I\0kdy₧\0obsahujφ\0nulovΘ\0znaky\0!"
  84. id c=[NSString stringWithCString:yy length:30];
  85. // °et∞zec lze naΦφst p°φmo ze souboru:
  86. id d=[NSString stringWithContentsOfFile:@"/tmp/something.text"];
  87. // nebo vytvo°it pomocφ "printf"-formßtu:
  88. id e=[NSString stringWithFormat:@"total:%d, %s, %@, %5.3f\n",1,"ahoj",a,3.14159];
  89. // m∙₧eme si takΘ vy₧ßdat automatick² "p°eklad" prost°ednictvφm
  90. // p°ekladovΘ tabulky v aktivnφm adresß°i lproj (podrobnosti viz NSBundle):
  91. id f=[NSString localizedStringWithFormat:@"%d files",ff];
  92. // v²Üe uveden² p°φklad vytvo°φ nap°. p°i aktivnφ ΦeÜtin∞ a
  93. // odpovφdajφcφ polo₧ce v tabulce string∙ °et∞zec
  94. // @"15 soubor∙".
  95. ╪et∞zce Φasto generujφ i jinΘ t°φdy (nap°. libovoln² objekt OpenStepu vrßtφ 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φ vytvo°it °et∞zec dan² kombinacφ vÜech obsa₧en²ch prvk∙ a libovolnΘho odd∞lovaΦe:
  96. NSArray *a=[NSArray arrayWithObjects:@"A",@"B",@"C",nil];
  97. NSLog(@"%@",[a componentsJoinedByString:@" nebo "]);
  98. // vypφÜe "A nebo B nebo C"
  99. NSLog(@"DOS path: %@",[a componentsJoinedByString:@"\\"]);
  100. // vypφÜe "DOS path: A\B\C"
  101. Zßkladnφ slu₧by pro prßci s °et∞zci samoz°ejm∞ zahrnujφ nejr∙zn∞jÜφ kombinace a rozklady. Uka₧me si n∞kolik p°φklad∙, vyu₧φvajφcφch °et∞zce a û f vytvo°enΘ v prvnφm p°φkladu:
  102. NSLog(@"%@",[f stringByAppendingString:f]);
  103. // vypφÜe "15 soubor∙15 soubor∙"
  104. NSLog(@"%@",[f stringByAppendingFormat:@" je prost∞ %@",f]);
  105. // vypφÜe "15 soubor∙ je prost∞ 15 soubor∙"
  106. NSArray a=[e componentsSeparatedByString:@", "];
  107. // vytvo°φ pole @"total:1",@"ahoj",@"Toto ... NSString",@"3.142"
  108. NSLog(@"%@",[c substringFromIndex:29]);
  109. // vypφÜe "!"
  110. [b deleteCharactersInRange:(NSRange){8,8}];
  111. // b obsahuje "M∙₧eme prom∞nnΘ "char *""
  112. [b appendString:@" pou₧φt"];
  113. // b obsahuje "M∙₧eme prom∞nnΘ "char *" pou₧φt"
  114. [b insertString:@"snadno " atIndex:7];
  115. // b obsahuje "M∙₧eme snadno prom∞nnΘ "char *" pou₧φt"
  116. Pro oznaΦovßnφ Φßstφ °et∞zc∙ a pro vyhledßvßnφ slou₧φ typ NSRange û obyΦejnß struktura, obsahujφcφ dv∞ Φφsla, pozici a dΘlku:
  117. NSLog(@"%@",[a substringFromRange:(NSRange){8,8}]);
  118. // vypφÜe "statick²"
  119. NSRange r=[a rangeOfString:@"je"];
  120. NSLog(@"\"je\" je na pozici %d, p°ed nφm je \"%@\"",r.location,[a substringToIndex:r.location]);
  121. // vypφÜe ""je" je na pozici 5, p°ed nφm je "Toto ""
  122. 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. Omezit lze takΘ rozsah prohledßvanΘho °et∞zce. Pro zßkladnφ a nejΦast∞ji pot°ebnß porovnßvßnφ jsou samoz°ejm∞ k dispozici hotovΘ metody:
  123. if ([a hasPrefix:@"Toto"]) // platφ
  124. if ([c hasSuffix:@"!"]) // platφ
  125. if ([d isEqual:e]) // neplatφ
  126. 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:
  127. NSLog(@"%@",[a commonPrefixWithString:e options:NSCaseInsensitiveSearch]);
  128. // vypφÜe "Tot"
  129. Prozatφm jsme se v∙bec nezab²vali vnit°nφm k≤dovßnφm °et∞zce. To je v objektovΘm prost°edφ samoz°ejmΘ û do vnit°nφho k≤dovßnφ nßm p°ece nic nenφ a zajφmajφ nßs pouze zprßvy, kterΘ je objekt schopen zpracovat. K≤dovßnφ vÜak m∙₧e b²t zajφmavΘ ze dvou d∙vod∙ û p°edn∞ z pou₧itΘho k≤dovßnφ vypl²vß rozsah znak∙, kterΘ °et∞zec m∙₧e obsahovat; druh²m d∙vodem m∙₧e b²t programovß volba k≤dovßnφ pro konkrΘtnφ ·Φel û nap°φklad pro uklßdßnφ do souboru bude asi nejv²hodn∞jÜφ k≤dovßnφ, kterΘ zabere nejmΘn∞ mφsta.
  130. Zßkladnφm k≤dovßnφm pro t°φdu NSString je Unicode v tom smyslu, ₧e °et∞zce reprezentovanΘ objekty t°φdy NSString mohou obsahovat libovolnΘ znaky Unicode, 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 dalÜφ k≤dovßnφ mßme k dispozici p°eddefinovan² typ NSStringEncoding, kter² reprezentuje k≤dovßnφ, a nßsledujφcφ metody:
  131. // vypφÜeme vÜechna k≤dovßnφ, kterß jsou k dispozici
  132. NSStringEncoding *en=[NSString availableStringEncodings];
  133. while (en) NSLog(@"%@",[NSString localizedNameOfStringEncoding:en++]);
  134. // zjistφme, kterΘ k≤dovßnφ odpovφdß b∞₧n²m CΘΦkov²m °et∞zc∙m
  135. en=[NSString defaultCStringEncoding];
  136. // ov∞°φme, lze-li do n∞j p°evΘst string d bez ztrßty informace
  137. if ([d canBeConvertedToEncoding:en])
  138.  // a pokud ano, p°evedeme jej:
  139.  newd=[d dataUsingEncoding:en];
  140. else {
  141.  // ne-li, vyhledßme nej·sporn∞jÜφ bezztrßtovΘ k≤dovßnφ
  142.  en=[d smallestEncoding];
  143.  // a pou₧ijeme jej:
  144.  newd=[d dataUsingEncoding:en];
  145. }
  146. // pro pou₧itφ ve standardnφm C jsou k dispozici
  147. // pomocnΘ p°evßd∞cφ metody
  148. void std_func(int i,float f,char *c)
  149. {
  150.  printf("%d, %e, %s",i,f,c);
  151. }
  152. NSString *s=@"3.141592654";
  153. std_func([s intValue],[s floatValue],[s cString]);
  154. // vypφÜe "3, 3.141593e+00, 3.141592654"
  155. Tφm samoz°ejm∞ mo₧nosti NSString∙ zdaleka nekonΦφ; na ·rovni tohoto Φlßnku by vÜak nem∞lo smysl podrobn∞ popisovat vÜechny metody. Proto se ji₧ seznßmφme jen se samostatnou skupinou slu₧eb, kterΘ zajiÜ¥ujφ korektnφ prßci s nßzvy soubor∙ a adresß°∙ û samoz°ejm∞ v konkrΘtnφm hostitelskΘm operaΦnφm systΘmu, tak₧e programßtor se nemusφ starat o to, odd∞lujφ-li se jednotlivΘ polo₧ky lomφtkem, obrßcen²m lomφtkem nebo t°eba dvojteΦkou:
  156. // p°φklady jsou z Unixu:
  157. NSString *p=@"/Users/oc/Apps/Test.app";
  158. NSLog(@"%@",[p lastPathComponent]);
  159. // vypφÜe "Test.app"
  160. NSLog(@"%@",[p pathExtension]);
  161. // vypφÜe "app"
  162. NSLog(@"%@",[p stringByAppendingPathComponent:@"Czech.lproj"]);
  163. // vypφÜe "/Users/oc/Apps/Test.app/Czech.lproj"
  164. NSLog(@"%@",[p stringByDeletingLastPathComponent]);
  165. // vypφÜe "/Users/oc/Apps"
  166. NSLog(@"%@",[p stringByAbbreviatingWithTildeInPath]);
  167. // pro u₧ivatele "oc" vypφÜe "~/Apps/Test.app"
  168. NSString *p=@"~/Apps/Test.app";
  169. NSLog(@"%@",[p stringByExpandingTildeInPath]);
  170. // pro u₧ivatele Steve vypφÜe "/Users/Steve/Apps/Test.app"
  171. NSString *p=@"/oc/RootTemp";
  172. NSLog(@"%@",[p stringByResolvingSymlinksInPath]);
  173. // u m∞ vypφÜe "/private/tmp", proto₧e
  174. // /oc/RootTemp je link ("zßstupce") slo₧ky /private/tmp
  175. NSString *p=@"~/../oc/./RootTemp/./TmpFile";
  176. NSLog(@"%@",[p stringByStandardizingPath]);
  177. // vypφÜe "/Users/oc/RootTemp/TmpFile"
  178.  
  179. Shrnutφ
  180. Vid∞li jsme p°φklady pou₧itφ dvou nesmφrn∞ Φasto vyu₧φvan²ch t°φd û NS(Mutable)Dictionary a NS(Mutable)String. Bez podrobn∞jÜφho v²kladu jsme se seznßmili s °adou dalÜφch t°φd API Cocoa, mj. s NSUserDefaults nebo NSFileManager, a ukßzali jsme si jin² p°φklad pou₧itφ t°φdy NSMutableSet. V p°φÜtφm dφlu se podφvßme na dalÜφ zajφmavΘ t°φdy Foundation Kitu.
  181.  
  182. Ond°ej ╚ada
  183.     Chyba! Neznßm² argument p°epφnaΦe./7
  184.  
  185.  
  186.