Trim string's suffix or extension?

StringGo

String Problem Overview


For example, I have a string, consists of "sample.zip". How do I remove the ".zip" extension using strings package or other else?

String Solutions


Solution 1 - String

Try:

basename := "hello.blah"
name := strings.TrimSuffix(basename, filepath.Ext(basename))

TrimSuffix basically tells it to strip off the trailing string which is the extension with a dot.

strings#TrimSuffix

Solution 2 - String

Edit: Go has moved on. Please see Keith's answer.

Use path/filepath.Ext to get the extension. You can then use the length of the extension to retrieve the substring minus the extension.

var filename = "hello.blah"
var extension = filepath.Ext(filename)
var name = filename[0:len(filename)-len(extension)]

Alternatively you could use strings.LastIndex to find the last period (.) but this may be a little more fragile in that there will be edge cases (e.g. no extension) that filepath.Ext handles that you may need to code for explicitly, or if Go were to be run on a theoretical O/S that uses a extension delimiter other than the period.

Solution 3 - String

This way works too:

var filename = "hello.blah"
var extension = filepath.Ext(filename)
var name = TrimRight(filename, extension)

but maybe Paul Ruane's method is more efficient?

Solution 4 - String

I am using go1.14.1, filepath.Ext did not work for me, path.Ext works fine for me

var fileName = "hello.go"
fileExtension := path.Ext(fileName)
n := strings.LastIndex(fileName, fileExtension)
fmt.Println(fileName[:n])

Playground: https://play.golang.org/p/md3wAq_obNc

Documnetation: https://golang.org/pkg/path/#Ext

Solution 5 - String

Here is example that does not require path or path/filepath:

func BaseName(s string) string {
   n := strings.LastIndexByte(s, '.')
   if n == -1 { return s }
   return s[:n]
}

and it seems to be faster than TrimSuffix as well:

PS C:\> go test -bench .
goos: windows
goarch: amd64
BenchmarkTrimFile-12            166413693                7.25 ns/op
BenchmarkTrimPath-12            182020058                6.56 ns/op
BenchmarkLast-12                367962712                3.28 ns/op

https://golang.org/pkg/strings#LastIndexByte

Solution 6 - String

This is just one line more performant. Here it is:

filename := strings.Split(file.Filename, ".")[0]

Solution 7 - String

Summary, including the case of multiple extension names abc.tar.gz and performance comparison.

temp_test.go

package _test
import ("fmt";"path/filepath";"strings";"testing";)
func TestGetBasenameWithoutExt(t *testing.T) {
	p1 := "abc.txt"
	p2 := "abc.tar.gz" // filepath.Ext(p2) return `.gz`
	for idx, d := range []struct {
		actual   interface{}
		expected interface{}
	}{
		{fmt.Sprint(p1[:len(p1)-len(filepath.Ext(p1))]), "abc"},
		{fmt.Sprint(strings.TrimSuffix(p1, filepath.Ext(p1))), "abc"},
		{fmt.Sprint(strings.TrimSuffix(p2, filepath.Ext(p2))), "abc.tar"},
		{fmt.Sprint(p2[:len(p2)-len(filepath.Ext(p2))]), "abc.tar"},
		{fmt.Sprint(p2[:len(p2)-len(".tar.gz")]), "abc"},
	} {
		if d.actual != d.expected {
			t.Fatalf("[Error] case: %d", idx)
		}
	}
}

func BenchmarkGetPureBasenameBySlice(b *testing.B) {
	filename := "abc.txt"
	for i := 0; i < b.N; i++ {
		_ = filename[:len(filename)-len(filepath.Ext(filename))]
	}
}

func BenchmarkGetPureBasenameByTrimSuffix(b *testing.B) {
	filename := "abc.txt"
	for i := 0; i < b.N; i++ {
		_ = strings.TrimSuffix(filename, filepath.Ext(filename))
	}
}

run cmd: go test temp_test.go -v -bench="^BenchmarkGetPureBasename" -run=TestGetBasenameWithoutExt

output

=== RUN   TestGetBasenameWithoutExt
--- PASS: TestGetBasenameWithoutExt (0.00s)
goos: windows
goarch: amd64
cpu: Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
BenchmarkGetPureBasenameBySlice
BenchmarkGetPureBasenameBySlice-8               356602328                3.125 ns/op
BenchmarkGetPureBasenameByTrimSuffix
BenchmarkGetPureBasenameByTrimSuffix-8          224211643                5.359 ns/op
PASS

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCoderView Question on Stackoverflow
Solution 1 - StringKeith CascioView Answer on Stackoverflow
Solution 2 - StringPaul RuaneView Answer on Stackoverflow
Solution 3 - StringAllan RuinView Answer on Stackoverflow
Solution 4 - StringCaffeinesView Answer on Stackoverflow
Solution 5 - StringZomboView Answer on Stackoverflow
Solution 6 - StringBitfiniconView Answer on Stackoverflow
Solution 7 - StringCarsonView Answer on Stackoverflow