diff options
Diffstat (limited to 'compare/compare_strings.go')
-rw-r--r-- | compare/compare_strings.go | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/compare/compare_strings.go b/compare/compare_strings.go new file mode 100644 index 000000000..1fd954081 --- /dev/null +++ b/compare/compare_strings.go @@ -0,0 +1,113 @@ +// Copyright 2019 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package compare + +import ( + "strings" + "unicode" + "unicode/utf8" +) + +// Strings returns an integer comparing two strings lexicographically. +func Strings(s, t string) int { + c := compareFold(s, t) + + if c == 0 { + // "B" and "b" would be the same so we need a tiebreaker. + return strings.Compare(s, t) + } + + return c +} + +// This function is derived from strings.EqualFold in Go's stdlib. +// https://github.com/golang/go/blob/ad4a58e31501bce5de2aad90a620eaecdc1eecb8/src/strings/strings.go#L893 +func compareFold(s, t string) int { + for s != "" && t != "" { + var sr, tr rune + if s[0] < utf8.RuneSelf { + sr, s = rune(s[0]), s[1:] + } else { + r, size := utf8.DecodeRuneInString(s) + sr, s = r, s[size:] + } + if t[0] < utf8.RuneSelf { + tr, t = rune(t[0]), t[1:] + } else { + r, size := utf8.DecodeRuneInString(t) + tr, t = r, t[size:] + } + + if tr == sr { + continue + } + + c := 1 + if tr < sr { + tr, sr = sr, tr + c = -c + } + + // ASCII only. + if tr < utf8.RuneSelf { + if sr >= 'A' && sr <= 'Z' { + if tr <= 'Z' { + // Same case. + return -c + } + + diff := tr - (sr + 'a' - 'A') + + if diff == 0 { + continue + } + + if diff < 0 { + return c + } + + if diff > 0 { + return -c + } + } + } + + // Unicode. + r := unicode.SimpleFold(sr) + for r != sr && r < tr { + r = unicode.SimpleFold(r) + } + + if r == tr { + continue + } + + return -c + } + + if s == "" && t == "" { + return 0 + } + + if s == "" { + return -1 + } + + return 1 +} + +// LessStrings returns whether s is less than t lexicographically. +func LessStrings(s, t string) bool { + return Strings(s, t) < 0 +} |