21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Objective-Cで絵文字入りの文字列の長さを取得する

Last updated at Posted at 2015-04-15

はじめに

Objective-Cでは文字列はNSStringを利用し、その長さを取得するにはlengthメソッドを使うのが一般的です。
ですが、これだと昨今頻繁に使われている絵文字などが混在した場合に"見た目通りの"長さが取得できません。

NSString *text = @"あ🌟い🐶う🐱え✪お☆";
NSLog(@"length: %@", @(text.length));
//=> length: 13

絵文字入りの場合はenumerateSubstringsInRangeを使う

絵文字が混在している場合はenumerateSubstringsInRangeNSStringEnumerationByComposedCharacterSequencesオプションで利用することで"見た目通りの"長さが取得できます。

NSStringのカテゴリとしてメソッドとプロパティを定義してあげると使いやすいと思います。

ヘッダー
#import <Foundation/Foundation.h>

@interface NSString (GraphemeLength)

/**
 *  人間の見た目通りの文字数を返す。
 *  絵文字などNSStringのlengthでは2文字扱いになってしまう文字を含む文字列向け。
 */
@property (assign, nonatomic, readonly) NSInteger graphemeLength;

/**
 *  人間の見た目通りの文字数を返す。
 *  絵文字などNSStringのlengthでは2文字扱いになってしまう文字を含む文字列向け。
 *
 *  @return 見た目通りの文字数
 */
- (NSInteger)graphemeLength;

@end
実装
#import "NSString+GraphemeLength.h"

@implementation NSString (GraphemeLength)

- (NSInteger)getGraphemeLength {
    return [self graphemeLength];
}

- (NSInteger)graphemeLength {
    __block NSInteger length = 0;
    
    [self enumerateSubstringsInRange:NSMakeRange(0, [self length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock: ^(NSString* substring, NSRange substringRange, NSRange enclosingRange, BOOL* stop) {
                                length++;
                            }];
    
    return length;
}

@end

使用例

NSString *text = @"あ🌟い🐶う🐱え✪お☆";
NSLog(@"length: %@", @(text.graphemeLength));
//=> length: 10

追記

コメント欄にてご指摘がありました。
NSStringEnumerationByComposedCharacterSequences は一部の絵文字(国旗の絵文字(🇯🇵など))は2文字としてカウントしてしまうため、上記の方法では完全にSwiftのcountメソッド(Swift1.1ではcountElements関数、Swift1.2ではcount関数)と同等の結果は得られないようです。

追記(2016/11/18)

こちらの記事を読んでいて気づいたのですが、現状仕様が変わっているようです。

Swift3.0で絵文字かどうかを判定するスマートな方法を考えた

NSStringEnumerationByComposedCharacterSequences を利用した場合、🇯🇵や👩‍👩‍👧‍👦なども1文字としてカウントするようになっていました。

また、当時試していなかったのですが、少なくともSwift 3.0では、👩‍👩‍👧‍👦は characters.count で4文字とカウントされるようです。

おまけ

SwiftではcountElementscountで一発です・ω・
追記したとおり、👩‍👩‍👧‍👦など、1文字としてカウントされない絵文字があります。

Swift1.1
let text = "あ🌟い🐶う🐱え✪お☆";
println("length: \(countElements(text))")
//=> length: 10
Swift1.2
let text = "あ🌟い🐶う🐱え✪お☆";
println("length: \(count(text))")
//=> length: 10
Swift2.1
let text = "あ🌟い🐶う🐱え✪お☆";
print("length: \(text.characters.count)")
//=> length: 10
21
19
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?