2017-02-18 22:46:11 +00:00
|
|
|
package tools
|
|
|
|
|
2017-06-13 20:52:21 +00:00
|
|
|
import (
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
)
|
2017-02-18 22:46:11 +00:00
|
|
|
|
|
|
|
var (
|
|
|
|
// quoteFieldRe greedily matches between matching pairs of '', "", or
|
|
|
|
// non-word characters.
|
2017-02-21 18:45:52 +00:00
|
|
|
quoteFieldRe = regexp.MustCompile("'(.*)'|\"(.*)\"|(\\S*)")
|
2017-02-18 22:46:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// QuotedFields is an alternative to strings.Fields (see:
|
|
|
|
// https://golang.org/pkg/strings#Fields) that respects spaces between matching
|
|
|
|
// pairs of quotation delimeters.
|
|
|
|
//
|
|
|
|
// For instance, the quoted fields of the string "foo bar 'baz etc'" would be:
|
2017-02-21 18:31:24 +00:00
|
|
|
// []string{"foo", "bar", "baz etc"}
|
2017-02-18 22:46:11 +00:00
|
|
|
//
|
|
|
|
// Whereas the same argument given to strings.Fields, would return:
|
|
|
|
// []string{"foo", "bar", "'baz", "etc'"}
|
|
|
|
func QuotedFields(s string) []string {
|
2017-02-21 18:31:24 +00:00
|
|
|
submatches := quoteFieldRe.FindAllStringSubmatch(s, -1)
|
|
|
|
out := make([]string, 0, len(submatches))
|
|
|
|
|
|
|
|
for _, matches := range submatches {
|
2017-02-21 18:45:52 +00:00
|
|
|
// if a leading or trailing space is found, ignore that
|
|
|
|
if matches[0] == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, find the first non-empty match (inside balanced
|
|
|
|
// quotes, or a space-delimited string)
|
2017-02-21 18:31:24 +00:00
|
|
|
var str string
|
|
|
|
for _, m := range matches[1:] {
|
|
|
|
if len(m) > 0 {
|
|
|
|
str = m
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out = append(out, str)
|
|
|
|
}
|
|
|
|
|
|
|
|
return out
|
2017-02-18 22:46:11 +00:00
|
|
|
}
|
2017-06-13 20:52:08 +00:00
|
|
|
|
2017-06-13 21:58:21 +00:00
|
|
|
// Ljust returns a copied string slice where each element is left justified to
|
|
|
|
// match the width of the longest element in the set.
|
|
|
|
func Ljust(strs []string) []string {
|
|
|
|
llen := len(Longest(strs))
|
|
|
|
|
|
|
|
dup := make([]string, len(strs), cap(strs))
|
|
|
|
copy(dup, strs)
|
|
|
|
|
|
|
|
for i, str := range strs {
|
|
|
|
width := MaxInt(0, llen-len(str))
|
|
|
|
padding := strings.Repeat(" ", width)
|
|
|
|
|
|
|
|
dup[i] = str + padding
|
|
|
|
}
|
|
|
|
|
|
|
|
return dup
|
|
|
|
}
|
|
|
|
|
2017-06-13 20:52:21 +00:00
|
|
|
// Rjust returns a copied string slice where each element is right justified to
|
|
|
|
// match the width of the longest element in the set.
|
|
|
|
func Rjust(strs []string) []string {
|
|
|
|
llen := len(Longest(strs))
|
|
|
|
|
|
|
|
dup := make([]string, len(strs), cap(strs))
|
|
|
|
copy(dup, strs)
|
|
|
|
|
|
|
|
for i, str := range strs {
|
|
|
|
width := MaxInt(0, llen-len(str))
|
|
|
|
padding := strings.Repeat(" ", width)
|
|
|
|
|
|
|
|
dup[i] = padding + str
|
|
|
|
}
|
|
|
|
|
|
|
|
return dup
|
|
|
|
}
|
|
|
|
|
2017-06-13 20:52:08 +00:00
|
|
|
// Longest returns the longest element in the string slice in O(n) time and O(1)
|
|
|
|
// space. If strs is empty or nil, an empty string will be returned.
|
|
|
|
func Longest(strs []string) string {
|
|
|
|
if len(strs) == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
var longest string
|
|
|
|
var llen int
|
2017-06-13 20:52:21 +00:00
|
|
|
for _, str := range strs {
|
2017-06-13 20:52:08 +00:00
|
|
|
if len(str) >= llen {
|
|
|
|
longest = str
|
|
|
|
llen = len(longest)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return longest
|
|
|
|
}
|
2017-07-06 17:43:18 +00:00
|
|
|
|
|
|
|
// Indent returns a string which prepends "\t" TAB characters to the beginning
|
|
|
|
// of each line in the given string "str".
|
|
|
|
func Indent(str string) string {
|
|
|
|
indented := strings.Replace(str, "\n", "\n\t", -1)
|
|
|
|
if len(indented) > 0 {
|
|
|
|
indented = "\t" + indented
|
|
|
|
}
|
|
|
|
|
|
|
|
return indented
|
|
|
|
}
|
|
|
|
|
2017-07-06 18:18:56 +00:00
|
|
|
var (
|
|
|
|
tabRe = regexp.MustCompile(`(?m)^[ \t]+`)
|
|
|
|
)
|
|
|
|
|
|
|
|
// Undent removes all leading tabs in the given string "str", line-wise.
|
|
|
|
func Undent(str string) string {
|
|
|
|
return tabRe.ReplaceAllString(str, "")
|
|
|
|
}
|