しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

Swiftでの絵文字判定について調べる

Swiftで文字列の中の絵文字を判定できないかを調べてみました。

結論

下のようにisEmojiPresentation、isEmojiModifier、isEmojiModifierBaseを使う事で判定できるようです。
各メソッドの内容は下部の調査内容に記載しました。

let inputText = "Some 🕵string 😂😂😂 with 👹👹 👹 emoji 🖐"
print(inputText.unicodeScalars.filter { !$0.properties.isEmojiPresentation && !$0.properties.isEmojiModifier && !$0.properties.isEmojiModifierBase }.reduce("", { $0 + String($1) })))

調査経緯

絵文字について調べたところisEmojiPresentationというメソッドがあったので試してみました。

Swift - Replacing emojis in a string with whitespace - Stack Overflow

Apple Developer Documentation

このメソッドを使って絵文字を除外してみました。
isEmojiPresentationはUnicode.Scalar.Propertiesクラスのメソッドなので文字列からPropertiesを取り出して再度結合する必要があります。

let inputText = "Some 🖐string 😂😂😂 with 👹👹 👹 emoji 🖐"
let textWithoutEmoij = inputText.unicodeScalars.filter { !$0.properties.isEmojiPresentation }.reduce("") { $0 + String($1) }
print(textWithoutEmoij)

結果は下の通りです。
🖐だけは除外することができませんでした。

f:id:llcc:20220207105126p:plain

除外できない原因を探る為、unicodeScalarsで取得したScalarを一つ一つ出力してみました。

let inputText = "Some 🖐string 😂😂😂 with 👹👹 👹 emoji 🖐"
inputText.unicodeScalars.forEach { print($0.properties) }

結果は下の通りです。
手の絵文字も正しく取得できているようでした。

f:id:llcc:20220207105349p:plain

良く分からないのでisEmojiPresentationのメソッドの説明を確認しました。
それによるとEmoji_Presentationに含まれる絵文字ならtrueになるようです。

A Boolean value indicating whether the scalar is one that should be rendered with an emoji presentation, rather than a text presentation, by default.

Scalars that have default to emoji presentation can be followed by U+FE0E VARIATION SELECTOR-15 to request the text presentation of the scalar instead. Likewise, scalars that default to text presentation can be followed by U+FE0F VARIATION SELECTOR-16 to request the emoji presentation.

This property corresponds to the "Emoji_Presentation" property in the [Unicode Standard](http://www.unicode.org/versions/latest/).

🖐はEmoji_Presentationにない可能性も考えてUnicodeのサイトを確認したのですが🖐は含まれていました。

Emoji Proposals, v14.0

f:id:llcc:20220207111310p:plain

🖐が異字体なこと(🖐🏾などのカラーバリエーションがある事)が原因の可能性も考えて他の異字体絵文字でも試してみました。

print("🕵".unicodeScalars)
print("🕵".unicodeScalars.first?.properties.isEmojiPresentation)

試した所、この絵文字もisEmojiPresentationで判別できない事が分かりました。
異字体はisEmojiPresentationを使った判別は難しいようです。

f:id:llcc:20220207114532p:plain

ドキュメント見ていた所、isEmojiModifierBaseとisEmojiModifierというメソッドがあったので動かしてみました。
検証コードは下の通りです。

print("😂".unicodeScalars)
print("😂".unicodeScalars.map { $0.properties.isEmojiPresentation })
print("😂".unicodeScalars.map { $0.properties.isEmojiModifier })
print("😂".unicodeScalars.map { $0.properties.isEmojiModifierBase })
print("🕵".unicodeScalars)
print("🕵".unicodeScalars.first?.properties.isEmojiPresentation)
print("🕵".unicodeScalars.map { $0.properties.isEmojiModifier })
print("🕵".unicodeScalars.map { $0.properties.isEmojiModifierBase })
print("🖐".unicodeScalars)
print("🖐".unicodeScalars.first?.properties.isEmojiPresentation)
print("🖐".unicodeScalars.map { $0.properties.isEmojiModifier })
print("🖐".unicodeScalars.map { $0.properties.isEmojiModifierBase })
print("🖐🏾".unicodeScalars)
print("🖐🏾".unicodeScalars.first?.properties.isEmojiPresentation)
print("🖐🏾".unicodeScalars.map { $0.properties.isEmojiModifier })
print("🖐🏾".unicodeScalars.map { $0.properties.isEmojiModifierBase })

結果は下の通りです。
異字体はisEmojiModifierBaseがtrueになっていました。
🖐🏾の結果を見た限り、異字体の色を決める部分はisEmojiModifierで判定できるようです。

f:id:llcc:20220207121409p:plain

上記メソッドを使って下のようにコードを修正しました。

let inputText = "Some 🕵string 😂😂😂 with 👹👹 👹 emoji 🖐"
print(inputText.unicodeScalars.filter { !$0.properties.isEmojiPresentation && !$0.properties.isEmojiModifier && !$0.properties.isEmojiModifierBase }.reduce("", { $0 + String($1) })))

動かしてみた所、すべての絵文字を除外できるようになりました。

f:id:llcc:20220207121224p:plain

余談ですがUnicode.Scalar.PropertiesにはisEmojiというメソッドもあります。
こちらは異字体も絵文字として判定するのですが、0などの絵文字以外も絵文字扱いしてしまうので使用しませんでした。

print("0".unicodeScalars.map { $0.properties.isEmojiPresentation }) // true