Skip to content

Commit

Permalink
Detect if grapheme is an emoji
Browse files Browse the repository at this point in the history
This adds the necessary logic to detect if a grapheme cluster is an
emoji based on @rivo's [comment](rivo#27 (comment))

Fixes: rivo#27
  • Loading branch information
aymanbagabas committed May 30, 2024
1 parent 087b3e4 commit 2a7cd3a
Showing 1 changed file with 65 additions and 0 deletions.
65 changes: 65 additions & 0 deletions grapheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ func (g *Graphemes) Bytes() []byte {
return []byte(g.cluster)
}

// IsEmoji returns true if the current grapheme cluster is an emoji.
func (g *Graphemes) IsEmoji() bool {
return IsGraphemeClusterEmoji([]byte(g.cluster), g.Width())
}

// Positions returns the interval of the current grapheme cluster as byte
// positions into the original string. The first returned value "from" indexes
// the first byte and the second returned value "to" indexes the first byte that
Expand Down Expand Up @@ -343,3 +348,63 @@ func FirstGraphemeClusterInString(str string, state int) (cluster, rest string,
}
}
}

const (
regionalIndicatorA = 0x1F1E6
regionalIndicatorZ = 0x1F1FF
)

// IsGraphemeClusterEmoji returns true if the given byte slice grapheme cluster
// and width is an emoji according to the Unicode Standard Annex #51, Unicode
// Emoji.
func IsGraphemeClusterEmoji(cluster []byte, width int) bool {
if width != 2 {
return false
}

for i := 0; len(cluster) > 0; i++ {
r, rw := utf8.DecodeRune(cluster)
if i == 0 {
if r >= regionalIndicatorA && r <= regionalIndicatorZ {
return true
}
if propertyGraphemes(r) == prExtendedPictographic &&
property(emojiPresentation, r) == prEmojiPresentation {
return true
}
}
if r == vs16 {
return true
}
cluster = cluster[rw:]
}

return false
}

// IsGraphemeClusterInStringEmoji is like [IsGraphemeClusterEmoji] but its input
// is a string.
func IsGraphemeClusterInStringEmoji(cluster string, width int) bool {
if width != 2 {
return false
}

for i := 0; len(cluster) > 0; i++ {
r, rw := utf8.DecodeRuneInString(cluster)
if i == 0 {
if r >= regionalIndicatorA && r <= regionalIndicatorZ {
return true
}
if propertyGraphemes(r) == prExtendedPictographic &&
property(emojiPresentation, r) == prEmojiPresentation {
return true
}
}
if r == vs16 {
return true
}
cluster = cluster[rw:]
}

return false
}

0 comments on commit 2a7cd3a

Please sign in to comment.