mirror of
https://github.com/golang/go
synced 2024-11-17 19:04:47 -07:00
unicode: fix SpecialCase to follow its docs & respect explict no-op mappings
If SpecialCase contains an explicit CaseRange with zero deltas, respect those and don't fall back to the default behavior. Fixes #25636 Change-Id: Ic554c6b3dd462b1b39c75194eec469b6ff4aa55b Reviewed-on: https://go-review.googlesource.com/117155 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
This commit is contained in:
parent
b459e00454
commit
05f8b44d5e
@ -206,9 +206,10 @@ func IsTitle(r rune) bool {
|
||||
}
|
||||
|
||||
// to maps the rune using the specified case mapping.
|
||||
func to(_case int, r rune, caseRange []CaseRange) rune {
|
||||
// It additionally reports whether caseRange contained a mapping for r.
|
||||
func to(_case int, r rune, caseRange []CaseRange) (mappedRune rune, foundMapping bool) {
|
||||
if _case < 0 || MaxCase <= _case {
|
||||
return ReplacementChar // as reasonable an error as any
|
||||
return ReplacementChar, false // as reasonable an error as any
|
||||
}
|
||||
// binary search over ranges
|
||||
lo := 0
|
||||
@ -229,9 +230,9 @@ func to(_case int, r rune, caseRange []CaseRange) rune {
|
||||
// bit in the sequence offset.
|
||||
// The constants UpperCase and TitleCase are even while LowerCase
|
||||
// is odd so we take the low bit from _case.
|
||||
return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1))
|
||||
return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1)), true
|
||||
}
|
||||
return r + delta
|
||||
return r + delta, true
|
||||
}
|
||||
if r < rune(cr.Lo) {
|
||||
hi = m
|
||||
@ -239,12 +240,13 @@ func to(_case int, r rune, caseRange []CaseRange) rune {
|
||||
lo = m + 1
|
||||
}
|
||||
}
|
||||
return r
|
||||
return r, false
|
||||
}
|
||||
|
||||
// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
|
||||
func To(_case int, r rune) rune {
|
||||
return to(_case, r, CaseRanges)
|
||||
r, _ = to(_case, r, CaseRanges)
|
||||
return r
|
||||
}
|
||||
|
||||
// ToUpper maps the rune to upper case.
|
||||
@ -282,8 +284,8 @@ func ToTitle(r rune) rune {
|
||||
|
||||
// ToUpper maps the rune to upper case giving priority to the special mapping.
|
||||
func (special SpecialCase) ToUpper(r rune) rune {
|
||||
r1 := to(UpperCase, r, []CaseRange(special))
|
||||
if r1 == r {
|
||||
r1, hadMapping := to(UpperCase, r, []CaseRange(special))
|
||||
if r1 == r && !hadMapping {
|
||||
r1 = ToUpper(r)
|
||||
}
|
||||
return r1
|
||||
@ -291,8 +293,8 @@ func (special SpecialCase) ToUpper(r rune) rune {
|
||||
|
||||
// ToTitle maps the rune to title case giving priority to the special mapping.
|
||||
func (special SpecialCase) ToTitle(r rune) rune {
|
||||
r1 := to(TitleCase, r, []CaseRange(special))
|
||||
if r1 == r {
|
||||
r1, hadMapping := to(TitleCase, r, []CaseRange(special))
|
||||
if r1 == r && !hadMapping {
|
||||
r1 = ToTitle(r)
|
||||
}
|
||||
return r1
|
||||
@ -300,8 +302,8 @@ func (special SpecialCase) ToTitle(r rune) rune {
|
||||
|
||||
// ToLower maps the rune to lower case giving priority to the special mapping.
|
||||
func (special SpecialCase) ToLower(r rune) rune {
|
||||
r1 := to(LowerCase, r, []CaseRange(special))
|
||||
if r1 == r {
|
||||
r1, hadMapping := to(LowerCase, r, []CaseRange(special))
|
||||
if r1 == r && !hadMapping {
|
||||
r1 = ToLower(r)
|
||||
}
|
||||
return r1
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
. "unicode"
|
||||
)
|
||||
@ -551,3 +552,14 @@ func TestLatinOffset(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpecialCaseNoMapping(t *testing.T) {
|
||||
// Issue 25636
|
||||
// no change for rune 'A', zero delta, under upper/lower/title case change.
|
||||
var noChangeForCapitalA = CaseRange{'A', 'A', [MaxCase]rune{0, 0, 0}}
|
||||
got := strings.ToLowerSpecial(SpecialCase([]CaseRange{noChangeForCapitalA}), "ABC")
|
||||
want := "Abc"
|
||||
if got != want {
|
||||
t.Errorf("got %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user