こんにちは、Sleipnir for Mac 開発担当の宮本です。
先ほど、CFStringFind を使うと文字列検索が速いよという記事を書いたのですが、速さの違いはオプションによるもののようです。
Twitter での、開発者さんたちの反応でわかりました。勉強になります!
rangeOfString:options: には NSLiteralSearch というオプションが、CFStringFindWithOptions には kCFCompareNonliteral というオプションがあります。
それぞれ逆のことを意味するオプションがあって、デフォルト値が逆になっているわけです。
(rangeOfString:Options:) + (NSLiteralSearch) = (CFStringFind)
(rangeOfString:) = (CFStringFindWithOptions) + (kCFCompareNonliteral)
といった感じでしょうか。
NSLiteralSearch を指定したらなぜ速いのか
日本語であれば、濁点/半濁点付の文字で問題があります。
「が」という文字は、「が」単体と、(「か」と「゛(濁点)」)との組み合わせで表現する合成文字の2種類が存在します。
NSString の rangeOfString: は、デフォルトでこの2種類を同等のものとして検索してくれます。一方、NSLiteralSearch を指定するか、CFStringFind を使うと byte ごとに比較するようになり、別のものとして扱われます。この違いだけで、8倍もの差が生まれてしまうわけです。
日本語だけでなく、ウムラウト記号が付く場合にもこの影響を受けます。リファレンスで kCFCompareNonliteral の説明に書いてあります。
オプションを合わせたときのパフォーマンスの違い
確認してみると、CFStringFind のほうが 1.05倍ほど速いぐらいの違いはありますが、ほとんど同じパフォーマンスです。
大文字小文字を区別、かつ非リテラルサーチをする場合は、あまりにもパフォーマンスに違いがあります。
パフォーマンスが重要な箇所では、合成文字を無視して NSLiteralSearch してしまうのも一つの手ですね。
まとめ
- ・NSLiteralSearch かどうかで 8 倍ほどの違いがでてしまう
- ・パフォーマンスが重要な場合は、合成文字を無視するのもアリ
- ・オプションはよく調べよう!!