suggest_side_quests skill v1 #100
@@ -314,28 +314,37 @@ func drop(q SideQuest, regulars regularNames, known *harness.Deduper, kept []Sid
|
|||||||
|
|
||||||
// named returns the Regulars text names, by one rule. A mention of a
|
// named returns the Regulars text names, by one rule. A mention of a
|
||||||
// Regular is a place where text spells its name, ignoring case and spacing,
|
// Regular is a place where text spells its name, ignoring case and spacing,
|
||||||
// with the name's own outer punctuation optional ("Easy Beef Chili!" is
|
// with no letter, mark or digit just outside it: the start or end of text,
|
||||||
// mentioned by "Easy Beef Chili." too) and no letter or digit just outside
|
// white space, punctuation or a symbol must border it, so "Beef
|
||||||
// it: the start or end of text, white space or punctuation must border it,
|
// Chili-inspired" and "Beef Chili's" mention "Beef Chili" while "Beef
|
||||||
// so "Beef Chili-inspired" and "Beef Chili's" mention "Beef Chili" while
|
// Chilis" does not, nor does "Cafe" with a combining accent after it
|
||||||
// "Beef Chilis" does not. A mention names its Regular unless a mention of a
|
// mention "Cafe". Punctuation at either end of the name, with any spacing
|
||||||
// different Regular covers the same text or more, so "Your Easy Beef
|
// beside it, is optional, and a mention takes it in only where text spells
|
||||||
// Chili." names "Easy Beef Chili" and not "Beef Chili", and text that two
|
// it and the border still holds after it: "Easy Beef Chili!" is mentioned
|
||||||
// Regulars spell alike names neither there.
|
// by "Easy Beef Chili." too, and by "Easy Beef Chili!x" without its "!". A
|
||||||
|
// combining mark is part of its letter, never punctuation. A mention names
|
||||||
|
// its Regular unless a mention of a different Regular covers the same text
|
||||||
|
// or more, so "Your Easy Beef Chili." names "Easy Beef Chili" and not "Beef
|
||||||
|
// Chili", and text that two Regulars spell alike names neither there.
|
||||||
func (r regularNames) named(text string) []string {
|
func (r regularNames) named(text string) []string {
|
||||||
type mention struct {
|
type mention struct {
|
||||||
name string
|
name string
|
||||||
start, end int
|
start, end int
|
||||||
}
|
}
|
||||||
text = exactName(text)
|
text = exactName(text)
|
||||||
|
bordered := func(start, end int) bool {
|
||||||
|
before, _ := utf8.DecodeLastRuneInString(text[:start])
|
||||||
|
after, _ := utf8.DecodeRuneInString(text[end:])
|
||||||
|
return (start == 0 || !isWord(before)) && (end == len(text) || !isWord(after))
|
||||||
|
}
|
||||||
var mentions []mention
|
var mentions []mention
|
||||||
for _, name := range r.all {
|
for _, name := range r.all {
|
||||||
full := exactName(name)
|
full := exactName(name)
|
||||||
core := strings.TrimFunc(full, isNotWord)
|
core := strings.TrimFunc(full, isOuter)
|
||||||
if core == "" {
|
if core == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lead := full[:len(full)-len(strings.TrimLeftFunc(full, isNotWord))]
|
lead := full[:len(full)-len(strings.TrimLeftFunc(full, isOuter))]
|
||||||
trail := full[len(lead)+len(core):]
|
trail := full[len(lead)+len(core):]
|
||||||
for at := 0; ; {
|
for at := 0; ; {
|
||||||
i := strings.Index(text[at:], core)
|
i := strings.Index(text[at:], core)
|
||||||
@@ -344,15 +353,13 @@ func (r regularNames) named(text string) []string {
|
|||||||
}
|
}
|
||||||
start, end := at+i, at+i+len(core)
|
start, end := at+i, at+i+len(core)
|
||||||
at = start + 1
|
at = start + 1
|
||||||
before, _ := utf8.DecodeLastRuneInString(text[:start])
|
if !bordered(start, end) {
|
||||||
after, _ := utf8.DecodeRuneInString(text[end:])
|
|
||||||
if (start > 0 && !isNotWord(before)) || (end < len(text) && !isNotWord(after)) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(text[:start], lead) {
|
if strings.HasSuffix(text[:start], lead) && bordered(start-len(lead), end) {
|
||||||
start -= len(lead)
|
start -= len(lead)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(text[end:], trail) {
|
if strings.HasPrefix(text[end:], trail) && bordered(start, end+len(trail)) {
|
||||||
end += len(trail)
|
end += len(trail)
|
||||||
}
|
}
|
||||||
mentions = append(mentions, mention{name, start, end})
|
mentions = append(mentions, mention{name, start, end})
|
||||||
@@ -370,5 +377,9 @@ func (r regularNames) named(text string) []string {
|
|||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
// isNotWord reports whether c is neither a letter nor a digit.
|
// isWord reports whether c is a letter, a mark on one or a digit.
|
||||||
func isNotWord(c rune) bool { return !unicode.IsLetter(c) && !unicode.IsDigit(c) }
|
func isWord(c rune) bool { return unicode.IsLetter(c) || unicode.IsMark(c) || unicode.IsDigit(c) }
|
||||||
|
|
||||||
|
// isOuter reports whether c may be left off the end of a name: punctuation
|
||||||
|
// or white space.
|
||||||
|
func isOuter(c rune) bool { return unicode.IsPunct(c) || unicode.IsSpace(c) }
|
||||||
|
|||||||
@@ -252,6 +252,11 @@ func TestSuggestSideQuestsReasonMentionRule(t *testing.T) {
|
|||||||
"punctuation-only difference": {[]string{"Beef Chili!"}, "Your Beef Chili! over corn chips.", "Beef Chili!", ""},
|
"punctuation-only difference": {[]string{"Beef Chili!"}, "Your Beef Chili! over corn chips.", "Beef Chili!", ""},
|
||||||
"bare name inside punctuated": {[]string{"Beef Chili!"}, "Your Beef Chili! over corn chips.", "Beef Chili", none},
|
"bare name inside punctuated": {[]string{"Beef Chili!"}, "Your Beef Chili! over corn chips.", "Beef Chili", none},
|
||||||
"spelled alike by both": {[]string{"Beef Chili!"}, "Corn chips under your Beef Chili.", "Beef Chili", none},
|
"spelled alike by both": {[]string{"Beef Chili!"}, "Corn chips under your Beef Chili.", "Beef Chili", none},
|
||||||
|
"punctuation then a letter": {[]string{"Beef Chili!"}, "Your Beef Chili!X is our inspiration.", "Beef Chili!", none},
|
||||||
|
"letter before punctuation": {[]string{"¡Beef Chili"}, "Your X¡Beef Chili is our inspiration.", "¡Beef Chili", none},
|
||||||
|
"stored symbol left off": {[]string{"Green Chili 🌶"}, "Like your Green Chili, gone green.", "Green Chili 🌶", none},
|
||||||
|
"stored accent left off": {[]string{"Chicken Cafe\u0301"}, "Like your Chicken Cafe, gone green.", "Chicken Cafe\u0301", none},
|
||||||
|
"accent written after name": {[]string{"Chicken Cafe"}, "Like your Chicken Cafe\u0301, gone green.", "Chicken Cafe", none},
|
||||||
} {
|
} {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
in := household
|
in := household
|
||||||
|
|||||||
Reference in New Issue
Block a user