文字列から辞典で使うような「インデックス文字」を取得する

この記事の二番煎じです。
[文字列からあ行など取得する](http://qiita.com/SolaRayLino/items/b29b1fbe0c4377823a43)
ちょっと調べたら面白かったので、記事にまとめてみました。

## 仕様

* 「あ〜わ」、もしくは、「A〜Z」の見出し文字を返す
* 先頭の文字から、インデックス文字が見つかるまで探索する
* 見出し文字が含まれていない場合には空文字@""を返す
* NSStringのカテゴリとして実装

## ソース

```objc:NSString+BTKIndexString.h
#import <Foundation/Foundation.h>

@interface NSString (BTKIndexString)

- (NSString*) btkIndexString;

@end
```

```objc:NSString+BTKIndexString.m
#import "NSString+BTKIndexString.h"

@implementation NSString (BTKIndexString)

- (NSString*) btkIndexString
{
    for(int i = 0; i < self.length; i++){
        // Upper Case Letter
        NSMutableString *keyStr = [self substringWithRange:NSMakeRange(i, 1)].uppercaseString.mutableCopy;
        // Full Witdh -> Half Width
        CFStringTransform((CFMutableStringRef)keyStr, NULL, kCFStringTransformFullwidthHalfwidth, FALSE);
        // Katakana -> Hiragana
        CFStringTransform((CFMutableStringRef)keyStr, NULL, kCFStringTransformHiraganaKatakana, TRUE);

        unichar uc = [keyStr characterAtIndex:0];
        switch (uc) {
            // Alphabets
            case L'A':
            case L'B':
            case L'C':
            case L'D':
            case L'E':
            case L'F':
            case L'G':
            case L'H':
            case L'I':
            case L'J':
            case L'K':
            case L'L':
            case L'M':
            case L'N':
            case L'O':
            case L'P':
            case L'Q':
            case L'R':
            case L'S':
            case L'T':
            case L'U':
            case L'V':
            case L'W':
            case L'X':
            case L'Y':
            case L'Z':
                return keyStr.copy;
            
            // Hiragana Characters
            // http://www.unicode.org/charts/PDF/U3040.pdf
            case L'ぁ':
            case L'あ':
            case L'ぃ':
            case L'い':
            case L'ぅ':
            case L'う':
            case L'ぇ':
            case L'え':
            case L'ぉ':
            case L'お':
                return @"あ";
            case L'か':
            case L'が':
            case L'き':
            case L'ぎ':
            case L'く':
            case L'ぐ':
            case L'け':
            case L'げ':
            case L'こ':
            case L'ご':
                return @"か";
            case L'さ':
            case L'ざ':
            case L'し':
            case L'じ':
            case L'す':
            case L'ず':
            case L'せ':
            case L'ぜ':
            case L'そ':
            case L'ぞ':
                return @"さ";
            case L'た':
            case L'だ':
            case L'ち':
            case L'ぢ':
            case L'っ':
            case L'つ':
            case L'づ':
            case L'て':
            case L'で':
            case L'と':
            case L'ど':
                return @"た";
            case L'な':
            case L'に':
            case L'ぬ':
            case L'ね':
            case L'の':
                return @"な";
            case L'は':
            case L'ば':
            case L'ぱ':
            case L'ひ':
            case L'び':
            case L'ぴ':
            case L'ふ':
            case L'ぶ':
            case L'ぷ':
            case L'へ':
            case L'べ':
            case L'ぺ':
            case L'ほ':
            case L'ぼ':
            case L'ぽ':
                return @"は";
            case L'ま':
            case L'み':
            case L'む':
            case L'め':
            case L'も':
                return @"ま";
            case L'ゃ':
            case L'や':
            case L'ゅ':
            case L'ゆ':
            case L'ょ':
            case L'よ':
                return @"や";
            case L'ら':
            case L'り':
            case L'る':
            case L'れ':
            case L'ろ':
                return @"ら";
            case L'ゎ':
            case L'わ':
            case L'ゐ':
            case L'ゑ':
            case L'を':
            case L'ん':
                return @"わ";
            case L'ゔ':
                return @"う";
                
            // Small Letters
            case L'ゕ':
            case L'ゖ':
                return @"か";
                
            // Katakana Phonetic Extensions
            // http://www.unicode.org/charts/PDF/U31F0.pdf
            case L'ㇰ':
                return @"か";
            case L'ㇱ':
            case L'ㇲ':
                return @"さ";
            case L'ㇳ':
                return @"た";
            case L'ㇴ':
                return @"な";
            case L'ㇵ':
            case L'ㇶ':
            case L'ㇷ':
            case L'ㇸ':
            case L'ㇹ':
                return @"は";
            case L'ㇺ':
                return @"ま";
            case L'ㇻ':
            case L'ㇼ':
            case L'ㇽ':
            case L'ㇾ':
            case L'ㇿ':
                return @"ら";
            default:
                continue;
        }
    }
    return @"";
}

@end

```

###実行結果
```text
abc -> A
アイスクリーム -> あ
☆ほし☆ -> は
ヴォーカル -> う
ㇰ -> か
```

## 豆知識
### unicharの定義
ソース内にあるように、Lをつけることで日本語等のunicharもそのまま定義できます。

### ユニコードの並び順
「ゕ」(3095)、「ゖ」(3096)は、「ん」(3093)、「ゔ」(3094)の後ろにあります。
今回のSwitch文はコード順に並べているので、同じインデックス文字が複数回現れている部分があります。

### 実はひらがなよりカタカナの方が多い
http://www.taishukan.co.jp/kokugo/webkoku/series003_03.html
アイヌ語対応の関係で、対応するひらがなのないカタカナがあります。
これはカタカナ->ひらがな変換で変換されないので、そのままSwitch文に追加してあります。

### パフォーマンス
パフォーマンスが重要なら、CFStringTransformを使わずに全部switch caseに列挙した方が良さそう。
サンプルコードじゃなくて、ライブラリとして作るならそっちかな。