LoginSignup
12
13

More than 5 years have passed since last update.

swiftで絵文字や半角文字が正しくカウントされない場合

Last updated at Posted at 2015-11-26

NSString.lengthを使おう

CoreText内部ではNSStringが使われている(と思う)ので、CoreTextと文字数を一致させるには、
NSString.lengthを使うとよさそうです。
逆に、表示されてる文字数ベースであれば、String.characters.countで良さそうです。
hiragramさんご指摘ありがとうございました。

試してみよう

以下のコードをplaygroundで実行してみる

func lengthPrint(str: String) {
    print("------: 1234567890123456789012345678901234567890")
    print("String: \(str)")
    print("Length: String(\(str.characters.count)) NSString(\(NSString(string: str).length))")
}

lengthPrint("​・゜゚・​:.。..。.:​・'(*゚▽゚​)'・:.。. .。.:​・゜゚・*​")
lengthPrint("😊")
lengthPrint("あ")

出力結果はこんな感じです。

------: 1234567890123456789012345678901234567890
String: ​・゜゚・​:.。..。.:​・'(*゚▽゚​)'・:.。. .。.:​・゜゚・*​
Length: String(38) NSString(42)
------: 1234567890123456789012345678901234567890
String: 😊
Length: String(1) NSString(2)
------: 1234567890123456789012345678901234567890
String: あ
Length: String(1) NSString(1)

一見String.CharacterView.countの方が正しそうです。
しかし、playgroundのコードを修正するために、Backwordで消そうとすると、NSString.lengthの文字列としてカウントされます。iOS上でも同様。絵文字はサロゲートペアでNSString.length=2と解釈されそうですが、キタワァーの顔文字は。。うーむ。。

顔文字の方は不可視の文字が入っていたためカウントが違っていたようです。wakufactoryさんご指摘ありがとうございました。

不可視文字

見えない文字にまったく考えが至らずトンチンカンな記事を書いてしまいましたので、さらに掘り下げたいと思います。

・゜゚・​:.。..。.:​・'(*゚▽゚​)'・:.。. .。.:​・゜゚・*

について、ASCII範囲外はcodePointで出してみました。

\u{200B}\u{FF65}\u{309C}\u{FF9F}\u{FF65}\u{200B}:.\u{FF61}..\u{FF61}.:\u{200B}\u{FF65}\'(*\u{FF9F}\u{25BD}\u{FF9F}\u{200B})\'\u{FF65}:.\u{FF61}. .\u{FF61}.:\u{200B}\u{FF65}\u{309C}\u{FF9F}\u{FF65}*\u{200B}

このU+200BがZERO WIDTH SPACEで不可視文字です。

そして、こうしてみると、NSStringはUTF-16については、codePointをカウントしてそうです。

エンコーディングの闇が深い。。。

12
13
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
12
13