☆文字列プログラミングガイド
これは、 文字列プログラミングガイド をiOS用に翻訳(意訳)したものである。 UnicodeやそのエンコードであるUTF-16/UTF-8というものについて、ある程度の知識が無いと意味が分からない部分もある。 特に合成文字(composed character sequences)は他の文字コードにはない概念なので、難しい。

文字列


文字列オブジェクトは、Cocoa Touchフレームワークでの文字列を意味する。 文字列をオブジェクトとして表現することはカプセル化の利点も提供する。

文字列オブジェクトは、のUnicode文字(言い換えると、テキスト文字列)として実装される。 不変の文字列は、作られてから解放されるまで変わることができない。 不変の文字列を造って管理するには、NSStringクラスを使用する。 造った後変わることが出来る文字列の管理には、NSMutableStringを使う。

NSStringとNSMutableStringを用いて作るオブジェクトは、文字列オブジェクトと呼ばれる。 または、Cの文字列と混乱が起こらないときは、単に「文字列」だけと呼ぶ。 特にC文字列という用語は、Cのchar *型を意味する。

文字列オブジェクトは、多数のUnicode文字として、表現される。 それが含む文字数(バイト数ではない)はlengthメソッドで得られる。 characterAtIndex:メソッドでは、文字列内の特定文字を取り出すことが出来る。 これら2つの「基本的な」メソッドは、文字列オブジェクトへの基本的なアクセスを提供する。
しかし、文字列でもっとも使われるのは、もっと高レベルにある。 文字列を比較して、それらを部分文字列として検索し、新しい文字列として結合したりする。

もしあなたが文字列オブジェクトを文字単位でアクセスする必要があるならUnicodeエンコード、 特に、合成文字に関する問題を理解する必要がある。 その詳細については、以下を見なさい (ASCIIやSHIFT-JISにはない概念が多数あり、かなり難しい)

文字列オブジェクトの生成と変換


NSStringとその子クラスNSMutableStringは、 それがサポートするいろいろな文字エンコードに関して、 最も基礎の文字列オブジェクトを作るいくつかの方法を提供する。

文字列オブジェクトは、常にその内容をUnicode文字として示すが、 その内容を多くの他のエンコード (例えば7ビットアスキーやシフトJIS) に変えることができる。 availableStringEncodingsクラス・メソッドは、サポートされるされるエンコードを返す。

C文字列を文字列オブジェクトに変えるとき、はっきりとエンコードを指定するか、デフォルトのC文字列エンコードを使う。

文字列の生成

文字列オブジェクトをソースコード内で生成する最も簡単な方法は、Objective-C のコンパイラディレクティブ @"..."である。
    NSString *temp = @"/tmp/scratch";
Objective-Cおいて、文字の内部表現はUTF-16であり、unichar型はその1文字を扱う型である。 しかし、プログラムソースはUTF-8で保存される。 従って、ソース上は、@""の中はUTF-8文字列ということになる。

C文字列とNSDataからNSStringへ

C文字列からNSStringオブジェクトを作るためには、initWithCString:encoding:メソッドを使う。 文字エンコードを正しく指定することが重要である。
char *utf8String = "これが存在すると仮定しなさい"; // ソースファイルはUTF-8なので直接記述出来る
NSString *stringFromUTFString = [[NSString alloc] initWithUTF8String:utf8String];
//
NSData *shiftJISData = "これが存在すると仮定しなさい"; // 実際にはSHIFT-JISで記述した文字列はUTF-8ファイル上では正しく表示されない
NSString *stringFromShiftJISData = [[NSString alloc] initWithData:shiftJISData encoding:NSShiftJISStringEncoding];
initWithData:encoding:メソッドは、NSDataオブジェクトに保存された文字列データをNSStringオブジェクトに変換出来る。
以下の例は、UTF-8 文字を含むNSStringオブジェクトをいったんNSDataに変換し、再度NSStringオブジェクトに戻している。
// NSString → NSData
unichar ellipsis = 0x2026;
NSString *theString = [NSString stringWithFormat:@"To be continued%C", ellipsis];
NSData *asciiData = [theString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
// NSData → NSString
NSString *asciiString = [[NSString alloc] initWithData:asciiData encoding:NSASCIIStringEncoding];
//
NSLog(@"Original:  %@ (長さ %d)", theString  , [theString length]  );
NSLog(@"Converted: %@ (長さ %d)", asciiString, [asciiString length]);
// 表示t:
// Original: To be continued… (長さ 16)
// Converted: To be continued... (長さ 18)
重要
NSStringは C文字列からNSStringを生成する多くのメソッドを提供する (stringWithCString:、initWithCString:、initWithCString:length:、initWithCStringNoCopy:length:freeWhenDone:等)。 これらのメソッドはデフォルトC文字列エンコードを使い、そのエンコードの変換において文字情報を失うかもしれない。 これらのメソッドは極力使わないこと。

C文字列を得る

文字列オブジェクトからC文字列を得るためにはUTF8Stringを使う。 これはUTF8文字列エンコードを使ったconst char* を返す。
const char *cString = [@"Hello, world" UTF8String];
あなたが受信するC文字列は、一時的なオブジェクトによって所有されて、自動割り当て解除が起こるとき無効になる。 あなたがC文字列を永久保存したいならば、バッファを作り、const char* の内容をコピーしなければならない。
重要
NSStringはC文字列を直接使うメソッドを数多く提供する。 (たとえば、cString、cStringLength、lossyCString、getCString:、getCString:maxLength:、 getCString:maxLength:range:remainingRange:等)。 これらのメソッドはデフォルトC文字列エンコードを使い、そのエンコードの変換において文字情報を失うかもしれない。 これらのメソッドは極力使わないこと。

可変的な文字列

可変文字列 (ここで言う可変とは、初期化後にも変更可能という意味ではなく、初期化時に任意のフォーマットを持って 生成出来るという意味である)を作るためには、一般的に、stringWithFormat:またはinitWithFormat: (ローカライズした文字列にはlocalizedStringWithFormat:)を使う。
これらのメソッドは、あなたが提供する値;数値・文字列や他オブジェクト等が挿入されるテンプレートとして、 フォーマット文字列を使う。サポートされるフォーマット記述子については 「フォーマット文字列オブジェクト」 で述べる。

ユーザに表示する文字列

ユーザーに表示する文字列を作るときは、アプリケーションをローカライズすることの重要性を考慮しなければならない。
一般に、プログラム内で、直接ユーザー見える文字列を作ることは避けなければならない。 代わりにあなたは、ローカライズされた文字列と結びつく辞書のキーの文字列をプログラム中で使わなければならない。 下例のように、一般的に、これにはlocalizable.stringsファイルとNSLocalizedString()等を使う。
// Objective-Cソース
NSString *greeting = NSLocalizedString(@"Hello", @"こんにちわ");    // @"Hello"がキー名、@"こんにちは"は単なる注釈
/* localizable.stringsファイル */
/* これがローカライズの実際を持つファイル */
"Hello" = "こんにちわ";
アプリケーションのローカライズについては「国際化プログラミングガイド」を見なさい。

文字列の結合と抽出

いろいろな方法で文字列を結合したり抽出したりできる。 2つの文字列を結合する最も簡単な方法は、stringByAppendingString: メソッドで、 既存の文字列に新しい文字列を加えて、新しい文字列オブジェクトを生成する。
NSString *beginning     = @"beginning";
NSString *alphaAndOmega = [beginning stringByAppendingString:@" and end"];
// alphaAndOmega は @"beginning and end" となる
initWithFormat:、stringWithFormat:、とstringByAppendingFormat: メソッドは、 テンプレートによっていくつかの文字列を結合することもできる; 詳細については 「フォーマット文字列オブジェクト で述べる。

substringToIndex:、 substringFromIndex:、と substringWithRange: メソッドでは 文字列の一部の抽出が出来る。
componentsSeparatedByString: メソッドでは文字列を部分文字列(セパレーター文字列)で分けることもできる。 これらのメソッドの例に示す。 なお、文字列の位置を示す番号は先頭を0とする。
NSString *source = @"0123456789";
NSString *firstFour = [source substringToIndex:4];
// firstFour は @"0123"

NSString *allButFirstThree = [source substringFromIndex:3];
// allButFirstThree は @"3456789"

NSRange twoToSixRange = NSMakeRange(2, 4);
NSString *twoToSix = [source substringWithRange:twoToSixRange];
// twoToSix は @"2345"

NSArray *split = [source componentsSeparatedByString:@"45"];
// split は { @"0123", @"6789" } を含む
あなたが文字位置番号よりもパターンマッチを使って文字列を抽出する必要があるならば、 スキャンを使わなければならない。それについては 「スキャン」を見なさい。

フォーマット文字列オブジェクト


ここでは、どのようにフォーマット文字列を使って文字列を作るか、 どのように非ASCII 文字をフォーマット文字列の中で使うか、 また、開発者がNSLog() または NSLogv()を使うとき作るメッセージについて述べる。

フォーマットの基礎

NSStringで使うフォーマット文字列は、ANSI C printf()関数の定義するフォーマット文字群に加え、 "%@"をどんなオブジェクトにも使えるように拡張している。
(フォーマット文字列については、 「文字列フォーマット記述子」 IEEE printf 仕様を参照のこと。)

オブジェクトがdescriptionWithLocale:メッセージに反応するならば NSStringは、テキスト表現を取り出すために、そのメッセージを送る。 さもなければ、descriptionメッセージを送る。元来これはNSObjectのメソッドで、 NSArrayやNSDictionary等はそれをオーバーライドして、%@で表示される時の 表現を作り出している。

フォーマット文字列の中で、'%'とそれに続く文字で、どんな種類の値が予想され、どのようにフォーマットするかを決定する。 たとえば、"%d houses"というフォーマット文字列は、整数値がフォーマット表現'%d'と置換されると予想する。

値のフォーマットは、ユーザの現在のロケールに影響される。 NSStringはロケールの定義で、10進数のセパレーターのみを使う(それはNSDecimalSeparatorという名前のキーで得られる)。 NSDictionaryオブジェクトでは数値、日付等のフォーマットを指定する。

NSStringのstringWithFormat:メソッド、他の関連するメソッドを引数のリストで特定されるprintf形式でフォーマットされた文字列を作るために を使うことができる。 これについては、 「文字列オブジェクトの生成と変換」で述べる。

下記の例は、フォーマット記述子と引数からどのように文字列を生成できるかについて示している。
NSString *string1 = [NSString stringWithFormat:@"A 文字列: %@, a float: %1.2f",@"文字列", 31415.9265];
// string1 は "A 文字列: 文字列, a float: 31415.93"

NSNumber *number = [NSNumber numberWithInt:1234];
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:[NSDate date] forKey:@"date"];
NSString *baseString = @"Base 文字列.";
NSString *string2 = [baseString stringByAppendingFormat:@" A number: %@, a dictionary: %@", number, dictionary];
// string2 は "Base 文字列. A number: 1234, a dictionary: {date = 2005-10-17 09:02:01 -0700; }"

文字列と非ASCII文字

あなたは、(Unicodeを含む)非ASCII 文字を、stringWithFormat: と stringWithUTF8String:等のメソッドを使って 文字列中に含めることが出来る。 Objective-Cでは文字の内部コードはUTF-16で、ソース上はUTF-8を使う。
NSString *s = [NSString stringWithFormat:@"Long %C dash", 0x2014];
UTF-16で0x2014はUTF-8では 0xe28094 なので、それを文字列の中に直接記述した場合は、以下のように書ける。
NSString *s = [NSString stringWithUTF8String:"Long \xe2\x80\x94 dash"];
なお、ソースコードの中に直接0x80~0xffの文字を含むことは安全でない。

NSLog と NSLogv

ユーティリティ関数のNSLog() と NSLogv()は、 エラーメッセージのログを取るため、NSString文字列の文字列フォーマットサービスを利用する。 これらの関数に引数を指定するとき、結果に注意しなさい。 一般的な間違いは、フォーマット文字を含む文字列を指定してしまうことにある。 以下に例を示す。
    NSString *string = @"A contrived string %@";
    NSLog(string);
    // アプリケーションは実行時エラーを発生する
このような場合、以下のように%@を経由して表示させると良い。
NSString *string = @"A contrived string %@";
NSLog(@"%@", string);
// 出力: contrived string %@

文字列フォーマット記述子


ここでは、文字列フォーマットメソッドや関数でサポートされている文字列フォーマット記述子について述べる。

フォーマット記述子

フォーマット記述子は、NSStringフォーマットメソッドとCFStringフォーマット関数でサポートされている。 前述の通りNSLog関数でも使用することもできる。 それはIEEE printf仕様に準拠しており、要約は表1である。
%1$@ %2$sのような「n$」位置指示子も使用できる。詳細は、IEEE printf仕様を見なさい。

表1 NSStringフォーマットメソッドとCFString フォーマット関数でサポートされているフォーマット記述子
記述子内容
%@Objective-C オブジェクトで、 有効ならばdescriptionWithLocale:、だめならdescriptionで返ってくる文字列。
CFCopyDescription関数の結果を返すことで、CFTypeRef オブジェクトでも動作する。
%%% 文字そのもの
%d, %D, %i符号付き 32ビット整数 (int)
%u, %U符号なし 32ビット整数 (符号なし int)
%hi符号付き 16ビット整数 (short)
%hu符号なし 16ビット整数 (符号なし short)
%qi符号付き 64ビット整数 (long long)
%qu符号なし 64ビット整数 (符号なし long long)
%x符号なし 32ビット整数 (符号なし int), 0~9数字と英小文字 a~fで出力される16進数
%X符号なし 32ビット整数 (符号なし int), 0~9数字と英大文字 A~Fで出力される16進数
%qx符号なし 64ビット整数 (符号なし long long), 0~9数字と英小文字 a~fで出力される16進数
%qX符号なし 64ビット整数 (符号なし long long), 0~9数字と英大文字 A~Fで出力される16進数
%o, %O符号なし 32ビット整数 (符号なし int), 8進数出力
%f64ビット浮動小数点値 (double)
%e64ビット浮動小数点値 (double)、 累乗の指数を導入するために、英小文字eを用いた指数表記で出力される
%E64ビット浮動小数点値 (double)、 累乗の指数を導入するために、英大文字Eを用いた指数表記で出力される
%g64ビット浮動小数点値 (double)、 累乗の指数が~4より少ないか、精度以上であるならば、%eで出力される。さもなければ%fで出力する。
%G64ビット浮動小数点値 (double), 累乗の指数が~4より少ないか、精度以上であるならば、%eで出力される。さもなければ%fで出力する。
%c8ビット符号なし文字 (符号なし char)、 ASCII 文字か、非ASCII 文字なら8進数表記の\\dddまたはUnicode 16進数フォーマットの \\udddd(dは数字)で NSLog() によって出力される
%C16ビット Unicode 文字 (unichar)、 ASCII 文字か、非ASCII 文字なら8進数表記の\\dddまたはUnicode 16進数フォーマットの \\udddd(dは数字)で NSLog() によって出力される
%sNullで終端する 8ビット符号なし文字の配列。 %sは、たとえば、UTF-8よりもむしろシステム・エンコードで、その入力を解釈する。
%SNullで終端する 16ビット Unicode 文字の配列
%pVoid ポインター (void *)、0xで始まる0~9数字と英小文字 a~fで出力される16進数
クラスインスタンスの場合は、そのアドレス
%L これに続くa、A、e、E、f、F、g、またはG変換記述子が、slong double 引数に適用されることを示している、長さ修飾子
%a64ビット浮動小数点値 (double)、 0xで始まり、小数点の前に1桁の16進数、指数表記のために英小文字pを使って累乗指数で出力する
%A64ビット浮動小数点値 (double)、 0Xで始まり、小数点の前に1桁の16進数、指数表記のために英大文字Pを使って累乗指数で出力する
%F64ビット浮動小数点値 (double)、10進数で出力される
%z これに続くd、i、o、u、xまたはX変換記述子が、size_tまたは対応する符号付き整数型引数に適用されることを示している、長さ修飾子
%t これに続くd、i、o、u、xまたはX変換記述子が、size_tまたは対応する符号なし整数型引数に適用されることを示している、長さ修飾子
%j これに続くd、i、o、u、xまたはX変換記述子が、intmax_tまたはuintmax_tに適用されることを示している、長さ修飾子


ファイルやURLから文字列を読み込んだり書き込んだりする


NSStringを使ってファイルまたはURLから読み込むことは、エンコードを知っているならば、簡単である。 もしエンコードを知らないならば、リソースを読み込むことはより難しい。 ファイルやURLに書き込むときは、使うエンコードを指定しなければならない。

ファイルと URLsから読み込む

NSStringはファイルとURLからファイルを読み込むための豊富なメソッドを提供する。 一般に、そのエンコードを知っているなら、データを読み込むことはより簡単である。 あなたが素のテキストとエンコードについての知識を持ってないなら、それは難しい。

エンコードを知っているデータを読み込む

エンコードを知っているファイルまたはURLから読み込むためには、 stringWithContentsOfFile:encoding:error: または stringWithContentsOfURL:encoding:error:、 またはinit~に相当するメソッドを使う。
NSString *path = ...;
NSError *error;
NSString *stringFromFileAtPath = [[NSString alloc]initWithContentsOfFile:path
                                                        encoding:NSUTF8StringEncoding
                                                        error:&error];
if (stringFromFileAtPath == nil) {
    // エラーが発生したとき
    NSLog(@"Error reading file at %@\n%@", path, [error localizedFailureReason]);
    ~
}
以下の例のように、データオブジェクトを使って文字列を初期化することも出来る。 ここでも正しいエンコードを指定しなければならない。
NSString *path = ...;
NSData *data = [NSData dataWithContentsOfFile:path];

// データがUTF8である
NSString *string = [NSString stringWithUTF8String:[data bytes]];

// データが他のエンコードである。たとえば ISO-8859-1
NSString *string = [[NSString alloc] initWithData:data encoding: NSISOLatin1StringEncoding];
重要
NSStringは エンコードを指定することなくファイルやURLを読み込むためのメソッド (stringWithContentsOfFile: と initWithContentsOfURL:のようなもの)を提供するが、 これらのメソッドではあなたは情報を失うか、使っているデータを壊すかもしれない。 極力使わないように。

エンコードを知らないデータを読み込む

もしあなたが未知のエンコードのテキストを見つけたなら、 回避不能なエラーを訂正するための機構があることを確認するのが一番である。 たとえば、アップルのメイルとSafariアプリケーションはエンコードメニューを持っている。 そして、TextEditによって、ユーザーが指定したエンコードでファイルを再オープンすることができる。

エンコードを推測するしかないときは、以下の手順をとる。
  1. stringWithContentsOfFile:usedEncoding:error: または initWithContentsOfFile:usedEncoding:error:を試す (または URL基準の等価メソッド)。
    これらのメソッドはリソースのエンコードを決定しようと試みる、 そして成功したなら、使ったエンコードを参照返しする。
  2. もし(1)に失敗したなら、エンコードとしてUTF-8を指定してリソースを読み込んでみる
  3. もし(2)に失敗したなら、適当な遺物的エンコードを試す。
    ここでの「適切」は、状況次第である。 それは、デフォルトのC文字列エンコードであるかもしれないし、 ISOまたはWindowsラテン語1または何か他のものであるかもしれない。 日本でならSHIFT-JISの可能性が高い。 それは、あなたのデータがどこから来ているか次第である。
  4. 最後に、 UIKitからNSAttributedStringの読み込みメソッドを試す。 (initWithURL:options:documentAttributes:error:のようなもの)。
    それらのメソッドはプレーンテキスト・ファイルを読み込ませようとして、使われるエンコードを返す。 それらは多少任意のテキスト文書の上で使わうできて、 あなたのアプリケーションがテキストで特別な専門知識を持ってないなら、考慮する価値がある。 ただし、それらは自然言語テキストでない文書やFoundationレベルのツールに対しては適切なものではないかもしれない。

ファイルと URLsに書き込む

ファイルやURLから読み込むことに比べ、書き込むことはわかりやすい。 NSStringは2つの簡便なメソッド writeToFile:atomically:encoding:error: と writeToURL:atomically:encoding:error: を提供する。
ここでは使うエンコードを指定しなければならない。 そして、atomicallyにリソースを書くべきかどうかを指定する。 atomically=NOならば、文字列は直接、あなたが指定するパスに書かれる。 atomically=YESならば、それは最初に補助ファイルに書かれてから、指定パスに移動される。 このオプションは、たとえシステムが文書を書き込んでいる途中に暴走/シャットダウンしても、 ファイルが壊れないことを保証する。
URLに書くならば、書き込み先がatomicallyにアクセスされることが出来るタイプでないならば、 atomicallyオプションは無視される。
NSString *path   = ...;
NSString *string = ...;
NSError *error;
BOOL ok = [string writeToFile:path atomically:YES encoding:NSUnicodeStringEncoding error:&error];
if (!ok) {
    // エラーが発生したとき
    NSLog(@"Error writing file at %@\n%@", path, [error localizedFailureReason]);
    ~
}

文字列の検索、比較、ソート


文字列クラスは、文字列同士の比較や、文字や部分文字列を文字列中で探すためのメソッドを提供する。 これらのメソッドは、2つの文字の列が等しいかどうか決定するためにUnicode基準に従う。 それは合成文字の列を正しく取り扱う。 効率が重要なときは、あなたには文字単位(literal)検索を指定出来る。 そして、合成文字の列のために若干の標準系を保証することが出来る。

検索と比較メソッド

検索と比較のメソッドは、いくつかの変化系からなる。 最も簡単なものは、文字列全体を検索、比較する。 変化系は、合成文字の列の比較方法を変えることが出来たり、 検索されるまたは比較される文字列の中で、特定の文字の範囲を指定することができる。 与えられたロケールのコンテキスト内で文字列の検索または比較も出来る。 下表は、基本的な検索と比較メソッドである。
検索メソッド 比較メソッド
rangeOfString: compare:
rangeOfString: options: compare: options:
rangeOfString: options: range: compare: options: range:
rangeOfString: options: range: locale: compare: options: range: locale:
rangeOfCharacterFromSet:
rangeOfCharacterFromSet: options:
rangeOfCharacterFromSet: options:range:

検索文字列

rangeOfString:~メソッドはレシーバー内で部分文字列を探すために使う。 rangeOfCharacterFromSet:~メソッドは、供給された文字の組から、個々の文字を捜す。 完全に指定された範囲の中で含まれる場合だけ、部分文字列は見つかる。
検索または比較メソッドのために範囲を指定して、NSLiteralSearch(下記参照)を要請しないならば、 範囲は、合成文字の列を、始点終点共に分解してはいけない。 分解してしまうと、誤った結果を得ることになる。 (rangeOfComposedCharacterSequenceAtIndex:メソッドの内容を、 範囲が文字列境界にあるように調整するプログラム・サンプルから見なさい。)

文字列オブジェクトをNSScannerのインスタンスを用いた数字と文字列値を求めて調べることもできる。 これについては、「スキャン」を見なさい。 NSString と the NSScanner クラス群は、NSCharacterSetクラス群を検索オプションとして使う。 文字セットについては 「文字セット」を見なさい。

文字列の比較とソート

compare:~メソッドはレシーバーと指定文字列の語彙の順序を返す。 他のいくつかのメソッドは、2つの文字列が等しいかどうか、 あるいは、一方が他方の接頭辞か接尾辞であるかどうか決定することができる。 しかし、それらは検索オプションまたは範囲を指定することができる変化系を持たない。

文字列を比較するのに最も簡単なメソッドはcompare:である。 これは、compare:options:range:をオプション(options)なし、範囲(range)をレシーバー全体にして比較を実行するのと同じである。 あなたが(NSCaseInsensitiveSearch、 NSLiteralSearch、または NSNumericSearchのような) 比較オプションを指定したいなら、 compare:options:を使う。 ロケールを指定したいなら、compare:options:range:locale:を使う。 NSString は直接、範囲とオプションを指定する必要なしで一般の比較を行うことができる、変化系の簡便なメソッドも提供する。 たとえば caseInsensitiveCompare: やlocalizedCompare:である。
重要
ユーザーに表示するソート結果については、あなたはローカライズされた比較を常に使わなければならない。 従って、一般的にcompare: または caseInsensitiveCompare:の代わりに localizedCompare: またはlocalizedCaseInsensitiveCompare:を使うべきである。
あなたが、Finderで表示されるのと同じ順番で文字列を比較したいなら、 compare:options:range:locale:にユーザーのロケールと以下のオプション NSCaseInsensitiveSearch、 NSNumericSearch、 NSWidthInsensitiveSearch や NSForcedOrderingSearchで使うことが出来る。 例については 「Finderのような文字列ソート」を見なさい。

検索と比較のオプション

検索と比較メソッドのいくつかは、「options」引数を持つ。 これはビットマスク指定であり、以下の組み合わせで指定できる。 (全てのオプションが全てのメソッドで有効なわけではない。)
検索オプションの効果
NSCaseInsensitiveSearch文字の大文字小文字の区別を無視する
NSLiteralSearchバイト単位で比較する。
他では同じと判定される合成文字も不一致と判定される。
このオプションを使うといくつかの操作が劇的に速くなる。
NSBackwardsSearch範囲の後ろから前に検索する
NSAnchoredSearch範囲の先頭または終端の文字だけを検索する。
先頭または終端で一致しないということは、全体としては不一致を意味する。
NSNumericSearchcompare:options: メソッドを一緒に使うとき、 数字の一群は、比較時に数値として処理される。
たとえば、Filename9.txt < Filename20.txt < Filename100.txtである。

接頭辞(Prefix)と接尾辞(Suffix)のための大文字小文字を無視した検索

NSString はメソッド hasPrefix: と hasSuffix:提供する。 それらは の完全一致を見つけるために使うことが出来る。 以下の例は、rangeOfString:options:を 大文字と小文字の区別をしない検索を実行するオプションの組合せで、 どのように使うかを示している。
NSString *searchString = @"age";
NSString *beginsTest   = @"Agencies";
//                         ~~~
NSRange prefixRange = [beginsTest rangeOfString:searchString options:(NSAnchoredSearch | NSCaseInsensitiveSearch)];
// prefixRange = {0, 3}

NSString *endsTest     = @"BRICOLAGE";
//                               ~~~
NSRange suffixRange = [endsTest rangeOfString:searchString   options:(NSAnchoredSearch | NSCaseInsensitiveSearch | NSBackwardsSearch)];
// suffixRange = {6, 3}

文字列比較

以下の例は、変化系文字列比較メソッドと関連するオプションの使い方を示している。 最初は最も簡単な比較メソッドである。
NSString *string1 = @"string1";
NSString *string2 = @"string2";
NSComparisonResult result;

result = [string1 compare:string2];
// result = -1 (NSOrderedAscending)
NSNumericSearch オプションを使うことで文字列を数値として比較することが出来る:
NSString *string10 = @"string10";
NSString *string2  = @"string2";
NSComparisonResult result;

result = [string10 compare:string2];
// result = -1 (NSOrderedAscending)

result = [string10 compare:string2 options:NSNumericSearch];
// result = 1 (NSOrderedDescending)
caseInsensitiveCompare: と localizedCaseInsensitiveCompare:で大文字小文字を無視した比較ができる。
NSString *string_a = @"Aardvark";
NSString *string_A = @"AARDVARK";

result = [string_a compare:string_A];
// result = 1 (NSOrderedDescending)

result = [string_a caseInsensitiveCompare:string_A];
// result = 0 (NSOrderedSame)
// [string_a compare:string_A options:NSCaseInsensitiveSearch]と等価

Finderのような文字列ソート

以下の例は、Finderで見られるような順番での文字列の比較がどのようにすれば出来るのかを示している。 最初に、関連した比較オプションを含むソート関数を定める。 (効率のために、コンテキストとしてユーザーのロケールを通すこと。このパスは一度だけ調べられる。)
int finderSortWithLocale(id string1, id string2, void *locale)
// ロケール対応のソート関数
{
    static NSStringCompareOptions comparisonOptions =
                                NSCaseInsensitiveSearch | NSNumericSearch |
                                NSWidthInsensitiveSearch | NSForcedOrderingSearch;
    NSRange string1Range = NSMakeRange(0, [string1 length]);
    return [string1 compare:string2 options:comparisonOptions range:string1Range locale:(NSLocale *)locale];
}
あなたは、sortedArrayUsingFunction:context:へのパラメータとして、 コンテキストとしてユーザの現在のロケールと共に、関数を渡す。
NSArray *stringsArray = [NSArray arrayWithObjects:
                                @"String 1",
                                @"String 21",
                                @"String 12",
                                @"String 11",
                                @"String 02", nil];
NSArray *sortedArray = [stringsArray sortedArrayUsingFunction:finderSortWithLocale context:[NSLocale currentLocale]];
// sortedArray は { "String 1", "String 02", "String 11", "String 12","String 21" }を含む

改段落と改行


ここでは、どのように行または段落セパレーターを定義するか、 どのように段落で文字列を分けるか、について述べる。

行と段落の セパレーター文字

行または段落が改まる方法がいくつかある。 歴史的には、\n、\rと\r\nが、使われてきた。 Unicodeは、明白な段落セパレーターU+2029(=NSParagraphSeparatorCharacter)と 明白な行セパレーターU+2028(=NSLineSeparatorCharacter)を定めている。

Cocoaテキスト・システムでは、NSParagraphSeparatorCharacterを一貫して改段落とみなし、 NSLineSeparatorCharacterは一貫して、改行;つまり改段落でない、段落の中の改行とみなす。
しかし、他のコンテキスト処理では、これらの文字が処理される保証があまりない。 たとえば、POSIX-レベル・ソフトウェアは、改行としてしばしば\nだけを認識する。 少し前のMacintoshソフトウェアは\rだけを認識する。 そして、若干のWindows/DOSソフトウェアは\r\nだけを認識する。 また時々、改行と改段落に区別がない。

あなたがどの改行または改段落文字を使うかは、 あなたのデータがどう使われるか、どのプラットフォームにあるか次第である。
Cocoaテキスト・システムは、\n、\rまたは\r\n全てをNSParagraphSeparatorCharacterと同じ改段落と認識する。 それが(たとえばinsertNewline:による)改段落を挿入する時それは、\nを使う。 通常、NSLineSeparatorCharacterは特に改段落ではなく、特に改行であるためにだけに使われる。 たとえばそれは、insertLineBreak:またはHTMLの<br>要素を意味する。

もしあなたの「改める」が改行であって改段落でないなら、 あなたは一般的にNSLineSeparatorCharacterを使わなければならない。 さもなければ、\n、\rまたは\r\nを、他のどんなソフトウェアがあなたのテキストを処理しそうか依存しながら、 使うかも知れない。Cocoaのためのデフォルト選択は、通常\nである。

文字列を“段落によって”分ける

文字列を“段落によって”分けるためには、共通の方法がある。 それは簡単で、
    NSArray *arr = [myString componentsSeparatedByString:@"\n"];
である。しかしながらこれは、\r, \r\n, または Unicode セパレーターという文字列にあるような、 改段落または改行に多くの方法があるという事実を無視する。 その代わりに、あなたはlineRangeForRange: または getParagraphStart:end:contentsEnd:forRange: のような メソッドを利用することが出来る。
NSString *string = @"分割する文字列~";
unsigned length = [string length];
unsigned paraStart = 0, paraEnd = 0, contentsEnd = 0;
NSMutableArray *array = [NSMutableArray array];
NSRange currentRange;
while (paraEnd < length) {
    [string getParagraphStart:&paraStart end:&paraEnd contentsEnd:&contentsEnd forRange:NSMakeRange(paraEnd, 0)];
    currentRange = NSMakeRange(paraStart, contentsEnd - paraStart);
    [array addObject:[string substringWithRange:currentRange]];
}

文字と書記素集団


文字列を一連の文字とみなすのは一般的である。 しかし、NSStringオブジェクトまたは一般のUnicode文字列で処理するとき、 ほとんどの場合、個々の文字よりもむしろ部分文字列で対処する方が良い。
この理由は、ユーザーが多くの場合、テキストの文字として認めるものが、文字列では並列文字によって 見受けられるかもしれないということである。 NSStringはUnicode文字列をちゃんと取り扱うための、メソッドの大きな目録を持つ。 それは一般に、Unicodeへの対応を簡単にする。 しかし、要注意事項がある。

NSStringオブジェクトは、概念的にプラットホームエンディアンによるUTF-16である。 それが意味するものは、NSString文字列長や文字要素番号と範囲がUTF-16単位で表現されるということである。 ほとんどの場合、ユーザーがそれを意識する必要は無い。 部分文字列で対処している限り、範囲要素番号の正確な解釈は必ずしも重要ではない。

現存する言語を書くために使われる大多数のUnicodeコードポイントは、一つのUTF-16ユニットで見受けられる(1文字1コードであると言うこと)。 (コードポイント:Unicodeの文字を表現するとき、"U+"の後に続く文字の符号位置を表す16進数の値のこと。) しかし、いくつかの一般でないUnicodeコードポイントは、サロゲートペア(代用対)によってUTF-16において表現される。 サロゲートペアは一連の2つのUTF-16単位である。 そして、一緒に一つのUnicodeコードポイントを代表する特定の予約の範囲からとられる。 CFStringは、サロゲートペアと対応するUnicodeコードポイントのUTF-32の間で変換するために、関数を持つ。 NSStringオブジェクトに対処するとき、1つの制約は部分文字列境界が通常サロゲートペア2つの半分を切り離してはならないということである。 これは通常、大部分のCocoaメソッドから返される範囲では自動である。 しかし、あなたが自分で部分文字列範囲を作っているならば、これのことを覚えておかなければならない。 さらに、これはあなたが考慮するべきである唯一の制約でない。

多くの文書システムでは、一つの文字は、アクセントまたは他の装飾を加えた基本活字から成るかもしれない (ウムラウトのような文字のことを言っている) 。 可能性がある活字とアクセントの数はUnicodeが各々の組合せを一つのコードポイントとして描写するのを妨げるので、 一般に、そのような組合せは、一つ以上の結合マークが続くベース文字によって見受けられる。 互換性理由で、Unicodeはいくつかの最も一般の組合せのために、一つのコードポイントを持つ。 これらは、precomposed形式と呼ばれる。 そして、Unicode正常化変換は、precomposedとdecomposed表記の間で変換する用いられる。 しかし、たとえ文字列が完全にprecomposedであるとしても、ベース文字と結合マークを使っていることを表されなければならない多くの組合せがまだある。 大部分のテキスト処理のために、それらの境界がベース文字をその連合結合マークから切り離さないように、 部分文字列範囲は配置されなければならない。

そのうえ、文字がアクセント記号より難しくなる役の組合せを表す文書システムがある。 韓国語では、たとえば、一つのハングル音節は、字母として知られている2つまたは3つの下位パーツから成ることができる。 南アジアと東南アジア中で一般のインド語派とインド語派に影響された文書システムに、 一つに書かれた文字は、しばしば子音、母音とマーク(例えばvirama)の組合せを表す。 そして、これらの文書システムのUnicode表記はこれらの個々のパーツのためにしばしばコードポイントを使う。 そのため、一つの文字は並列コードポイントから成るかもしれない。 大部分のテキスト処理のために、 それらの境界が一つのハングル音節でも字母を切り離さないように、 またはインド語派子音の構成要素が集まるように、 部分文字列範囲も配置されなければならない。

一般に、これらのサロゲートペア組み合わせ~基本文字+結合マーク、ハングル字母、そして インド語の子音群は書記素集団(grapheme clusters)と呼ばれる。 それらを考慮に入れるために、あなたはNSStringのrangeOfComposedCharacterSequencesForRange: または rangeOfComposedCharacterSequenceAtIndex: メソッド、または CFStringGetRangeOfComposedCharactersAtIndexを使う。 これらは、 上記の制約の全てを考慮し、書記素集団境界にかかるように、 文字列要素番号または部分文字列範囲を調節するのに用いられる。 これらのメソッドは、ユーザーの認めた文字の境界をプログラム的に決定するためのデフォルト選択でなければならない。

場合によっては、Unicodeアルゴリズムは、書記素集団境界さえ越える方向で、並列文字に対処する。 英小文字から英大文字へ行くとき、Unicodeの大文字小文字変換アルゴリズムは一つの文字を並列文字に変えるかもしれない。 たとえば、標準的な英大文字ドイツの文字s相当は、2活字列「SS」である。 多くの言語の局所的な照合アルゴリズムは、並列文字列を一つの単位と思う。 たとえば、文字列「ch」は、いくらかのヨーロッパの言語の目的を分類するための一つの活字とみなされる。 きちんとこれらのようなケースにも正しくに対処するために、 大文字小文字化、ソート、検索で標準的なNSStringメソッドを使うこと、 そして、全てのそれらが適用されることになっている文字列の上でそれらを使うことは重要である。 NSString のlowercaseString、uppercaseString、 capitalizedString、 compare:またはその変化系のメソッド、 rangeOfString: とその変化系、そしてrangeOfCharacterFromSet:とその変化系、 またはCFStringでの等価関数を使いなさい。 これらのすべては、Unicode文字列処理の複雑さを考慮している。 そして、特に検索とソートメソッドは、認識する同等の種類を制御するために、多くのオプションがある。

若干のより少ない例では、それは書記素集団の定義を特定の必要に合わせるのに必要な場合がある。 書記素集団境界を決定して、手直しすることに関係する問題は Unicode Standard Annex #29で詳細にてカバーされる。 そして、それはいくつかの例と若干のアルゴリズムを伝える。 一般に、「The Unicode standard」は、Unicodeアルゴリズムに関する最高の情報源であり、 Unicode文字列処理に関係する重要なポイントである。

あなたがカーソル運動と挿入位置位置決めの観点から書記素集団境界に興味があり、 そしてあなたがCocoaテキスト・システムを使用しているならば、 Mac OS X v10.5以降では、 NSLayoutManagerが、一連のテキストの範囲内で配置される、挿入位置位置を測定するためのAPIサポートをする。 挿入位置境界が絵文字境界線と同一でないことに注意すべきである。 例えばラテン語の「fi」スラーのようなスラー絵文字は、ユーザーの認めた文字境界で、 場合によっては内部の挿入位置を必要とするかもしれない。 詳細はCocoaテキスト・システム文書(例えばMac OS X Text Overview GuideとText Editing Programming Guide)を見なさい。

・・・というようにUnicodeは、従来の文字コードとは明らかに異なるコード体系である。 こんなもん考える方も考える方だが、それを正しく理解して全ての言語で正しく動作するように 文字列操作プログラムを書ける人間はどれだけいるのだろうかと思う。 少なくとも、私には無理。X-BASIC for iOS内部では、SHIFT-JISとUTF-8両対応のためにそれなりに複雑な文字コード処理をしているが、 サロゲートペアとかは考慮してない。

文字セット


NSCharacterSet オブジェクトは Unicode 文字の組を示す。 NSStringとNSScannerオブジェクトは検索動作のために文字を一緒に集めるために NSCharacterSetオブジェクトを使う。 それらが検索の間、文字の特定の組のどれでも見つけることができるように。

文字セットの基本

文字セットオブジェクトはUnicode 文字の組を扱う。 2つの公開クラスは、 NSCharacterSet NSMutableCharacterSet で、 固定文字セットと可変文字セットとして、それぞれプログラムインターフェースを宣言する。 固定文字セットは、生成するとき定義され、その後変更できない。 可変文字セットはそれを生成した後に変更できる。

文字セットオブジェクトは単体では機能しない。文字列操作上において文字の組の価値を持つ。 NSString と NSScannerはNSCharacterSet オブジェクトをある一連の文字を探すための引数として使う。 たとえば、下記プログラムは、最初の英大文字活字の範囲をmyString:で発見する。
NSString *myString = @"some text in an NSString...";
NSCharacterSet *characterSet = [NSCharacterSet uppercaseLetterCharacterSet];
NSRange letterRange;
letterRange = [myString rangeOfCharacterFromSet:characterSet];
このプログラムを実行するとrangeOfCharacterFromSet:が呼び出され、 letterRange.location は "NSString"の最初の“N”の文字位置となる。 文字列の最初の文字が'S'なら、それは0=先頭になる。

文字セットの生成

NSCharacterSetは、一般的に用いられる文字セット、 例えば活字(大文字または小文字)・10進数・空白文字・その他を返すクラス・メソッドを定義する。 これらの「標準」文字セットは、それがNSMutableCharacterSetにメッセージを送ることで生成されたとしても、 いつも固定である。 標準文字セットについての追加情報は 「標準文字セットとUnicode定義」 を見なさい。

標準文字セットの可変のコピーを作り、それを変更することでカスタムのセットを構築し、使うことが出来る。 ((もちろん、allocとinitと追加の文字で可変の文字セットを一から生成して始めることも出来る。) たとえば、下記プログラムは、アルファベット・数字・基本的な句読点を含む文字セットを生成する。
NSCharacterSet *finalCharSet;       // 文字群(固定)
NSMutableCharacterSet *workingSet;  // 中間ワーク(可変)
//
workingSet   = [[NSCharacterSet alphanumericCharacterSet] mutableCopy]; // 英数字
[workingSet addCharactersInString:@";:,."]; // 句読点を追加
finalCharSet = [workingSet copy]; // 最終文字群を作成
[workingSet release]; // 中間ワークを解放
Unicodeコードポイントを使っているカスタム文字セットを定義するためには、 以下に類似したプログラムを使いなさい。 これは、改行と行セパレーター文字を含む文字セットを作っている。
UniChar chars[]  = {0x000C, 0x2028};
NSString *string = [[NSString alloc] initWithCharacters:chars length:sizeof(chars) / sizeof(UniChar)];
NSCharacterSet *chset = [NSCharacterSet characterSetWithCharactersInString:string];
[string release];

パフォーマンス考慮点

文字セットはしばしば、パフォーマンスが重要なプログラムに関与する。 可変文字セットは、通常固定文字セットより非常に遅く、多くのメモリを消費する。 なので、あなたは以下のガイドラインに従うべきである。

文字セットファイルの生成

あなたのアプリケーションがカスタム文字セットを多用するならば、 リソース・ファイルにその定義を保存しなければならない。 そして、あなたがセットを生成する必要があるたびに、個々の文字から再作成する代わりに、それを読み込ませなさい。 あなたは、そのビットマップ表記(NSDataオブジェクト)を得ることによって、文字セットを保存することができる。 そして、ファイルにそのオブジェクトを保存する。
NSString *filename=@"filename";
NSString *absolutePath;
NSData   *charSetRep;
BOOL result;

absolutePath = [filename stringByStandardizingPath];
charSetRep   = [finalCharSet bitmapRepresentation];
result       = [charSetRep writeToFile:absolutePath atomically:YES];
習慣的に、文字セットファイル名は拡張子.bitmapを使う。 あなたが他の人のために文字セット・ファイルを公開するつもりなら、この規則に従わなければならない。 .bitmap拡張子で文字セット・ファイルを読むためには、characterSetWithContentsOfFile: メソッドを使う。

標準文字セットと Unicode定義

letterCharacterSetによって返されるような標準文字セットは、 Unicode標準(例えば英大文字、結合マーク、その他)によって確立される規範的で有益なカテゴリーに関して、正式に定められる。 標準文字セットの正式な定義は、標準で定められるカテゴリーの一つ以上として、ほとんどの場合与えられている。 たとえば、letterCharacterSetによって返されるセットは、lowercaseLetterCharacterSetによって返されるセットが アルファベットカテゴリの全文字を含む間、全文字を模範的な英小文字カテゴリーに含む(ややこしい言い回し)。

カテゴリー自体の定義は、新しいバージョンのUnicodeでは変わるかもしれないことに注意すべきである。 あなたは、 http://www.unicode.org/.からカテゴリー・メンバーシップを定めるファイルをダウンロードすることができる。

スキャン


NSScannerオブジェクトはNSStringオブジェクトの文字を調べる。そして、文字を解釈して、それらを数字と文字列値に変える。 アイテムを要請する度に、スキャナはその文字列の始めから終わりまで文字を進む。

Scannerを生成する

NSScannerのスキャナオブジェクトは通常、 クラスメソッド scannerWithString: または localizedScannerWithString:を呼び出すことにより インスタンス化する。 どちらのメソッドも、あなたがそれに通す文字列で初期化されるスキャナ・オブジェクトを返す。 新しく生成されたスキャナは、その文字列の先頭から開始される。

たとえば scanInt:、 scanDouble:、scanString:intoString:のようなを使って構成要素を調べる。 あなたが複数行を調べるなら一般的に、スキャナが文字列の終わりなるまで続くwhileループを作成する。 それを以下のプログラムに例示する。
float aFloat;
NSScanner *theScanner = [NSScanner scannerWithString:aString];
while ([theScanner isAtEnd] == NO) {
    [theScanner scanFloat:&aFloat];
    ~
}
スキャナーにおいて英大文字小文字を区別するかどうかの設定はsetCaseSensitive: メソッドで行う。 デフォルトのスキャナーは大文字小文字を区別しない。

Scannerを使う

スキャンは、スキャン位置から開始される。、 そして、スキャナーはスキャンされた値表記の最後の文字の直後まで進んでいる。
たとえば、文字列“137 small cases of bananas”から整数を調べた後には、 スキャナの示す位置は3である。それは、数字の直後のスペースを示す。 しばしば、あなたは関心がない文字をスキップするために、スキャン位置を進める必要がある。 それはsetScanLocation:メソッドで変更できる (エラーの後、一部の文字列を再度調べるために、このメソッドを使うこともあろう)。

スキャナをsetCharactersToBeSkipped:メソッドで、一組の文字をスキップするように構成することができる。 スキャナは、どんなスキャン活動の始めにでもスキップされる文字を無視する。 しかし、一旦それがスキャン可能な文字を見つけたら、それは要請に一致しているすべての文字を含む。
スキャナは、デフォルトで空白文字と改行復帰をスキップする。 大文字小文字がスキップされる文字に関しては常に考慮されることに注意すべきである。 たとえば、すべての英語の母音をスキップするために、文字列@"AEIOUaeiou"でスキップされる文字を設定しなければならない。

現在の場所から特定の文字列まで内容を読みたいならば、scanUpToString:intoString:を使う (あなたが単に間の文字をスキップしたいならば、第2の引数としてNULLを渡すことができる)。
たとえば、以下の文字列を与えられたとする。
137 small cases of bananas
あなたはコンテナの型とコンテナの数をscanUpToString:intoString:を使って調べることが出来る。 それは以下の例のようになる。
    NSString *bananas = @"137 small cases of bananas";
    NSString *separatorString = @" of";

    NSScanner *aScanner = [NSScanner scannerWithString:bananas];

    NSInteger anInteger;
    [aScanner scanInteger:&anInteger];
    NSString *container;
    [aScanner scanUpToString:separatorString intoString:&container];
検索文字列=separatorStringが" of"であることに注意しなければならない。 デフォルトで、スキャナは空白文字を無視するので、整数の後のスペース文字は無視される。 しかし、一旦スキャナが文字を集め始めるならば、検索文字列に達するまで、すべての文字は出力文字列に追加される。 このように、検索文字列が"of"(前にスペースがない)なら、最初のコンテナ値は"small cases "(後のスペースを含む)である。 検索文字列が" of"(前にスペースを含む)なら、最初のコンテナ値は"small cases"(後ろにスペースがない)である。

与えられた文字列でのスキャン終了後のスキャン位置は、その文字列の始まりである。 あなたがその文字列をスキップしてスキャンしたいならば、 スキャン終了した文字列を最初にスキャンしなければならない。

以下のプログラムは、前の例で検索文字列を通り越してスキップして、コンテナで製品のタイプを決定する方法を示している 文字列の終わりまでスキャンするsubstringFromIndex:の使い方に注意しなさい。
[aScanner scanString:separatorString intoString:NULL];
NSString *product = [[aScanner string] substringFromIndex:[aScanner scanLocation]];

// これも使える:
// product = [bananas substringFromIndex:[aScanner scanLocation]];

次のような文字列を含む行があるとする。
    Product: Acme Potato Peeler; Cost: 0.98 73
    Product: Chef Pierre Pasta Fork; Cost: 0.75 19
    Product: Chef Pierre Colander; Cost: 1.27 2
以下の例は、製品名(product names)と経費(costs)を引き抜くために、交互のスキャン活動を使う(経費は、単純化のため、floatと解釈する)。 そして、予想される部分文字列「Product:」と「Cost:」をセミコロン(;)と同様に飛ばす。 スキャナがデフォルトのによって空白文字と改行文字をスキップするので、 ループがそれらのために特別な処理をしていない点にも注目しなさい (特に、最終的な整数を取り出すためにさらなる空白文字処理をする必要がない)。
#define PRODUCT @"Product:"
#define COST    @"Cost:"

NSString *string = PRODUCT @" Acme Potato Peeler; "     COST " 0.98 73\n"
                   PRODUCT @" Chef Pierre Pasta Fork; " COST " 0.75 19\n"
                   PRODUCT @" Chef Pierre Colander; "   COST " 1.27 2\n";   // ここでは@文字列の結合を使っている

NSCharacterSet *semicolonSet;
NSScanner *theScanner;


NSString *productName;
float productCost;
NSInteger productSold;

semicolonSet = [NSCharacterSet characterSetWithCharactersInString:@";"];
theScanner   = [NSScanner scannerWithString:string];

while ([theScanner isAtEnd] == NO) {
    if ([theScanner scanString:PRODUCT intoString:NULL] &&
        [theScanner scanUpToCharactersFromSet:semicolonSet
            intoString:&productName] &&
        [theScanner scanString:@";" intoString:NULL] &&
        [theScanner scanString:COST intoString:NULL] &&
        [theScanner scanFloat:&productCost] &&
        [theScanner scanInteger:&productSold]
    ) {
        NSLog(@"Sales of %@: $%1.2f", productName, productCost * productSold);
    }
}

ローカライズ

スキャナは、スキャナーの振る舞いの一部をロケールに依存する。 それは、言語と値表記の慣例を指定する。 NSScannerは、10進セパレーターのためだけに、ロケールの定義を使う (NSDecimalSeparatorという名前のキーで与えられる)。
あなたはlocalizedScannerWithString:を使って、またはsetLocale:ではっきりとロケールを設定することでユーザーロケールのスキャナーを生成できる。 あなたがロケールを指定しないでメソッドを使うならば、スキャナはデフォルトのロケールを使う。

ファイルパスの文字列表現


NSStringはファイルシステムパスを表す文字列の操作のための豊富なメソッドを提供する。 あなたは、パスのディレクトリ、ファイル名と拡張子を抽出することができる。
チルダ式(例えば「~me」)を展開し、または、ユーザーのホームディレクトリのために1つをつくり、 シンボリックリンク、冗長なスラッシュ、そして“.” (カレントディレクトリ) と“..” (親ディレクトリ)への参照を解決する。

パスの説明

NSStringは'/'をパスセパレーターとして、'.'を拡張子セパレーターとして意味する。 文字列をパス引数と認めるメソッドは、必要に応じてこれらの一般的な表記を適当なシステムに特有の形式に変える。
暗黙のルートディレクトリによるシステム上で、絶対パスはパスセパレーターで始まるか、チルダ式(「~/...」または「~user/...」)で始める。 チルダはホームディレクトリを示す省略形である(多くの場合/Users/。iOSでは存在しないかも)

stringByStandardizingPathを使うことで、正規化表現されたパスを生成できる。 この実行は、いくつかの作業を含む。 たとえば以下のようになる。
NSString *path;
NSString *standardizedPath;

path = @"/usr/bin/./grep";
standardizedPath = [path stringByStandardizingPath];
// standardizedPath: /usr/bin/grep

path = @"~me";
standardizedPath = [path stringByStandardizingPath];
// standardizedPath /Users/me

path = @"/usr/include/objc/..";
standardizedPath = [path stringByStandardizingPath];
// standardizedPath: /usr/include

path = @"/private/usr/include";
standardizedPath = [path stringByStandardizingPath];
// standardizedPath: /usr/include

ユーザーディレクトリ

以下の例は、あなたがユーザーディレクトリを得るために、 NSStringのパス・ユーティリティと他のCocoa関数をどのように使用することができるかについて説明する。
NSString *meHome   = [@"~me"        stringByExpandingTildeInPath];
// meHome = @"/Users/me"

NSString *mePublic = [@"~me/Public" stringByExpandingTildeInPath];
// mePublic = @"/Users/me/Public"
あなたはカレントユーザーと与えられたユーザーのホームディレクトリをそれぞれ、NSHomeDirectoryとNSHomeDirectoryForUser で見つけることが出来る (iOSでは関係ないはず)
NSString *currentUserHomeDirectory = NSHomeDirectory();
NSString *meHomeDirectory = NSHomeDirectoryForUser(@"me");
一般的に、現在のユーザーのために標準的なディレクトリを見つけるためには、 関数NSSearchPathForDirectoriesInDomainsを使わなければならない。 たとえば、
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
の代わりにこれを使うべきである。
    NSString *documentsDirectory;
    NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    if ([path count] > 0) {
        documentsDirectory = [path objectAtIndex:0];
    }

パスの構成要素

NSStringは、ファイルシステム・パスを文字列として操作するために豊富なメソッドを提供する。
pathExtensionレシーバーの拡張子を返す
stringByDeletingPathExtensionレシーバーから拡張子を(存在すれば)削除することによって作られる新しい文字列を返す
stringByDeletingLastPathComponentレシーバーから最後のパス構成要素を削除することによって作られる新しい文字列を返す
ファイル名+拡張子を除いたパス名部分のみを返す
これらとNSStringのメソッドを使って、以下の例のように、パスのディレクトリ、ファイル名と拡張子を抽出することができる。
NSString *documentPath = @"~me/Public/Demo/readme.txt";

NSString *documentDirectory = [documentPath stringByDeletingLastPathComponent];
// documentDirectory = @"~me/Public/Demo"

NSString *documentFilename = [documentPath lastPathComponent];
// documentFilename = @"readme.txt"

NSString *documentExtension = [documentPath pathExtension];
// documentExtension = @"txt"

ファイル名補完

completePathIntoString:caseSensitive:matchesIntoArray:filterTypes: を使ってファイル名の拡張子を見つけることが出来る。 たとえば、ディレクトリ ~/Demo が以下のファイルを含むとする。
    ReadMe.txt
    readme.html
    readme.rtf
    recondite.txt
    test.txt
あなたは、"~/Demo/r"としての可能性あるファイルを見つけることができる。
NSString *partialPath = @"~/Demo/r";
NSString *longestCompletion;
NSArray *outputArray;

unsigned allMatches = [partialPath completePathIntoString:&longestCompletion
                                caseSensitive:NO 
                                matchesIntoArray:&outputArray 
                                filterTypes:NULL];

// allMatches = 3
// longestCompletion = @"~/Demo/re"
// outputArray = (@"~/Demo/readme.html", "~/Demo/readme.rtf","~/Demo/recondite.txt")
また、"~/Demo/r" で、拡張子“.txt”または“.rtf”を持つファイルを見つけることができる。
NSArray *filterTypes = [NSArray arrayWithObjects:@"txt", @"rtf", nil];
unsigned textMatches = [partialPath completePathIntoString:&outputName
                                caseSensitive:NO
                                matchesIntoArray:&outputArray
                                filterTypes:filterTypes];
// allMatches = 2
// longestCompletion = @"~/Demo/re"
// outputArray = (@"~/Demo/readme.rtf", @"~/Demo/recondite.txt")

参照


追加情報を得るには、以下の文書も参照しなさい。