github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/go/internal/str/str.go (about)

     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  }