...

Source file src/pkg/cmd/go/internal/str/str.go

     1	// Copyright 2017 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Package str provides string manipulation utilities.
     6	package str
     7	
     8	import (
     9		"bytes"
    10		"fmt"
    11		"unicode"
    12		"unicode/utf8"
    13	)
    14	
    15	// StringList flattens its arguments into a single []string.
    16	// Each argument in args must have type string or []string.
    17	func StringList(args ...interface{}) []string {
    18		var x []string
    19		for _, arg := range args {
    20			switch arg := arg.(type) {
    21			case []string:
    22				x = append(x, arg...)
    23			case string:
    24				x = append(x, arg)
    25			default:
    26				panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
    27			}
    28		}
    29		return x
    30	}
    31	
    32	// ToFold returns a string with the property that
    33	//	strings.EqualFold(s, t) iff ToFold(s) == ToFold(t)
    34	// This lets us test a large set of strings for fold-equivalent
    35	// duplicates without making a quadratic number of calls
    36	// to EqualFold. Note that strings.ToUpper and strings.ToLower
    37	// do not have the desired property in some corner cases.
    38	func ToFold(s string) string {
    39		// Fast path: all ASCII, no upper case.
    40		// Most paths look like this already.
    41		for i := 0; i < len(s); i++ {
    42			c := s[i]
    43			if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
    44				goto Slow
    45			}
    46		}
    47		return s
    48	
    49	Slow:
    50		var buf bytes.Buffer
    51		for _, r := range s {
    52			// SimpleFold(x) cycles to the next equivalent rune > x
    53			// or wraps around to smaller values. Iterate until it wraps,
    54			// and we've found the minimum value.
    55			for {
    56				r0 := r
    57				r = unicode.SimpleFold(r0)
    58				if r <= r0 {
    59					break
    60				}
    61			}
    62			// Exception to allow fast path above: A-Z => a-z
    63			if 'A' <= r && r <= 'Z' {
    64				r += 'a' - 'A'
    65			}
    66			buf.WriteRune(r)
    67		}
    68		return buf.String()
    69	}
    70	
    71	// FoldDup reports a pair of strings from the list that are
    72	// equal according to strings.EqualFold.
    73	// It returns "", "" if there are no such strings.
    74	func FoldDup(list []string) (string, string) {
    75		clash := map[string]string{}
    76		for _, s := range list {
    77			fold := ToFold(s)
    78			if t := clash[fold]; t != "" {
    79				if s > t {
    80					s, t = t, s
    81				}
    82				return s, t
    83			}
    84			clash[fold] = s
    85		}
    86		return "", ""
    87	}
    88	
    89	// Contains reports whether x contains s.
    90	func Contains(x []string, s string) bool {
    91		for _, t := range x {
    92			if t == s {
    93				return true
    94			}
    95		}
    96		return false
    97	}
    98	
    99	func isSpaceByte(c byte) bool {
   100		return c == ' ' || c == '\t' || c == '\n' || c == '\r'
   101	}
   102	
   103	// SplitQuotedFields splits s into a list of fields,
   104	// allowing single or double quotes around elements.
   105	// There is no unescaping or other processing within
   106	// quoted fields.
   107	func SplitQuotedFields(s string) ([]string, error) {
   108		// Split fields allowing '' or "" around elements.
   109		// Quotes further inside the string do not count.
   110		var f []string
   111		for len(s) > 0 {
   112			for len(s) > 0 && isSpaceByte(s[0]) {
   113				s = s[1:]
   114			}
   115			if len(s) == 0 {
   116				break
   117			}
   118			// Accepted quoted string. No unescaping inside.
   119			if s[0] == '"' || s[0] == '\'' {
   120				quote := s[0]
   121				s = s[1:]
   122				i := 0
   123				for i < len(s) && s[i] != quote {
   124					i++
   125				}
   126				if i >= len(s) {
   127					return nil, fmt.Errorf("unterminated %c string", quote)
   128				}
   129				f = append(f, s[:i])
   130				s = s[i+1:]
   131				continue
   132			}
   133			i := 0
   134			for i < len(s) && !isSpaceByte(s[i]) {
   135				i++
   136			}
   137			f = append(f, s[:i])
   138			s = s[i:]
   139		}
   140		return f, nil
   141	}
   142	

View as plain text