酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

iOSで半角から全角へ変換したり、ローマ字からひらがなに変換したりする

id:alzaが少し前に半角カナを全角カナに変換する。 - アルザえもんの手記のような記事を書いているのを思い出しました。

それぞれのコードで同じ処理を書くのは面倒ですし、変数transformと変数reverseの組み合わせで「カタカナからひらがな」なのか「ひらがなからカタカナ」なのか、少し判断に迷いバグを混入してしまいそうです。他のプロジェクトでも使えるようにNSString型を拡張してカテゴリで実装してみました。あとはこのソースコードを取り込めばNSDateの拡張機能が使えるという寸法です。

CFMutableString Referenceを読む限りでは、CFStringTransform関数以外にも便利そうな関数がありましたので、こちらの方も追々フォローできれば良いかなと考えています。

id:alzaが変換に使用していたCFStringTransform関数は以下のようになっています。

Perform in-place transliteration on a mutable string.

Boolean CFStringTransform (
   CFMutableStringRef string,
   CFRange *range,
   CFStringRef transform,
   Boolean reverse
);

第3引数のtransformには、以下の既定の定義を指定し、第4引数にてどちらからどちらへの変換かを指定します。

const CFStringRef kCFStringTransformStripCombiningMarks;
const CFStringRef kCFStringTransformToLatin;
const CFStringRef kCFStringTransformFullwidthHalfwidth;
const CFStringRef kCFStringTransformLatinKatakana;
const CFStringRef kCFStringTransformLatinHiragana;
const CFStringRef kCFStringTransformHiraganaKatakana;
const CFStringRef kCFStringTransformMandarinLatin;
const CFStringRef kCFStringTransformLatinHangul;
const CFStringRef kCFStringTransformLatinArabic;
const CFStringRef kCFStringTransformLatinHebrew;
const CFStringRef kCFStringTransformLatinThai;
const CFStringRef kCFStringTransformLatinCyrillic;
const CFStringRef kCFStringTransformLatinGreek;
const CFStringRef kCFStringTransformToXMLHex;
const CFStringRef kCFStringTransformToUnicodeName;
const CFStringRef kCFStringTransformStripDiacritics;

日本語で関係ありそうなのは以下の4つでしょうか。

kCFStringTransformFullwidthHalfwidth 全角⇔半角
kCFStringTransformHiraganaKatakana ひらがな⇔カタカナ
kCFStringTransformLatinHiragana ローマ字⇔ひらがな
kCFStringTransformLatinKatakana ローマ字⇔カタカナ

NSString+Henkan.h

//
//  NSString+Henkan.h
//  
//
//  Created by Kenji Wada ( http://ch3cooh.jp/ ) on 12/06/19.
//  Copyright (c) 2012 Softbuild. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSString (NSString_Henkan)

// 半角→全角
- (NSString*) stringToFullwidth;

// 全角→半角
- (NSString*) stringToHalfwidth;

// カタカナ→ひらがな
- (NSString*) stringKatakanaToHiragana;

// ひらがな→カタカナ
- (NSString*) stringHiraganaToKatakana;

// ひらがな→ローマ字
- (NSString*) stringHiraganaToLatin;

// ローマ字→ひらがな
- (NSString*) stringLatinToHiragana;

// カタカナ→ローマ字
- (NSString*) stringKatakanaToLatin;

// ローマ字→カタカナ
- (NSString*) stringLatinToKatakana;

@end

NSString+Henkan.m

//
//  NSString+Henkan.m
//  
//  Created by Kenji Wada ( http://ch3cooh.jp/ ) on 12/06/19.
//  Copyright (c) 2012 Softbuild. All rights reserved.
//

#import "NSString+Henkan.h"

@implementation NSString (Henkan)

- (NSString*) stringTransformWithTransform:(CFStringRef)transform reverse:(Boolean)reverse {
    NSMutableString* retStr = [[NSMutableString alloc] initWithString:self];
    CFStringTransform((CFMutableStringRef)retStr, NULL, transform, reverse);
    return [retStr autorelease];
}

- (NSString*) stringToFullwidth {
    return [self stringTransformWithTransform:kCFStringTransformFullwidthHalfwidth 
                                      reverse:true];
}

- (NSString*) stringToHalfwidth {
    return [self stringTransformWithTransform:kCFStringTransformFullwidthHalfwidth 
                                      reverse:false];
}

- (NSString*) stringKatakanaToHiragana {
    return [self stringTransformWithTransform:kCFStringTransformHiraganaKatakana
                                      reverse:true];
}

- (NSString*) stringHiraganaToKatakana {
    return [self stringTransformWithTransform:kCFStringTransformHiraganaKatakana
                                      reverse:false];
}

- (NSString*) stringHiraganaToLatin {
    return [self stringTransformWithTransform:kCFStringTransformLatinHiragana
                                      reverse:true];
}

- (NSString*) stringLatinToHiragana {
    return [self stringTransformWithTransform:kCFStringTransformLatinHiragana
                                      reverse:false];
}

- (NSString*) stringKatakanaToLatin {
    return [self stringTransformWithTransform:kCFStringTransformLatinKatakana
                                      reverse:true];
}

- (NSString*) stringLatinToKatakana {
    return [self stringTransformWithTransform:kCFStringTransformLatinKatakana
                                      reverse:false];
}

@end

テストコード

//
//  unittest_string.m
//  
//  Created by Kenji Wada ( http://ch3cooh.jp/ ) on 12/06/19.
//  Copyright (c) 2012 Softbuild. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <SenTestingKit/SenTestingKit.h>
#import "NSString+Henkan.h"

@interface unittest_string : SenTestCase
@end

#pragma mark -

@implementation unittest_string

- (void)testFullToHalf {
    NSString* temp = @"アイウエオ";
    NSString* result = [temp stringToHalfwidth];
    STAssertTrue([result isEqualToString:@"アイウエオ"] , @"result:%@ is not アイウエオ.", result);
}

- (void)testHalfToFull {
    NSString* temp = @"アイウエオ";
    NSString* result = [temp stringToFullwidth];
    STAssertTrue([result isEqualToString:@"アイウエオ"] , @"result:%@ is not アイウエオ.", result);
}

- (void)testKanaToHira {
    NSString* temp = @"アイウエオ";
    NSString* result = [temp stringKatakanaToHiragana];
    STAssertTrue([result isEqualToString:@"あいうえお"] , @"result:%@ is not あいうえお.", result);
}

- (void)testHiraToKana {
    NSString* temp = @"あいうえお";
    NSString* result = [temp stringHiraganaToKatakana];
    STAssertTrue([result isEqualToString:@"アイウエオ"] , @"result:%@ is not アイウエオ.", result);
}

- (void)testRomajiToHira {
    NSString* temp = @"aiueo";
    NSString* result = [temp stringLatinToHiragana];
    STAssertTrue([result isEqualToString:@"あいうえお"] , @"result:%@ is not あいうえお.", result);
}

- (void)testHiraToRomaji {
    NSString* temp = @"あいうえお";
    NSString* result = [temp stringHiraganaToLatin];
    STAssertTrue([result isEqualToString:@"aiueo"] , @"result:%@ is not aiueo.", result);
}

- (void)testRomajiToKana {
    NSString* temp = @"aiueo";
    NSString* result = [temp stringLatinToKatakana];
    STAssertTrue([result isEqualToString:@"アイウエオ"] , @"result:%@ is not アイウエオ.", result);
}

- (void)testKanaToRomaji {
    NSString* temp = @"アイウエオ";
    NSString* result = [temp stringKatakanaToLatin];
    STAssertTrue([result isEqualToString:@"aiueo"] , @"result:%@ is not aiueo.", result);
}

@end