NSAttributedStringで簡易シンタックスハイライト - エピソードII

本日の動機

( ^o^)<シンタックスハイライトできたお

|Xcode|┗(☋` )┓三

( ◠‿◠ )☛あんなものでごまかしたつもりか

▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂うわあああああ


……というわけで、今回はここまでやってみました。端末上でそれっぽくテキストを色分けできている事がおわかり頂けるかと思います。

f:id:tercel_s:20130211223945p:plain

ソースコードが少し複雑になってしまったため、今回はコメント部を緑にする方法だけご紹介します。

つまり、 /**/ で囲まれた部分と、// 以降の文字列をハイライト表示するというのが今回の要件です。

前回との決定的な違いは、ハイライト表示したい文字列が固定的ではないという点です。

実装

実装方針は前回とほぼ一緒で、ViewController クラスの実装部にコーディングしていきます。

@implementation ViewController {
    @private NSMutableArray *comments;
}

少し違うのは、検索に正規表現を使用している点です。これによって、文字列からコメント部を柔軟に判別する事ができるようになります。

- (id)initWithNibName:(NSString *)nibNameOrNil
               bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil
                           bundle:nibBundleOrNil];
    if(self) {
        comments = [[NSMutableArray alloc] initWithObjects:
                    @"/\\*/?([^/]|[^*]/)*\\*/", // 「/* … */」にマッチする正規表現
                    @"//.*",                    // 「// …」にマッチする正規表現
                    nil];
    }   
    return self;
}

そのため、rangeOfString: options: range: メソッドにも NSRegularExpressionSearch正規表現検索)を指定しています。

- (NSAttributedString *)getHighlightedString:(NSString *)str
{
    NSMutableAttributedString *attributedString;
    attributedString = [[NSMutableAttributedString alloc] initWithString:str];
    
    for(NSString *comment in comments) {
        NSRange textSearchRange = NSMakeRange(0, str.length);
        NSRange range;
        do {
            range = [str rangeOfString: comment
                               options: NSRegularExpressionSearch
                                 range: textSearchRange];
            
            if(range.location != NSNotFound) {
                [attributedString addAttribute:NSForegroundColorAttributeName
                                         value:[UIColor colorWithRed:0.0
                                                               green:0.5
                                                                blue:0.0
                                                               alpha:1.0]
                                         range:NSMakeRange(range.location,
                                                           range.length)];
                
                textSearchRange = NSMakeRange(NSMaxRange(range),
                                              str.length - NSMaxRange(range));
            }
        } while (range.location != NSNotFound && range.length > 0);
    }
    return attributedString;
}

最後に、テスト用の文字列を適当に渡してやります。

- (void)viewDidLoad
{
    [super viewDidLoad];

    // テスト用の文字列
    NSString *str = @"/* *****************************   \n"
                     "   Hello World を表示するプログラム   \n"
                     "   ***************************** */\n"
                     "\n"
                     "#include <stdio.h> \n"
                     "\n"
                     "int main (int argc, char *argv[])\n"
                     "{\n"
                     "    printf (\"Hello world.\\n\");  // 出力\n"
                     "    return 0;\n"
                     "}\n";
    
    [textView setAttributedText:[self getHighlightedString:str]];
}

以上、めでたしめでたし。

眠いので寝ます。

Copyright (c) 2012 @tercel_s, @iTercel, @pi_cro_s.