Hatena::Groupiphone-dev

iOS プログラミングメモ

2013-08-09 (Fri)

[] NSStringの文字列比較はisEqualToStringではなくてcompareメソッドがいいのか 16:52  NSStringの文字列比較はisEqualToStringではなくてcompareメソッドがいいのか - iOS プログラミングメモ を含むブックマーク

Appleのサンプルコード DownloadFont を眺めてたら、NSStringの文字列比較にcompare:メソッドを使っていて「あれisEqualToStringじゃないの?」って思ったので調べてみたら意外と重大な事実が判明しました。isEqualToStringはNSLiteralSearchオプションによる比較なので、見かけ上同じ文字列だったとしてもバイト列が異なる場合はNOを返すらしい。うはー、こんな基本的なことを知らなかったとか恥ずかしいです。

たとえば以下のコードの場合ですとisEqualToStringは通りませんが、compare:はNSOrderedSameを返すので真になります。

NSString *stringA = @"\343\203\221\343\202\272\343\203\211\343\203\251";
NSString *stringB = @"\343\203\217\343\202\232\343\202\271\343\202\231\343\203\210\343\202\231\343\203\251";

if([stringA isEqualToString:stringB]) NSLog(@"isEqualToString");
if([stringA compare:stringB] == NSOrderedSame) NSLog(@"compare");

stringAが「パズドラ」という文字で、stringBは濁点と半濁点が分離した文字になっています。Macのファイルシステムで使われてる UTF-8-MAC がこの分離文字を扱ってるので、結構おなじみかもしれません。

そういえば拙作の SkyBook でも、内蔵ストレージに保存した濁点付きの文字列の比較がうまくいかなくて困った経験がありました。その時は分離した文字列をくっつけるように変換して対処しましたが、compare:使うのが正解だったのか!!

参考までにSkyBookでやったやり方はこちら。

NSString *stringA = @"\343\203\221\343\202\272\343\203\211\343\203\251";
NSString *stringB = @"\343\203\217\343\202\232\343\202\271\343\202\231\343\203\210\343\202\231\343\203\251";

NSMutableString *stringC = [NSMutableString stringWithString:stringB];
CFStringNormalize((CFMutableStringRef)stringC, kCFStringNormalizationFormC);

if([stringA isEqualToString:stringC]) NSLog(@"great!!");

これだとgreat!!と出力されます。