24/7 twenty-four seven

iOS/OS X application programing topics.

iPhoneアプリで正規表現を使う

RegexKit Framework

上記のサイトからRegexKitLiteをダウンロードします。

RegexKitLite-2.2.tar.bz2を展開すると、以下のようになります。

  • RegexKitLite.h
  • RegexKitLite.m
  • RegexKitLite.html
  • examples
    • RKLMatchEnumerator.h
    • RKLMatchEnumerator.m
    • NSString-HexConversion.h
    • NSString-HexConversion.m
    • link_example.m
    • main.m

とりあえず、RegexKitLite.hとRegexKitLite.mの2つのファイルをコピーすれば一通りの正規表現は使えるようになります。

  1. RegexKitLite.h、RegexKitLite.mをプロジェクトにコピーする
  2. プロジェクトを選択し、ファイル>情報を見る>ビルド>リンク>他のリンカフラグに-licucoreを設定します。

基本的にNSStringとNSMutableStringのカテゴリとして作られているので、文字列のインスタンスに対して、メッセージを送信する形で使用します。

以下はドキュメントに載っている使い方の例です。

NSString *searchString      = @"This is neat.";
NSString *regexString       = @"\\b(\\w+)\\b";
NSString *replaceWithString = @"{$1}";
NSString *replacedString    = NULL;

replacedString = [searchString stringByReplacingOccurrencesOfRegex:regexString withString:replaceWithString];

NSLog(@"replaced string: '%@'", replacedString);
// 2008-07-01 19:03:03.195 test[68775:813] replaced string: '{This} {is} {neat}.'

繰り返しマッチさせるような場合には、Match Enumeratorを作成するようにとドキュメントには書いてありますが、exmplesディレクトリに同梱されているRKLMatchEnumeratorがそのまま使用できます。
以下はドキュメントに掲載のサンプルです。

#import <Foundation/NSAutoreleasePool.h>
#import "RegexKitLite.h"
#import "RKLMatchEnumerator.h"

int main(int argc, char *argv[]) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  NSString     *searchString    = @"one\ntwo\n\nfour\n";
  NSEnumerator *matchEnumerator = NULL;
  NSString     *regexString     = @"(?m)^.*$";

  NSLog(@"searchString: '%@'", searchString);
  NSLog(@"regexString : '%@'", regexString);

  matchEnumerator = [searchString matchEnumeratorWithRegex:regexString];

  NSUInteger  line          = 0;
  NSString   *matchedString = NULL;

  while((matchedString = [matchEnumerator nextObject]) != NULL) {
    NSLog(@"%d: %d '%@'", ++line, [matchedString length], matchedString);
  }

  [pool release];
  return(0);
}

RegexKitLiteはテレビ番組表iconで使用しています。

配信されるRSS本文中に新番組 ニュースこのようなアイコン表記が混ざっているので、imgタグからalt属性の値を取り出して、それを表示するという処理をしています。
具体的には下記のような処理になります。

<img src="/img/icon_new_b.gif" alt="新番組" width="13" height="13" /> → [新]
<img src="/img/icon_news_b.gif" alt="ニュース" width="13" height="13" /> → [N]

RegexKitLiteは基本機能のみのシンプルなライブラリなので、正規表現で一発というわけにはいかないのですが、これまでに述べた機能だけでも、重ねて使用することでこのような処理を実現できます。

NSString *details = [item objectForKey:@"description"];
if ([details length] > 0) {
	NSString *searchString = [details stringByHalfwideningLatinCharacters];
			
	NSEnumerator *matchEnumerator = NULL;
	NSString *regex = @"<img[^>]+alt=\"([^>]+)\"[^>]*>";
	matchEnumerator = [searchString matchEnumeratorWithRegex:regex];
	NSUInteger line = 0;
	NSString *matchedString = NULL;
	while((matchedString = [matchEnumerator nextObject]) != NULL) {
		NSString *imgTag = matchedString;
		NSMutableString *alt = [NSMutableString stringWithString:imgTag];
				
		NSString *replaceWithString = @"$1";
		NSUInteger replacedCount = [alt replaceOccurrencesOfRegex:regex withString:replaceWithString];
		if (replacedCount) {
			NSString *abbr = [abbreviationMappings objectForKey:alt];
			if (!abbr) {
				abbr = [NSString stringWithFormat:@"[%@]", alt];
			}
			searchString = [searchString stringByReplacingOccurrencesOfString:imgTag withString:abbr];
		}
		line++;
	}
	program.details = searchString;
}