File: str_tools.go

package info (click to toggle)
git-lfs 3.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,808 kB
  • sloc: sh: 21,256; makefile: 507; ruby: 417
file content (124 lines) | stat: -rw-r--r-- 2,837 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package tools

import (
	"regexp"
	"strings"
)

var (
	// quoteFieldRe greedily matches between matching pairs of '', "", or
	// non-word characters.
	quoteFieldRe = regexp.MustCompile("'(.*)'|\"(.*)\"|(\\S*)")
)

// QuotedFields is an alternative to strings.Fields (see:
// https://golang.org/pkg/strings#Fields) that respects spaces between matching
// pairs of quotation delimiters.
//
// For instance, the quoted fields of the string "foo bar 'baz etc'" would be:
//
//	[]string{"foo", "bar", "baz etc"}
//
// Whereas the same argument given to strings.Fields, would return:
//
//	[]string{"foo", "bar", "'baz", "etc'"}
func QuotedFields(s string) []string {
	submatches := quoteFieldRe.FindAllStringSubmatch(s, -1)
	out := make([]string, 0, len(submatches))

	for _, matches := range submatches {
		// 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)
		var str string
		for _, m := range matches[1:] {
			if len(m) > 0 {
				str = m
				break
			}
		}

		out = append(out, str)
	}

	return out
}

// 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
}

// 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
}

// 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
	for _, str := range strs {
		if len(str) >= llen {
			longest = str
			llen = len(longest)
		}
	}

	return longest
}

// 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
}

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, "")
}