text/emoji/detect.go
Functions
func IsBlackFlag
func IsBlackFlag(r rune) bool {
return r == 0x1F3F4
}
func IsCancelTag
IsCancelTag returns true for the cancel tag character (U+E007F).
This terminates subdivision flag sequences.
func IsCancelTag(r rune) bool {
return r == 0xE007F
}
func IsCombiningEnclosingKeycap
IsCombiningEnclosingKeycap returns true for the keycap combining mark.
func IsCombiningEnclosingKeycap(r rune) bool {
return r == 0x20E3
}
func IsEmoji
IsEmoji returns true if the rune is an emoji character.
This includes characters with Emoji_Presentation=Yes or that are
commonly used as emoji with variation selector.
func IsEmoji(r rune) bool {
return isEmojiPresentation(r) || isEmojiComponent(r) || isTextPresentationEmoji(r)
}
func IsEmojiModifier
IsEmojiModifier returns true if the rune is a skin tone modifier.
Fitzpatrick scale modifiers: U+1F3FB - U+1F3FF.
func IsEmojiModifier(r rune) bool {
return r >= 0x1F3FB && r <= 0x1F3FF
}
func IsEmojiModifierBase
IsEmojiModifierBase returns true if the rune can be modified by a skin tone.
This includes humans, body parts, and human activities.
func IsEmojiModifierBase(r rune) bool {
// Common emoji modifier bases
switch {
// People and body parts
case r >= 0x1F466 && r <= 0x1F469: // Boy, Girl, Man, Woman
return true
case r >= 0x1F46E && r <= 0x1F478: // Police, Guard, etc.
return true
case r >= 0x1F47C && r <= 0x1F47C: // Baby Angel
return true
case r >= 0x1F481 && r <= 0x1F487: // Information Desk, etc.
return true
case r >= 0x1F4AA && r <= 0x1F4AA: // Flexed Biceps
return true
case r >= 0x1F574 && r <= 0x1F575: // Man in Suit, Detective
return true
case r >= 0x1F57A && r <= 0x1F57A: // Man Dancing
return true
case r >= 0x1F590 && r <= 0x1F590: // Hand with Fingers Splayed
return true
case r >= 0x1F595 && r <= 0x1F596: // Middle Finger, Vulcan
return true
case r >= 0x1F645 && r <= 0x1F64F: // Gestures and Person
return true
case r >= 0x1F6A3 && r <= 0x1F6A3: // Rowing
return true
case r >= 0x1F6B4 && r <= 0x1F6B6: // Cycling, Walking
return true
case r >= 0x1F6C0 && r <= 0x1F6C0: // Bath
return true
case r >= 0x1F918 && r <= 0x1F91F: // Hand signs
return true
case r >= 0x1F926 && r <= 0x1F926: // Face Palm
return true
case r >= 0x1F930 && r <= 0x1F939: // Pregnancy, etc.
return true
case r >= 0x1F93C && r <= 0x1F93E: // Wrestling, etc.
return true
// Hands from dingbats range
case r >= 0x261D && r <= 0x261D: // Index Pointing Up
return true
case r >= 0x26F9 && r <= 0x26F9: // Person Bouncing Ball
return true
case r >= 0x270A && r <= 0x270D: // Fists, Writing Hand
return true
}
return false
}
func IsEmojiPresentation
IsEmojiPresentation returns true if the rune defaults to emoji presentation.
These characters display as emoji without requiring U+FE0F.
func IsEmojiPresentation(r rune) bool {
return isEmojiPresentation(r)
}
func IsEmojiVariation
IsEmojiVariation returns true for the emoji variation selector (U+FE0F).
func IsEmojiVariation(r rune) bool {
return r == 0xFE0F
}
func IsKeycapBase
IsKeycapBase returns true if the rune can form a keycap emoji.
Digits 0-9, # and * can be followed by U+FE0F U+20E3 to form keycaps.
func IsKeycapBase(r rune) bool {
return (r >= '0' && r <= '9') || r == '#' || r == '*'
}
func IsRegionalIndicator
IsRegionalIndicator returns true if the rune is a Regional Indicator (A-Z).
Two regional indicators form a flag emoji (e.g., U+1F1FA U+1F1F8 = US flag).
func IsRegionalIndicator(r rune) bool {
return r >= 0x1F1E6 && r <= 0x1F1FF
}
func IsTagCharacter
IsTagCharacter returns true for emoji tag characters.
Tags U+E0020-U+E007E are used in subdivision flag sequences.
func IsTagCharacter(r rune) bool {
return r >= 0xE0020 && r <= 0xE007E
}
func IsTextPresentation
IsTextPresentation returns true for the text variation selector (U+FE0E).
func IsTextPresentation(r rune) bool {
return r == 0xFE0E
}
func IsVariationSelector
IsVariationSelector returns true for emoji-related variation selectors.
U+FE0E forces text presentation, U+FE0F forces emoji presentation.
func IsVariationSelector(r rune) bool {
return r == 0xFE0E || r == 0xFE0F
}
func IsZWJ
IsZWJ returns true if the rune is Zero-Width Joiner (U+200D).
ZWJ is used to join emoji into composite sequences.
func IsZWJ(r rune) bool {
return r == 0x200D
}
func Segment
Segment splits text into emoji and non-emoji runs.
ZWJ sequences and other multi-codepoint emoji are kept together.
Flag sequences (regional indicators) are combined.
Keycap sequences are combined.
Tag sequences are combined.
func Segment(text string) []Run {
if text == "" {
return nil
}
runes := []rune(text)
if len(runes) == 0 {
return nil
}
runs := make([]Run, 0, 4)
byteOffsets := computeByteOffsets(text, runes)
i := 0
for i < len(runes) {
// Try to parse a complete emoji sequence
emojiLen, codepoints := parseEmojiSequence(runes[i:])
if emojiLen > 0 {
// Found an emoji sequence
run := Run{
Text: text[byteOffsets[i]:byteOffsets[i+emojiLen]],
IsEmoji: true,
Codepoints: codepoints,
Start: byteOffsets[i],
End: byteOffsets[i+emojiLen],
}
runs = appendOrMergeRun(runs, run)
i += emojiLen
} else {
// Regular text character
run := Run{
Text: text[byteOffsets[i]:byteOffsets[i+1]],
IsEmoji: false,
Start: byteOffsets[i],
End: byteOffsets[i+1],
}
runs = appendOrMergeRun(runs, run)
i++
}
}
return runs
}
Structs
type Run struct
Run represents a contiguous run of text with uniform emoji status.
type Run struct {
// Text is the substring of the run.
Text string
// IsEmoji is true if this run contains emoji characters.
// For ZWJ sequences, this will be a single Run with multiple codepoints.
IsEmoji bool
// Codepoints contains the individual runes for emoji runs.
// For non-emoji runs, this is nil.
Codepoints []rune
// Start is the byte offset in the original string.
Start int
// End is the byte offset of the end (exclusive).
End int
}
IsBlackFlag returns true for the black flag emoji.
This is the base for subdivision flag sequences.