compare_strings.go (2207B)
1 // Copyright 2019 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package compare 15 16 import ( 17 "strings" 18 "unicode" 19 "unicode/utf8" 20 ) 21 22 // Strings returns an integer comparing two strings lexicographically. 23 func Strings(s, t string) int { 24 c := compareFold(s, t) 25 26 if c == 0 { 27 // "B" and "b" would be the same so we need a tiebreaker. 28 return strings.Compare(s, t) 29 } 30 31 return c 32 } 33 34 // This function is derived from strings.EqualFold in Go's stdlib. 35 // https://github.com/golang/go/blob/ad4a58e31501bce5de2aad90a620eaecdc1eecb8/src/strings/strings.go#L893 36 func compareFold(s, t string) int { 37 for s != "" && t != "" { 38 var sr, tr rune 39 if s[0] < utf8.RuneSelf { 40 sr, s = rune(s[0]), s[1:] 41 } else { 42 r, size := utf8.DecodeRuneInString(s) 43 sr, s = r, s[size:] 44 } 45 if t[0] < utf8.RuneSelf { 46 tr, t = rune(t[0]), t[1:] 47 } else { 48 r, size := utf8.DecodeRuneInString(t) 49 tr, t = r, t[size:] 50 } 51 52 if tr == sr { 53 continue 54 } 55 56 c := 1 57 if tr < sr { 58 tr, sr = sr, tr 59 c = -c 60 } 61 62 // ASCII only. 63 if tr < utf8.RuneSelf { 64 if sr >= 'A' && sr <= 'Z' { 65 if tr <= 'Z' { 66 // Same case. 67 return -c 68 } 69 70 diff := tr - (sr + 'a' - 'A') 71 72 if diff == 0 { 73 continue 74 } 75 76 if diff < 0 { 77 return c 78 } 79 80 if diff > 0 { 81 return -c 82 } 83 } 84 } 85 86 // Unicode. 87 r := unicode.SimpleFold(sr) 88 for r != sr && r < tr { 89 r = unicode.SimpleFold(r) 90 } 91 92 if r == tr { 93 continue 94 } 95 96 return -c 97 } 98 99 if s == "" && t == "" { 100 return 0 101 } 102 103 if s == "" { 104 return -1 105 } 106 107 return 1 108 } 109 110 // LessStrings returns whether s is less than t lexicographically. 111 func LessStrings(s, t string) bool { 112 return Strings(s, t) < 0 113 }