2013年10月3日木曜日

NSRegularExpressionで文字列を分解

この文字列は何を意味するのでしょうか?

20130925_172439

例えばこれが2013年9月25日17時24分39秒という意味だとして、その各数字を個別に読み取りたいとします。
方法はいろいろあると思いますが、今回は正規表現を使ってやってみます。

iOS、Mac OS Xの標準ライブラリに、NSRegularExpressionという正規表現クラスがあるので、それを利用します。


バックスラッシュはエスケープ

正規表現に使うパターンでバックスラッシュを使うものは、バックスラッシュをエスケープしてやらないと、ワーニングが出るので注意しましょう。

例えば、以下は数字にマッチするメタキャラクターですが、
\d
これをそのまま文字列に登録すると、Xcode上で以下のようにワーニングが表示されます。
pattern1.png

これは気持ち悪いので、バックスラッシュをバックスラッシュでエスケープしてやります。
pattern2.png

この通り、ワーニングは無くなりましたが、これはこれで気持ち悪いです。
普段、RubyやPerlなどで正規表現を使ってる人には、読みづらいかもしれません。

パターンを作るぞー

先の日付を分解して取得するための正規表現パターンを以下のようにします。
NSString *pattern = @"^(\\d{4})(\\d{2})(\\d{2})_(\\d{2})(\\d{2})(\\d{2})$";
^は行頭、$は行末を意味します。
\\dは数字を意味して、{数字}は直前の文字が何個続くかを意味します。なので、\\d{4}は4桁の数字という意味です。
そして、()で括った要素を、パターンがマッチした時に取得することができます。
メタキャラクターやオペレータの意味は、NSRegularExpressionのクラスリファレンスをご覧ください。

英語だとちょっと…という人には、こちらのサイトをオススメしておきます。
JavaScript用ですが、パターンの意味は同じです。

NSRegularExpressionをインスタンス化

先のpattern変数を使用して、NSRegularExpressionオブジェクトのインスタンスを作成します。
ARCを使用していない場合は、autoreleaseなどを忘れずに。
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:nil];

これでやっと文字列をマッチングさせる準備が整いました。
正直、パターン毎にインスタンスオブジェクトを生成するコードを書くのは面倒なので、慣れてきたらこれらの処理を適当にラッピング化してしまうことをオススメします。

文字列をマッチングさせて、要素ごとの文字列を取得するサンプルコードは以下のようになります。
NSString *string = @"20130925_172439";

NSTextCheckingResult *match = [regex firstMatchInString:string options:0 range:NSMakeRange(0,[string length])];
if (match) {
    int memCnt = match.numberOfRanges;
    NSLog(@"記憶された要素の数 = %d",memCnt);
            
    NSRange matchRange = [match range];
    NSLog(@"マッチした範囲 = (%u,%u)",matchRange.location,matchRange.length);

    NSLog(@"記憶した要素:");
    for (int i=0 ; i<memCnt ; ++i) {
        NSRange range = [match rangeAtIndex:i];
        NSString *memStr = [string substringWithRange:range];
        NSLog(@" %d: %@",i,memStr);
    }
}

firstMatchInString:options:range:メソッドは、指定した文字列とパターンがマッチするかチェックして、マッチしたらNSTextCheckingResultオブジェクトを返します。
複数マッチする可能性があるパターンを使用する場合は、matchesInString:options:range:メソッドの方が便利でしょう。

結果ログは、以下のように出力されます。
最初の要素は、マッチした文字列全体が入ります。
記憶された要素の数 = 7
マッチした範囲 = (0,15)
記憶した要素:
 0: 20130925_172439
 1: 2013
 2: 09
 3: 25
 4: 17
 5: 24
 6: 39
string変数に、わざとマッチしない文字列を入れてみるなどして、動作の理解を深めて下さい。

関連記事

0 件のコメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...