mirror of
https://github.com/golang/go
synced 2024-11-23 05:30:07 -07:00
bytes, strings: add TrimPrefix and TrimSuffix
Everybody either gets confused and thinks this is TrimLeft/TrimRight or does this by hand which gets repetitive looking. R=rsc, kevlar CC=golang-dev https://golang.org/cl/7239044
This commit is contained in:
parent
fe14ee52cc
commit
e515d80d5d
@ -778,8 +778,7 @@ func (w *Walker) walkConst(vs *ast.ValueSpec) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(litType, constDepPrefix) {
|
||||
dep := litType[len(constDepPrefix):]
|
||||
if dep := strings.TrimPrefix(litType, constDepPrefix); dep != litType {
|
||||
w.constDep[ident.Name] = dep
|
||||
continue
|
||||
}
|
||||
|
@ -1542,8 +1542,8 @@ func godefsFields(fld []*ast.Field) {
|
||||
npad := 0
|
||||
for _, f := range fld {
|
||||
for _, n := range f.Names {
|
||||
if strings.HasPrefix(n.Name, prefix) && n.Name != prefix {
|
||||
n.Name = n.Name[len(prefix):]
|
||||
if n.Name != prefix {
|
||||
n.Name = strings.TrimPrefix(n.Name, prefix)
|
||||
}
|
||||
if n.Name == "_" {
|
||||
// Use exported name instead.
|
||||
|
@ -180,7 +180,7 @@ func (p *Package) cdefs(f *File, srcfile string) string {
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
|
||||
s := line[len("type ") : len(line)-len(" struct {")]
|
||||
s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
|
||||
printf("typedef struct %s %s;\n", s, s)
|
||||
}
|
||||
}
|
||||
|
@ -395,9 +395,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
|
||||
// Field or method.
|
||||
name := n.Sel.Name
|
||||
if t := typeof[n.X]; t != "" {
|
||||
if strings.HasPrefix(t, "*") {
|
||||
t = t[1:] // implicit *
|
||||
}
|
||||
t = strings.TrimPrefix(t, "*") // implicit *
|
||||
if typ := cfg.Type[t]; typ != nil {
|
||||
if t := typ.dot(cfg, name); t != "" {
|
||||
typeof[n] = t
|
||||
|
@ -195,9 +195,7 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
|
||||
}
|
||||
name := arg[1:]
|
||||
// If there's already "test.", drop it for now.
|
||||
if strings.HasPrefix(name, "test.") {
|
||||
name = name[5:]
|
||||
}
|
||||
name = strings.TrimPrefix(name, "test.")
|
||||
equals := strings.Index(name, "=")
|
||||
if equals >= 0 {
|
||||
value = name[equals+1:]
|
||||
|
@ -229,9 +229,7 @@ func (dir *Directory) lookupLocal(name string) *Directory {
|
||||
}
|
||||
|
||||
func splitPath(p string) []string {
|
||||
if strings.HasPrefix(p, "/") {
|
||||
p = p[1:]
|
||||
}
|
||||
p = strings.TrimPrefix(p, "/")
|
||||
if p == "" {
|
||||
return nil
|
||||
}
|
||||
@ -310,14 +308,9 @@ func (root *Directory) listing(skipRoot bool) *DirList {
|
||||
// the path is relative to root.Path - remove the root.Path
|
||||
// prefix (the prefix should always be present but avoid
|
||||
// crashes and check)
|
||||
path := d.Path
|
||||
if strings.HasPrefix(d.Path, root.Path) {
|
||||
path = d.Path[len(root.Path):]
|
||||
}
|
||||
path := strings.TrimPrefix(d.Path, root.Path)
|
||||
// remove leading separator if any - path must be relative
|
||||
if len(path) > 0 && path[0] == '/' {
|
||||
path = path[1:]
|
||||
}
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
p.Path = path
|
||||
p.Name = d.Name
|
||||
p.HasPkg = d.HasPkg
|
||||
|
@ -459,9 +459,7 @@ func (ns nameSpace) ReadDir(path string) ([]os.FileInfo, error) {
|
||||
if hasPathPrefix(old, path) && old != path {
|
||||
// Find next element after path in old.
|
||||
elem := old[len(path):]
|
||||
if strings.HasPrefix(elem, "/") {
|
||||
elem = elem[1:]
|
||||
}
|
||||
elem = strings.TrimPrefix(elem, "/")
|
||||
if i := strings.Index(elem, "/"); i >= 0 {
|
||||
elem = elem[:i]
|
||||
}
|
||||
|
@ -419,9 +419,7 @@ func pkgLinkFunc(path string) string {
|
||||
relpath := path[1:]
|
||||
// because of the irregular mapping under goroot
|
||||
// we need to correct certain relative paths
|
||||
if strings.HasPrefix(relpath, "src/pkg/") {
|
||||
relpath = relpath[len("src/pkg/"):]
|
||||
}
|
||||
relpath = strings.TrimPrefix(relpath, "src/pkg/")
|
||||
return pkgHandler.pattern[1:] + relpath // remove trailing '/' for relative URL
|
||||
}
|
||||
|
||||
|
@ -347,7 +347,7 @@ func main() {
|
||||
fs.Bind(target, OS(path), "/", bindReplace)
|
||||
abspath = target
|
||||
} else if strings.HasPrefix(path, cmdPrefix) {
|
||||
path = path[len(cmdPrefix):]
|
||||
path = strings.TrimPrefix(path, cmdPrefix)
|
||||
forceCmd = true
|
||||
} else if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
|
||||
fs.Bind(target, OS(bp.Dir), "/", bindReplace)
|
||||
|
@ -90,9 +90,7 @@ func (f *File) checkCanonicalMethod(id *ast.Ident, t *ast.FuncType) {
|
||||
fmt.Fprintf(&f.b, "<%s>", err)
|
||||
}
|
||||
actual := f.b.String()
|
||||
if strings.HasPrefix(actual, "func(") {
|
||||
actual = actual[4:]
|
||||
}
|
||||
actual = strings.TrimPrefix(actual, "func(")
|
||||
actual = id.Name + actual
|
||||
|
||||
f.Warnf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
|
||||
|
@ -515,6 +515,24 @@ func TrimFunc(s []byte, f func(r rune) bool) []byte {
|
||||
return TrimRightFunc(TrimLeftFunc(s, f), f)
|
||||
}
|
||||
|
||||
// TrimPrefix returns s without the provided leading prefix string.
|
||||
// If s doesn't start with prefix, s is returned unchanged.
|
||||
func TrimPrefix(s, prefix []byte) []byte {
|
||||
if HasPrefix(s, prefix) {
|
||||
return s[len(prefix):]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// TrimSuffix returns s without the provided trailing suffix string.
|
||||
// If s doesn't end with suffix, s is returned unchanged.
|
||||
func TrimSuffix(s, suffix []byte) []byte {
|
||||
if HasSuffix(s, suffix) {
|
||||
return s[:len(s)-len(suffix)]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
|
||||
// It returns the byte index in s of the first Unicode
|
||||
// code point satisfying f(c), or -1 if none do.
|
||||
|
@ -794,8 +794,8 @@ func TestRunes(t *testing.T) {
|
||||
}
|
||||
|
||||
type TrimTest struct {
|
||||
f string
|
||||
in, cutset, out string
|
||||
f string
|
||||
in, arg, out string
|
||||
}
|
||||
|
||||
var trimTests = []TrimTest{
|
||||
@ -820,12 +820,17 @@ var trimTests = []TrimTest{
|
||||
{"TrimRight", "", "123", ""},
|
||||
{"TrimRight", "", "", ""},
|
||||
{"TrimRight", "☺\xc0", "☺", "☺\xc0"},
|
||||
{"TrimPrefix", "aabb", "a", "abb"},
|
||||
{"TrimPrefix", "aabb", "b", "aabb"},
|
||||
{"TrimSuffix", "aabb", "a", "aabb"},
|
||||
{"TrimSuffix", "aabb", "b", "aab"},
|
||||
}
|
||||
|
||||
func TestTrim(t *testing.T) {
|
||||
for _, tc := range trimTests {
|
||||
name := tc.f
|
||||
var f func([]byte, string) []byte
|
||||
var fb func([]byte, []byte) []byte
|
||||
switch name {
|
||||
case "Trim":
|
||||
f = Trim
|
||||
@ -833,12 +838,21 @@ func TestTrim(t *testing.T) {
|
||||
f = TrimLeft
|
||||
case "TrimRight":
|
||||
f = TrimRight
|
||||
case "TrimPrefix":
|
||||
fb = TrimPrefix
|
||||
case "TrimSuffix":
|
||||
fb = TrimSuffix
|
||||
default:
|
||||
t.Errorf("Undefined trim function %s", name)
|
||||
}
|
||||
actual := string(f([]byte(tc.in), tc.cutset))
|
||||
var actual string
|
||||
if f != nil {
|
||||
actual = string(f([]byte(tc.in), tc.arg))
|
||||
} else {
|
||||
actual = string(fb([]byte(tc.in), []byte(tc.arg)))
|
||||
}
|
||||
if actual != tc.out {
|
||||
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
|
||||
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,3 +66,20 @@ func ExampleCompare_search() {
|
||||
// Found it!
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleTrimSuffix() {
|
||||
var b = []byte("Hello, goodbye, etc!")
|
||||
b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
|
||||
b = bytes.TrimSuffix(b, []byte("gopher"))
|
||||
b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
|
||||
os.Stdout.Write(b)
|
||||
// Output: Hello, world!
|
||||
}
|
||||
|
||||
func ExampleTrimPrefix() {
|
||||
var b = []byte("Goodbye,, world!")
|
||||
b = bytes.TrimPrefix(b, []byte("Goodbye,"))
|
||||
b = bytes.TrimPrefix(b, []byte("See ya,"))
|
||||
fmt.Printf("Hello%s", b)
|
||||
// Output: Hello, world!
|
||||
}
|
||||
|
@ -42,10 +42,7 @@ func readParseTest(r *bufio.Reader) (text, want, context string, err error) {
|
||||
}
|
||||
b = append(b, line...)
|
||||
}
|
||||
text = string(b)
|
||||
if strings.HasSuffix(text, "\n") {
|
||||
text = text[:len(text)-1]
|
||||
}
|
||||
text = strings.TrimSuffix(string(b), "\n")
|
||||
b = b[:0]
|
||||
|
||||
// Skip the error list.
|
||||
|
@ -551,9 +551,7 @@ func stripCommonPrefix(lines []string) {
|
||||
}
|
||||
// Shorten the computed common prefix by the length of
|
||||
// suffix, if it is found as suffix of the prefix.
|
||||
if strings.HasSuffix(prefix, string(suffix)) {
|
||||
prefix = prefix[0 : len(prefix)-len(suffix)]
|
||||
}
|
||||
prefix = strings.TrimSuffix(prefix, string(suffix))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,10 +44,7 @@ func FindPkg(path, srcDir string) (filename, id string) {
|
||||
if bp.PkgObj == "" {
|
||||
return
|
||||
}
|
||||
noext = bp.PkgObj
|
||||
if strings.HasSuffix(noext, ".a") {
|
||||
noext = noext[:len(noext)-len(".a")]
|
||||
}
|
||||
noext = strings.TrimSuffix(bp.PkgObj, ".a")
|
||||
|
||||
case build.IsLocalImport(path):
|
||||
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
|
||||
|
@ -172,7 +172,7 @@ func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// listing the available profiles.
|
||||
func Index(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
|
||||
name := r.URL.Path[len("/debug/pprof/"):]
|
||||
name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/")
|
||||
if name != "" {
|
||||
handler(name).ServeHTTP(w, r)
|
||||
return
|
||||
|
@ -198,9 +198,7 @@ func (r *Response) Write(w io.Writer) error {
|
||||
}
|
||||
protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor)
|
||||
statusCode := strconv.Itoa(r.StatusCode) + " "
|
||||
if strings.HasPrefix(text, statusCode) {
|
||||
text = text[len(statusCode):]
|
||||
}
|
||||
text = strings.TrimPrefix(text, statusCode)
|
||||
io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n")
|
||||
|
||||
// Process Body,ContentLength,Close,Trailer
|
||||
|
@ -179,3 +179,19 @@ func ExampleToLower() {
|
||||
fmt.Println(strings.ToLower("Gopher"))
|
||||
// Output: gopher
|
||||
}
|
||||
|
||||
func ExampleTrimSuffix() {
|
||||
var s = "Hello, goodbye, etc!"
|
||||
s = strings.TrimSuffix(s, "goodbye, etc!")
|
||||
s = strings.TrimSuffix(s, "planet")
|
||||
fmt.Print(s, "world!")
|
||||
// Output: Hello, world!
|
||||
}
|
||||
|
||||
func ExampleTrimPrefix() {
|
||||
var s = "Goodbye,, world!"
|
||||
s = strings.TrimPrefix(s, "Goodbye,")
|
||||
s = strings.TrimPrefix(s, "Howdy,")
|
||||
fmt.Print("Hello" + s)
|
||||
// Output: Hello, world!
|
||||
}
|
||||
|
@ -558,6 +558,24 @@ func TrimSpace(s string) string {
|
||||
return TrimFunc(s, unicode.IsSpace)
|
||||
}
|
||||
|
||||
// TrimPrefix returns s without the provided leading prefix string.
|
||||
// If s doesn't start with prefix, s is returned unchanged.
|
||||
func TrimPrefix(s, prefix string) string {
|
||||
if HasPrefix(s, prefix) {
|
||||
return s[len(prefix):]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// TrimSuffix returns s without the provided trailing suffix string.
|
||||
// If s doesn't end with suffix, s is returned unchanged.
|
||||
func TrimSuffix(s, suffix string) string {
|
||||
if HasSuffix(s, suffix) {
|
||||
return s[:len(s)-len(suffix)]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Replace returns a copy of the string s with the first n
|
||||
// non-overlapping instances of old replaced by new.
|
||||
// If n < 0, there is no limit on the number of replacements.
|
||||
|
@ -496,8 +496,8 @@ func TestSpecialCase(t *testing.T) {
|
||||
func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
|
||||
|
||||
var trimTests = []struct {
|
||||
f string
|
||||
in, cutset, out string
|
||||
f string
|
||||
in, arg, out string
|
||||
}{
|
||||
{"Trim", "abba", "a", "bb"},
|
||||
{"Trim", "abba", "ab", ""},
|
||||
@ -520,6 +520,10 @@ var trimTests = []struct {
|
||||
{"TrimRight", "", "123", ""},
|
||||
{"TrimRight", "", "", ""},
|
||||
{"TrimRight", "☺\xc0", "☺", "☺\xc0"},
|
||||
{"TrimPrefix", "aabb", "a", "abb"},
|
||||
{"TrimPrefix", "aabb", "b", "aabb"},
|
||||
{"TrimSuffix", "aabb", "a", "aabb"},
|
||||
{"TrimSuffix", "aabb", "b", "aab"},
|
||||
}
|
||||
|
||||
func TestTrim(t *testing.T) {
|
||||
@ -533,12 +537,16 @@ func TestTrim(t *testing.T) {
|
||||
f = TrimLeft
|
||||
case "TrimRight":
|
||||
f = TrimRight
|
||||
case "TrimPrefix":
|
||||
f = TrimPrefix
|
||||
case "TrimSuffix":
|
||||
f = TrimSuffix
|
||||
default:
|
||||
t.Errorf("Undefined trim function %s", name)
|
||||
}
|
||||
actual := f(tc.in, tc.cutset)
|
||||
actual := f(tc.in, tc.arg)
|
||||
if actual != tc.out {
|
||||
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
|
||||
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user