Swift & Objective-C

Swift文字列の長さ:ハングル・絵文字・バイトを測る

Character、Unicode scalar、UTF-16、UTF-8を比較し、等価なハングルの辞書検索と、家族の絵文字を途中で切らない処理を検証します。

読了 3 分
Swift文字列の長さ:ハングル・絵文字・バイトを測るのカバー画像

文字数制限を実装する前に、数える単位を決めます。SwiftのcountはCharacter、つまり拡張書記素クラスタを数えますが、通信量制限は通常バイトです。見た目が同じ文字でも内部サイズは異なることがあります。

仕組みと設計の判断基準

実験のハングル音節は、合成済みスカラー一つ、または結合する字母スカラー三つで表せます。Swift Stringは正規等価性を考慮し、辞書検索でも同じキーとして扱います。家族の絵文字は複数スカラーで一つのCharacterを作る例です。他言語が別単位を数えること自体は誤りではありません。 一次資料

再現コード

Unicodeエスケープで入力を固定し、ハングル二形式のCharacter数、スカラー数、UTF-8バイト数を比較します。家族の絵文字のUTF-16とUTF-8も測り、AとBの間へ入れてprefixとString.Indexを使います。空文字列へのアクセスも別に検証します。

この独立したサンプルは2026-10-23に、arm64 macOS向けのApple Swift 6.4をSwift 6言語モードで実行しました。ネットワーク接続や追加パッケージは不要です。

Swiftファイル全体をダウンロード

ダウンロード先のフォルダーで実行してください。検証条件を満たさない場合はpreconditionで停止します。検証が削除されるため、-Ouncheckedは使用しないでください。

swift -swift-version 6 swift-string-grapheme-cluster-indexing.swift
let composed = "\u{D55C}"
let decomposed = "\u{1112}\u{1161}\u{11AB}"
precondition(composed == decomposed)
precondition(composed.count == 1 && decomposed.count == 1)
precondition(composed.utf8.count == 3 && decomposed.utf8.count == 9)
precondition(decomposed.unicodeScalars.count == 3)
let lookup = [composed: 42]
precondition(lookup[decomposed] == 42)

let family = "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}"
precondition(family.count == 1 && family.unicodeScalars.count == 7)
precondition(family.utf16.count == 11 && family.utf8.count == 25)
let text = "A" + family + "B"
precondition(text.count == 3 && String(text.prefix(2)) == "A" + family)
let second = text.index(after: text.startIndex)
precondition(String(text[second]) == family)
let empty = ""
precondition(empty.first == nil && empty.prefix(2).isEmpty)
print("hangul=characters:1,scalars:1/3,utf8:3/9 equal:true dictionary:42")
print("family=characters:1,scalars:7,utf16:11,utf8:25 prefix=2 empty=safe")

実行結果と読み取り方

hangul=characters:1,scalars:1/3,utf8:3/9 equal:true dictionary:42
family=characters:1,scalars:7,utf16:11,utf8:25 prefix=2 empty=safe

ハングルはどちらもCharacter一つですがUTF-8では3バイトと9バイトで、分解形はスカラー三つです。等価な辞書キーでは42を取得できました。家族の絵文字はCharacter一つ、スカラー7、UTF-16単位11、UTF-8バイト25でした。prefix(2)は絵文字を分断しません。

適用範囲と注意点

Characterが全言語で人間の考える一文字と完全一致するわけではありません。分割規則やUnicode版も関係します。表示上のハングルや絵文字を一律3バイトと計算できません。Swift Dictionaryのために常にNFC化が必要なわけではなく、外部との比較・符号化契約を確認します。

次に確認すること

サーバーとクライアントで文字数かUTF-8バイト数かを合意します。プレビューにはprefixなどCharacter単位のAPIを使います。ランダムアクセスを繰り返すなら配列化の費用とメモリを比較してください。未入力と空文字列の差はOptional実験へ続きます。

関連する実験

出典と確認基準