package util import ( "regexp" "strings" ) // Flag detection rules: [regex, emoji]. // Per review-resolution #16: Go RE2 supports \p{Regional_Indicator} and \uFE0F. var flagRules []flagRule type flagRule struct { re *regexp.Regexp emoji string } func init() { rules := []struct { pattern string emoji string }{ {`香港|港|hong\s*kong|\bhk\b`, "🇭🇰"}, {`台湾|台灣|taiwan|\btw\b`, "🇹🇼"}, {`新加坡|狮城|獅城|singapore|\bsg\b`, "🇸🇬"}, {`日本|东京|東京|大阪|japan|tokyo|osaka|\bjp\b`, "🇯🇵"}, {`美国|美國|洛杉矶|洛杉磯|纽约|紐約|united\s*states|los\s*angeles|new\s*york|\bus\b|\busa\b`, "🇺🇸"}, {`英国|英國|伦敦|倫敦|united\s*kingdom|london|\buk\b`, "🇬🇧"}, {`德国|德國|法兰克福|法蘭克福|germany|frankfurt|\bde\b`, "🇩🇪"}, {`韩国|韓國|首尔|首爾|korea|seoul|\bkr\b`, "🇰🇷"}, } for _, r := range rules { re, err := regexp.Compile("(?i)" + r.pattern) if err != nil { continue } flagRules = append(flagRules, flagRule{re: re, emoji: r.emoji}) } } // DetectFlag returns the flag emoji for a name, or 🏳️ if no match. func DetectFlag(name string) string { text := strings.ToLower(name) for _, rule := range flagRules { if rule.re.MatchString(text) { return rule.emoji } } return "🏳️" } // removeFlagRe matches leading flag emoji sequences and whitespace. // Regional Indicator letters are U+1F1E6–U+1F1FF; ZWJ is U+200D; VS16 is U+FE0F. var removeFlagRe = regexp.MustCompile(`^[\x{1F1E6}-\x{1F1FF}\x{FE0F}\x{200D}\s]+`) // RemoveFlag strips leading flag emoji and whitespace from a name. // Per review-resolution #16: handles ZWJ (\u200D) and variation selector (\uFE0F). func RemoveFlag(name string) string { cleaned := removeFlagRe.ReplaceAllString(name, "") // Also strip leading 🏳️ cleaned = strings.TrimLeft(cleaned, "🏳️ ") return strings.TrimSpace(cleaned) } // NormalizeTaiwanFlag maps the Taiwan flag to different flags based on `tw` mode. // Per review-resolution #19: three modes — ws/tw/default. func NormalizeTaiwanFlag(flag, mode string) string { if flag != "🇹🇼" { return flag } switch mode { case "ws": return "🇼🇸" case "tw": return "🇹🇼" default: return "🇨🇳" } } // IsASCII checks if a string contains only ASCII characters. func IsASCII(s string) bool { for i := 0; i < len(s); i++ { if s[i] > 127 { return false } } return true }