Ignore spacing beside a Regular's outer punctuation in a mention
A mention took in a stored name's leading or trailing punctuation only where the text repeated the stored spacing exactly, although the rule says spacing is ignored. With Regulars "Beef Chili !" and "Chili!", the reason "Like your Beef Chili!" left the first mention at "Beef Chili", so a citation of "Chili!" passed. Match the punctuation with any spacing beside it, then apply the same border check to the extended mention. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -320,8 +320,9 @@ func drop(q SideQuest, regulars regularNames, known *harness.Deduper, kept []Sid
|
|||||||
// Chilis" does not, nor does "Cafe" with a combining accent after it
|
// Chilis" does not, nor does "Cafe" with a combining accent after it
|
||||||
// mention "Cafe". Punctuation at either end of the name, with any spacing
|
// mention "Cafe". Punctuation at either end of the name, with any spacing
|
||||||
// beside it, is optional, and a mention takes it in only where text spells
|
// beside it, is optional, and a mention takes it in only where text spells
|
||||||
// it and the border still holds after it: "Easy Beef Chili!" is mentioned
|
// it, spaced in any way, and the border still holds after it: "Easy Beef
|
||||||
// by "Easy Beef Chili." too, and by "Easy Beef Chili!x" without its "!". A
|
// Chili!" is mentioned by "Easy Beef Chili." too, by "Easy Beef Chili !"
|
||||||
|
// with its "!", and by "Easy Beef Chili!x" without its "!". A
|
||||||
// combining mark is part of its letter, never punctuation. A mention names
|
// 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
|
// 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
|
// or more, so "Your Easy Beef Chili." names "Easy Beef Chili" and not "Beef
|
||||||
@@ -356,11 +357,11 @@ func (r regularNames) named(text string) []string {
|
|||||||
if !bordered(start, end) {
|
if !bordered(start, end) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(text[:start], lead) && bordered(start-len(lead), end) {
|
if s := spelledBefore(text, start, lead); s >= 0 && bordered(s, end) {
|
||||||
start -= len(lead)
|
start = s
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(text[end:], trail) && bordered(start, end+len(trail)) {
|
if e := spelledAfter(text, end, trail); e >= 0 && bordered(start, e) {
|
||||||
end += len(trail)
|
end = e
|
||||||
}
|
}
|
||||||
mentions = append(mentions, mention{name, start, end})
|
mentions = append(mentions, mention{name, start, end})
|
||||||
}
|
}
|
||||||
@@ -377,6 +378,33 @@ func (r regularNames) named(text string) []string {
|
|||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// spelledAfter returns where outer ends when text spells it from at,
|
||||||
|
// ignoring spacing, or -1 when text does not.
|
||||||
|
func spelledAfter(text string, at int, outer string) int {
|
||||||
|
for _, c := range strings.Join(strings.Fields(outer), "") {
|
||||||
|
at = len(text) - len(strings.TrimLeftFunc(text[at:], unicode.IsSpace))
|
||||||
|
if !strings.HasPrefix(text[at:], string(c)) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
at += utf8.RuneLen(c)
|
||||||
|
}
|
||||||
|
return at
|
||||||
|
}
|
||||||
|
|
||||||
|
// spelledBefore returns where outer starts when text spells it up to at,
|
||||||
|
// ignoring spacing, or -1 when text does not.
|
||||||
|
func spelledBefore(text string, at int, outer string) int {
|
||||||
|
punct := []rune(strings.Join(strings.Fields(outer), ""))
|
||||||
|
for i := len(punct) - 1; i >= 0; i-- {
|
||||||
|
at = len(strings.TrimRightFunc(text[:at], unicode.IsSpace))
|
||||||
|
if !strings.HasSuffix(text[:at], string(punct[i])) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
at -= utf8.RuneLen(punct[i])
|
||||||
|
}
|
||||||
|
return at
|
||||||
|
}
|
||||||
|
|
||||||
// isWord reports whether c is a letter, a mark on one or a digit.
|
// isWord reports whether c is a letter, a mark on one or a digit.
|
||||||
func isWord(c rune) bool { return unicode.IsLetter(c) || unicode.IsMark(c) || unicode.IsDigit(c) }
|
func isWord(c rune) bool { return unicode.IsLetter(c) || unicode.IsMark(c) || unicode.IsDigit(c) }
|
||||||
|
|
||||||
|
|||||||
@@ -254,6 +254,10 @@ func TestSuggestSideQuestsReasonMentionRule(t *testing.T) {
|
|||||||
"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},
|
"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},
|
"letter before punctuation": {[]string{"¡Beef Chili"}, "Your X¡Beef Chili is our inspiration.", "¡Beef Chili", none},
|
||||||
|
"spacing before punctuation": {[]string{"Beef Chili!"}, "Your Beef Chili ! over corn chips.", "Beef Chili!", ""},
|
||||||
|
"spacing after punctuation": {[]string{"¡Beef Chili"}, "Your ¡ Beef Chili is our inspiration.", "¡Beef Chili", ""},
|
||||||
|
"stored spacing left off": {[]string{"Beef Chili !", "Chili!"}, "Like your Beef Chili!", "Beef Chili !", ""},
|
||||||
|
"inside unspaced punctuation": {[]string{"Beef Chili !", "Chili!"}, "Like your Beef Chili!", "Chili!", none},
|
||||||
"stored symbol left off": {[]string{"Green Chili 🌶"}, "Like your Green Chili, gone green.", "Green 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},
|
"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},
|
"accent written after name": {[]string{"Chicken Cafe"}, "Like your Chicken Cafe\u0301, gone green.", "Chicken Cafe", none},
|
||||||
|
|||||||
Reference in New Issue
Block a user