[iOS] NSString

2016.02.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

NSStringは、文字列を扱う標準のクラスです。

NSString内の文字列は、一旦、作成されるとその内容を変更することはできません。 生成後に、その内容を変更したい場合は、NSMutableStringクラスを使います。

文字列オブジェクトは、内部的には、Unicode文字列の配列として表現されており、lengthメソッドで文字数、characterAtIndex:メソッドで、特定の文字を取得することができます。 そして、この2つの「プリミティブ」メソッドが、文字列オブジェクト操作の基本となっています。

以下、いろいろな場面に向けて用意されているプロパティやメソッドを列挙してみます。

2 操作

(1) @記法

C言語の文字列のように、" "で包み、先頭に@をつけることで、NSStringオブジェクトを生成する記法が用意されています。 そして、これが、最も簡単なNSStringオブジェクトの生成方法だと思います。

NSString *name = @"Taro Yamamoto";

(2) C文字列との相互変化

文字コードがUTF−8で、最後に¥0となている、C言語タイプの文字列との相互変換は、次のようになります。

// C言語文字列からNSStringを生成
// - (instancetype)initWithUTF8String:(const char *)bytes

NSString *name = [[NSString alloc] initWithUTF8String:"Taro Yamamoto"];

// NSStirngからC言語を生成
// @property(readonly) const char *UTF8String

const char *p = [name UTF8String];

(3) 長さ(文字数)

オブジェクトに含まれる文字数を取得するには、lengthプロパティが利用されます。(バイト数や表示幅には利用できません)

// 長さを取得する
// @property(readonly) NSUInteger length

NSString *name = @"Taro Yamamoto";
int len = [name length]; // len = 13

(4) 文字の取得

指定した位置の文字を取得する。なお、取得した文字は、charでは無く、unichar型です。

// 指定位置の文字取得
// - (unichar)characterAtIndex:(NSUInteger)index

NSString *name = @"Taro Yamamoto";
//インデックス2の文字を取得する
unichar c = [name characterAtIndex:2]; // 'r'

3 文字列コードの変換

NSStringとは、文字列やバイト列と相互にエンコード・デコードが可能です。 そして、この際の文字コードの種類の指定には、NSStringEncoding型が定義されており、主なものに次のようなものがあります。

NSASCIIStringEncoding   // 7bit ASCIIエンコーディング
NSMacOSRomanStringEncoding  // Classic Macintosh Romanエンコーディング
NSUTF8StringEncoding // UTF-8エンコーディング
NSJapaneseEUCStringEncoding // 日本語8bit EUCエンコーディング
NSShiftJISStringEncoding // 日本語8bit Shift-JISエンコーディング

(1) NSString <- C文字列 

指定した文字コードで、最後が¥0となっている、C言語タイプの文字列からの生成です。

// 文字コードを指定したC文字列からの生成
// - (instancetype)initWithCString:(const char *)nullTerminatedCString
//                       encoding:(NSStringEncoding)encoding


NSString *str0 = [[NSString alloc] initWithCString:"あいうえお" encoding:NSUTF8StringEncoding];

// 文字コードを指定したC文字列からの生成(コンビニエンスコンストラク)
// + (instancetype)stringWithCString:(const char *)cString
//                       encoding:(NSStringEncoding)enc

NSString *str1 = [NSString stringWithCString:"かきくけこ" encoding:NSUTF8StringEncoding];

(2) NSString -> C文字列

続いて、指定した文字コードで、C言語タイプの文字列を生成です。 指定した文字コードに変換できなかった場合は、例外となります。

// C文字列の生成
// - (const char *)cStringUsingEncoding:(NSStringEncoding)encoding

NSString *str = @"さしすせそ";
printf("%s\n", [str cStringUsingEncoding:NSUTF8StringEncoding]);

(3) NSStirng <- バイト列

バイト列(NSData)からの生成です。

// NSDataからの生成
// - (instancetype)initWithData:(NSData *)data
//                 encoding:(NSStringEncoding)encoding

const char* s = "12345";
NSData *data = [NSData dataWithBytes:s length:5 ];
NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

// バイト列からの生成(バイト数指定)
// - (instancetype)initWithBytes:(const void *)bytes
//                     length:(NSUInteger)length
//                   encoding:(NSStringEncoding)encoding

const char* data = "12345";
NSString *str = [[NSString alloc] initWithBytes:data length:5 encoding:NSUTF8StringEncoding];

(4) NSString -> バイト列

指定した文字コードでエンコードされたNSDataを生成します。 変換できない場合、nilとなります。

// NSDataの生成
// - (NSData *)dataUsingEncoding:(NSStringEncoding)encoding

NSString *str = @"たちつてと";
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];

// エンコード後のバイト数の取得
// - (NSUInteger)lengthOfBytesUsingEncoding:(NSStringEncoding)enc

NSUInteger *len = [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];

(5) エンコードの可否判定

指定した文字コードへの変換が可能かどうかを判定します。

// エンコードの可否判定
// - (BOOL)canBeConvertedToEncoding:(NSStringEncoding)encoding

NSString *str = @"abcde";
BOOL isAscii = [str canBeConvertedToEncoding:NSASCIIStringEncoding];

(6) パーセント符号化

指定した文字コードにしたがって、URL文字列表現で使用するパーセント符号化します。

// パーセント符号化
// - (NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding

NSString* inputString = @"http://www.exsample.com/index.php?data=テスト";
NSString* encodeString = [inputString
                              stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//@"http://www.exsample.com/index.php?data=%E3%83%86%E3%82%B9%E3%83%88"

// パーセント符号化から戻す
// - (NSString *)stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)encoding

NSString *outputString = [encodeString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

4 書式指定による文字列作成

NSStringでは、書式文字列を使用した文字列の生成が可能です。 なお、書式文字列自体もNSStringです。

// 書式文字列によるNSStringの生成
// - (instancetype)initWithFormat:(NSString *)format

NSInteger n = 100000000;
NSString *str0 = [[NSString alloc]initWithFormat:@"文字列:%ld", n];


// 書式文字列によるNSStringの生成(コンビニエンスコンストラクタ)
// + (instancetype)stringWithFormat:(NSString *)format

NSString *str1 = [NSString stringWithFormat:@"文字列; %ld",n];

C言語と違って、%@ と言う書式指定子がありますが、これは、引数にオブジェクト(NSObject)を取り、そのオブジェクトにdescriptionというメッセージを送って、受け取っとNSStringが、そこに挿入されます。

5 比較

比較の結果として返されるNSComparisonResultは、次の3つの値をとる列挙型です。

NSComparisonResult result = [ str1 compare : str2];
switch (result) {
    case NSOrderedAscending:
        NSLog(@"小さい (-1)");
        break;
    case NSOrderedSame:
        NSLog(@"等しい (0)");
        break;
    case NSOrderedDescending:
        NSLog(@"大きい (1)");
        break;
}

(1) 文字列の比較

// 文字列の比較
// - (NSComparisonResult)compare:(NSString *)aString

NSString* str1 = @"abc";
NSString* str2 = @"efd";

NSComparisonResult result = [ str1 compare : str2];
// result = NSOrderedAscending(小さい)

(2) 英文字の大文字・小文字を区別しないで比較

// 英数大文字・小文字を区別しない比較
// - (NSComparisonResult)caseInsensitiveCompare:(NSString *)aString

NSString* str1 = @"abc";
NSString* str2 = @"ABC";

NSComparisonResult result = [str1 caseInsensitiveCompare:str2];
// result = NSOrderedSame(等しい)

(3) 等しいかどうか

// 文字列が等しいかどうかの判定
// - (BOOL)isEqualToString:(NSString *)aString

NSString* str1 = @"abc";
NSString* str2 = @"ABC";

BOOL resutl = [str1 isEqualToString:str2];
// result = NO

(4) 先頭・末尾と一致するかどうか

// 先頭一致判定
// - (BOOL)hasPrefix:(NSString *)aString
// 末尾一致判定
// - (BOOL)hasSuffix:(NSString *)aString

NSString* str = @"abcdefg";

BOOL result0 = [str hasPrefix:@"abc"];  // 文字列が"abc"から始まる場合TRUE
BOOL result1 = [str hasSuffix:@"efg"];  // 文字列が"efg"で終わる場合TRUE


// 先頭から比較して一致した部分を返す
// - (NSString *)commonPrefixWithString:(NSString *)aString
//                             options:(NSStringCompareOptions)mask

NSString *result2 = [str commonPrefixWithString:@"abc" options:NSLiteralSearch];
// result2 = "abc"

最後のcommonPrefixWithStringで使用されたNSStringCompareOptionsには、以下のような指定が可能です。

  • NSCaseInsensitiveSearch 1 大文字と小文字を区別しない
  • NSLiteralSearch 2 完全一致
  • NSBackwardsSearch 4 文末から検索
  • NSAnchoredSearch 8 検索で最初にヒットした文字を拾う(NSBackwardsSearchでは最後)

commonPrefixWithStringでは、文字列の途中からの比較はできません。

6 結合

結合は、対象オブジェクトの後ろに追加する形で利用されます。

// 後ろに文字列を追加して、新しい文字列を生成する
// - (NSString *)stringByAppendingString:(NSString *)aString

NSString* str1 = @"abc";
NSString* str2 = @"ABC";

NSString *str3 = [str1 stringByAppendingString:str2];
// str3 = @"abcABC"

// 後ろに書式文字列を追加して、新しい文字列を生成する
// - (NSString *)stringByAppendingFormat:(NSString *)format
// , ...

int n = 100;
NSString *str4 = [str1 stringByAppendingFormat:@"%ld",n];
// str4 = @"abc100"

7 部分文字列

指定した部分の文字列を切り出すことができます。

// 先頭から指定したインデックスまでの文字列を切りだす
// - (NSString *)substringToIndex:(NSUInteger)anIndex

NSString *str0 = [@"あいうえお" substringToIndex:3];
// str0 = @"あいう"

// 指定したインデックスから最後までの文字列を切りだす
// - (NSString *)substringFromIndex:(NSUInteger)anIndex

NSString *str1 = [@"あいうえお" substringFromIndex:3];
// str1 = @"えお"

// 指定した範囲の文字列を切りだす
// - (NSString *)substringWithRange:(NSRange)aRange

NSString *str3 = [@"あいうえお" substringWithRange:NSMakeRange(1,3)];
//str3 = @"いうえ"

8 分割

セパレータ文字列を指定して、文字列を分割します。

// 指定した文字列で分割する
// - (NSArray<NSString *> *)componentsSeparatedByString:(NSString *)separator

NSString *str = @"abc:def:ghi";
NSArray *arr = [str componentsSeparatedByString:@":"];
// arr[0] = @"abc"
// arr[1] = @"def"
// arr[2] = @"ghi"

複数の文字をセパレータに指定することもできます。

// セパレータ文字を指定して分割する
// - (NSArray<NSString *> *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator

NSString *str = @"https://dev.classmethod.jp/";
NSCharacterSet *spr = [NSCharacterSet characterSetWithCharactersInString:@".:/"];
NSArray *arry = [str componentsSeparatedByCharactersInSet:spr];
// arry[0] = "http"
// array[1] = ""
// array[2] = ""
// array[3] = "dev"
// array[4] = "classmethod"
// array[5] = "jp"
// array[6] = ""

セパレータとして指定する文字セットは、予め用意されているものを使用することもできます。

9 検索

文字列の中から、パターンを検出することができます。 そして、多数の問題解決が、この検索の機能を応用することで実現可能になります。

(1) パターン検出

// 文字列の中で、どこに同じパターンがあるかを検索する
// - (NSRange)rangeOfString:(NSString *)aString


// 文字列の中に@"BBB"というパターンが存在するかどうか
NSRange searchResult = [@"AAABBBCCC" rangeOfString: @"BBB"];
if(searchResult.location == NSNotFound){
    // 見つからない
}else{
    // searchResult = location=3, length=3 
    // 3文字目から3文字の場所に見つかった
}

(2) 条件付パターン検出

rangeOfStringによる検索は、オプション指定して、使用することもできます。

// 文字列の中で、どこに同じパターンがあるかを検索する(オプション指定あり)
// - (NSRange)rangeOfString:(NSString *)aString
//                 options:(NSStringCompareOptions)mask

// 大文字小文字を区別せずに検索する
NSRange searchResult = [@"AAABBBCCC" rangeOfString:@"bbb" options:NSCaseInsensitiveSearch];
if(searchResult.location == NSNotFound){
    // 見つからない
}else{

    // searchResult = location=3, length=3 
    // 3文字目から3文字の場所に見つかった
}

(3) 行分割

指定した範囲を含んだ行を返すメソッドがあります。 これを利用すると、複数の行を1行づつ順番に取得することができます。

// 指定した範囲を含む行の範囲を返す
// - (NSRange)lineRangeForRange:(NSRange)aRange

// 1行ずつ読み出す
NSString *lines = @"AAA\nBBB\nCCC\nDDD\n";
NSUInteger lineEnd = 0;
while (lineEnd < [lines length])
{
    NSRange currentRange = [lines lineRangeForRange:NSMakeRange(lineEnd, 0)];
    NSString *currentLine = [lines substringWithRange:currentRange];
    lineEnd = currentRange.location + currentRange.length;
}

(4) 正規表現

検索では、オプションにNSRegularExpressionSearchを指定して、正規表現を使用することもできます。 次の例は、正規表現を使用して、3桁の数値が含まれているかどうかを確認しています。

//3つの連続した数値を表現する正規表現
NSString* expression = @"[0-9]{3}";
NSRange range = [@"aaabbbccc628ddd" rangeOfString:expression options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
    NSLog(@"3桁の数値が含まれている");
}

10 置換

// 指定した範囲を指定した文字列で置き換える
// - (NSString *)stringByReplacingCharactersInRange:(NSRange)range
//                                      withString:(NSString *)replacement

// 3文字目から5文字を"x"で置き換える
NSString *str = [@"123456789" stringByReplacingCharactersInRange:NSMakeRange(3,5) withString:@"x"];
// str = @"123x9"
// 指定したパターンを指定した文字列で置き換える 
// - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target

// "," を全て "-" に置き換える
NSString *hoge = @"0,1,2,3,4";
NSString *str = [hoge stringByReplacingOccurrencesOfString: @"," withString: @"-"];

// str = @"0-1-2-3-4"

11 大文字・小文字化

英文字を全て、大文字にしたり、小文字にしたりします。

NSString *str0 = @"AbCDEfg";

// 英文字を全て小文字にする
// @property(readonly, copy) NSString *lowercaseString

NSString *str1 = [str0 lowercaseString];
// str1 = "abcdefg"

// 英文字を全て大文字にする
// @property(readonly, copy) NSString *uppercaseString

NSString *str2 = [str0 uppercaseString];
// str1 = "ABCDEFG"

12 型へのキャスト

それそれの型へ変換します。 評価の際に文字列の先頭に含まれる空白は無視されます。

なお、boolValueに関しては、先頭文字がY,y,T,tのいづれか、または、、先頭に0以外の10進数がある場合に、YESを返します。

int i = [@"123" intValue];
double d = [@"0.1" doubleValue];
float f = [@"0.1" floatValue];
NSInteger n = [@"123" integerValue];
bool b = [@"true" boolValue];

13 ファイルパスからファイル名や拡張子への変換

フルパスから必要な文字列を取得する要領は、次の通りです。

NSString *path = [NSString stringWithFormat:@"user/local/sample.txt"];
NAString *fileName = [path lastPathComponent];  // sample.txt
NSString *directory = [path stringByDeletingLastPathComponent]; // user/local
NSString *extension = [fileName pathExtension]; // txt

14 最後に

NSStringは、非常に高機能で、多くのプロパティやメソッドがあります。 全てを列挙するのは難しいのですが、とりあえず、困らない程度に、使えるものを列挙できたかと思います。

文字列操作プログラミングガイド - Apple Developer