// Copyright 2018 The CUE Authors // // 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 strings implements simple functions to manipulate UTF-8 encoded // strings.package strings. // // Some of the functions in this package are specifically intended as field // constraints. For instance, MaxRunes as used in this CUE program // // import "strings" // // myString: strings.MaxRunes(5) // // specifies that the myString should be at most 5 code points. package strings import ( "fmt" "strings" "unicode" ) // ByteAt reports the ith byte of the underlying strings or byte. func ByteAt(b []byte, i int) (byte, error) { if i < 0 || i >= len(b) { return 0, fmt.Errorf("index out of range") } return b[i], nil } // ByteSlice reports the bytes of the underlying string data from the start // index up to but not including the end index. func ByteSlice(b []byte, start, end int) ([]byte, error) { if start < 0 || start > end || end > len(b) { return nil, fmt.Errorf("index out of range") } return b[start:end], nil } // Runes returns the Unicode code points of the given string. func Runes(s string) []rune { return []rune(s) } // MinRunes reports whether the number of runes (Unicode codepoints) in a string // is at least a certain minimum. MinRunes can be used a field constraint to // except all strings for which this property holds. func MinRunes(s string, min int) bool { // TODO: CUE strings cannot be invalid UTF-8. In case this changes, we need // to use the following conversion to count properly: // s, _ = unicodeenc.UTF8.NewDecoder().String(s) return len([]rune(s)) >= min } // MaxRunes reports whether the number of runes (Unicode codepoints) in a string // exceeds a certain maximum. MaxRunes can be used a field constraint to // except all strings for which this property holds func MaxRunes(s string, max int) bool { // See comment in MinRunes implementation. return len([]rune(s)) <= max } // ToTitle returns a copy of the string s with all Unicode letters that begin // words mapped to their title case. func ToTitle(s string) string { // Use a closure here to remember state. // Hackish but effective. Depends on Map scanning in order and calling // the closure once per rune. prev := ' ' return strings.Map( func(r rune) rune { if unicode.IsSpace(prev) { prev = r return unicode.ToTitle(r) } prev = r return r }, s) } // ToCamel returns a copy of the string s with all Unicode letters that begin // words mapped to lower case. func ToCamel(s string) string { // Use a closure here to remember state. // Hackish but effective. Depends on Map scanning in order and calling // the closure once per rune. prev := ' ' return strings.Map( func(r rune) rune { if unicode.IsSpace(prev) { prev = r return unicode.ToLower(r) } prev = r return r }, s) } // SliceRunes returns a string of the underlying string data from the start index // up to but not including the end index. func SliceRunes(s string, start, end int) (string, error) { runes := []rune(s) if start < 0 || start > end || end > len(runes) { return "", fmt.Errorf("index out of range") } return string(runes[start:end]), nil }