SwiftのString
は真剣にunicodeを扱っているらしく、大変難しいです。
参考:Swift の文字列の長さ - Qiita
部分文字列(ex:「アイウエオ」の「イウエ」)の取得も例外ではありません。Swift4までのやり方とは変わってしまい、調べてもなかなか出てこないのでメモしておきます。
追記
よく考えるとこれが一番スマートでした。返ってくるのはSubString
でパフォーマンス上のメリットもありそうです。
let string = "✨💪🥺✨"
let partialString = string[string.index(string.startIndex, offsetBy: 1)...string.index(string.startIndex, offsetBy: 2)]
print(partialString) //"💪🥺"
本文
まず、求めるのは「i
番目の文字からj
番目の文字まで」とします。例えばi=1, j=3
でstring = "アイウエオ"
ならばpartialString = イウエ
となります。
以下は誤りです。
let partialString = [String.Index(utf16Offset: i, in: string)...String.Index(utf16Offset: j, in: string)]
私は最初うっかりしてこの方法を使っていたのですが、これだと次のような例でバグが起こります。
let string = "✨💪🥺✨"
let partialString = [String.Index(utf16Offset: 1, in: string)...String.Index(utf16Offset: 2, in: string)]
print(partialString) //"💪"
なぜこうなってしまうのかというと、utf16Offset
としっかり書いてある通り、あくまでここで得ているIndex
はutf16
でのものだからです。実際
print("✨💪🥺✨".utf16.count) //6
なので、納得のいく結果でした。
確実に文字数単位で取り出したいときは、一度文字ごとに分割してから改めて次のようにします。
let string = "✨💪🥺✨"
let partialString = String(string.map{$0}[1...2])
print(partialString) //"💪🥺"
なかなか危ないところなので気をつけましょう。