Retrieve first directory in URL-like string in Go - go

I am trying to obtain the first directory in an URL-like string like this: "/blog/:year/:daynum/:postname". I thought splitting it, then retrieving the first directory, would be this simple. But it returns square brackets surrounding the string even though it's not a slice. How can I get that first directory? (I am guaranteed that the string starts with a "/" followed by a valid directory designation and that contains both a leading directory and a string using those permalink properties).
What's the best way to parse out that first directory?
package main
import (
"fmt"
"strings"
)
// Retrieve the first directory in the URL-like
// string passed in
func firstDir(permalink string) string {
split := strings.Split(permalink, "/")
return string(fmt.Sprint((split[0:2])))
}
func main() {
permalink := "/blog/:year/:daynum/:postname"
dir := firstDir(permalink)
fmt.Printf("leading dir is: %s.", dir)
// Prints NOT "blog" but "[ blog]".
}

Since you said:"(I am guaranteed that the string starts with a "/" followed by a valid directory designation and that contains both a leading directory and a string using those permalink properties)"
Then simply use split[1] to get the root directory.
package main
import (
"fmt"
"os"
"strings"
)
func firstDir(permalink string) string {
split := strings.Split(permalink, string(os.PathSeparator))
return split[1]
}
func main() {
permalink := "/blog/:year/:daynum/:postname"
dir := firstDir(permalink)
fmt.Printf("leading dir is: %s.", dir)
// Prints "blog".
}
https://go.dev/play/p/hCHnrDIsWYE

Related

Get the next word after you match a word in a string

I am trying to get the next word after a match in a string.
For instance
var somestring string = "Hello this is just a random string"
to match the word I do this
strings.Contains(somestring, "just")
and in this case i would want to get the "a".
package main
import (
"fmt"
"strings"
)
func main() {
s := "Hello this is just a random string"
// find the index of string "just"
index := strings.Index(s, "just")
fmt.Println(index)
// get next single word after "just"
word := strings.Fields(s[index:])
fmt.Println(word[1])
}

Find a file by regex in Golang, given the regex and path

I'm trying to implement cache busting, via the following:
on the front end of things, I insert, via JS plugin, content hash to the asset filenames (e.g. bundle.1947shkey7.js)
in the HTML file, use some template tag to create the asset (e.g. <script>) tags for me
from the Golang side, have template func that will extract the directory path dirpath, create a regex from the filename filenameRegex, and use dirpath,filenameRegex to find the file and form the tag for it.
Most of this is already working, except I have no idea how best to do that regex-based find.
The regex for the file is something like [name].\\w+.[ext], for reference. This works and I've tested it.
However, how to use that regex and the dirpath to get the actual file's path? I know we can do something like
filepath.Walk(dirpath, func(path string, info os.FileInfo, err error) error {
// logic to check info.IsDir(), info.Name(), and written actual filename
})
but there's one problem with this: the complexity. If I understand this correctly, this is going to execute for every file in directory dirname!
Is this the only way to find the asset filename via regex or is there a much simpler way?
You can use something like this, where you can customize the callback to your
needs:
package main
import (
"io/fs"
"path/filepath"
)
func glob(root string, fn func(string)bool) []string {
var files []string
filepath.WalkDir(root, func(s string, d fs.DirEntry, e error) error {
if fn(s) {
files = append(files, s)
}
return nil
})
return files
}
func main() {
files := glob(".", func(s string) bool {
return filepath.Ext(s) == ".js"
})
for _, file := range files {
println(file)
}
}

string replace backslash with slash

I need to replace \ with / in a path string, but following code failed.
package main
import (
"fmt"
"strings"
)
func main() {
string := "P:\Project\project-name/content/topic/"
fmt.Println(strings.Replace(string, "\\", "/", -1))
}
Any helpful suggestions?
Use the function filepath.ToSlash to replace the operating system path separator with '/' in a path.
On Windows, the function returns strings.Replace(path, string(filepath.Separator), "/", -1). On other operating systems, the function returns the path argument as is.
You didn't escape backslashes in string. The following code works:
package main
import (
"fmt"
"strings"
)
func main() {
string := "P:\\Project\\project-name/content/topic/"
fmt.Println(strings.Replace(string, "\\", "/", -1))
}
Play this on playground: https://play.golang.org/p/T3XE5uiIkk
You can also use back-quotes (`) to create a raw string:
func main() {
string := `P:\Project\project-name/content/topic/`
fmt.Println(strings.Replace(string, "\\", "/", -1))
}
Note that the raw string above would still have its internal representation as
"P:\\Project\\project-name/content/topic/"
Hence the need to use "\\" in strings.Replace function.

Get the first directory of a path in GO

In Go, is it possible to get the root directory of a path so that
foo/bar/file.txt
returns foo? I know about path/filepath, but
package main
import (
"fmt"
"path/filepath"
)
func main() {
parts := filepath.SplitList("foo/bar/file.txt")
fmt.Println(parts[0])
fmt.Println(len(parts))
}
prints foo/bar/file.txt and 1 whereas I would have expected foo and 3.
Simply use strings.Split():
s := "foo/bar/file.txt"
parts := strings.Split(s, "/")
fmt.Println(parts[0], len(parts))
fmt.Println(parts)
Output (try it on the Go Playground):
foo 3
[foo bar file.txt]
Note:
If you want to split by the path separator of the current OS, use os.PathSeparator as the separator:
parts := strings.Split(s, string(os.PathSeparator))
filepath.SplitList() splits multiple joined paths into separate paths. It does not split one path into folders and file. For example:
fmt.Println("On Unix:", filepath.SplitList("/a/b/c:/usr/bin"))
Outputs:
On Unix: [/a/b/c /usr/bin]
Note that if you just need the first part, strings.SplitN is at least 10 times
faster from my testing:
package main
import "strings"
func main() {
parts := strings.SplitN("foo/bar/file.txt", "/", 2)
println(parts[0] == "foo")
}
https://golang.org/pkg/strings#SplitN

How do I parse URLs in the format of /id/123 not ?foo=bar

I'm trying to parse an URL like:
http://example.com/id/123
I've read through the net/url docs but it seems like it only parses strings like
http://example.com/blah?id=123
How can I parse the ID so I end up with the value of the id in the first example?
This is not one of my own routes but a http string returned from an openid request.
In your example /id/123 is a path and you can get the "123" part by using Base from the path module.
package main
import (
"fmt"
"path"
)
func main() {
fmt.Println(path.Base("/id/123"))
}
For easy reference, here's the docs on the path module. http://golang.org/pkg/path/#example_Base
You can try using regular expression as follow:
import "regexp"
re, _ := regexp.Compile("/id/(.*)")
values := re.FindStringSubmatch(path)
if len(values) > 0 {
fmt.Println("ID : ", values[1])
}
Here is a simple solution that works for URLs with the same structure as yours (you can improve to suit those with other structures)
package main
import (
"fmt"
"net/url"
)
var path = "http://localhost:8080/id/123"
func getFirstParam(path string) (ps string) {
// ignore first '/' and when it hits the second '/'
// get whatever is after it as a parameter
for i := 1; i < len(path); i++ {
if path[i] == '/' {
ps = path[i+1:]
}
}
return
}
func main() {
u, _ := url.Parse(path)
fmt.Println(u.Path) // -> "/id/123"
fmt.Println(getFirstParam(u.Path)) // -> "123"
}
Or, as #gollipher suggested, use the path package
import "path"
func main() {
u, _ := url.Parse(path)
ps := path.Base(u.Path)
}
With this method it's faster than regex, provided you know before hand the structure of the URL you are getting.

Resources