diff --git a/string.go b/string.go index 95b68f3d..97758b28 100644 --- a/string.go +++ b/string.go @@ -431,8 +431,14 @@ func splitWordBoundaries(s string) []byte { } if i+2 < len(s) { if e := s[i+2]; isASCIIUpper(c) && isASCIIUpper(d) && isASCIILower(e) { - out = append(out, c, ' ', d, e) - i += 3 + // The lowercase letter only marks where the acronym ends: it + // opens the next word, so leave it for the following iteration. + // Consuming it here skips the boundary check on the pair it + // forms with the byte after it, which kept "Pv6" glued together + // in "IPv6Address" while "Int8Value" split the same + // letter/digit boundary. + out = append(out, c, ' ', d) + i += 2 continue } } diff --git a/string_test.go b/string_test.go index 639db529..a4d0a53a 100644 --- a/string_test.go +++ b/string_test.go @@ -492,6 +492,18 @@ func TestAllCase(t *testing.T) { KebabCase: "first-last", SnakeCase: "first_last", }}, + {in: "IPv6Address", want: output{ + PascalCase: "IPv6Address", + CamelCase: "iPv6Address", + KebabCase: "i-pv-6-address", + SnakeCase: "i_pv_6_address", + }}, + {in: "HTMLv5Doc", want: output{ + PascalCase: "HtmLv5Doc", + CamelCase: "htmLv5Doc", + KebabCase: "htm-lv-5-doc", + SnakeCase: "htm_lv_5_doc", + }}, } for _, tc := range testCases { @@ -522,6 +534,9 @@ func TestWords(t *testing.T) { {"UPPERCASE", []string{"UPPERCASE"}}, {"HTTPCode", []string{"HTTP", "Code"}}, {"Int8Value", []string{"Int", "8", "Value"}}, + {"IPv6Address", []string{"I", "Pv", "6", "Address"}}, + {"ABc1", []string{"A", "Bc", "1"}}, + {"ABCdEf", []string{"AB", "Cd", "Ef"}}, } for _, tc := range testCases { tc := tc