I working on some Go code but I am having troubles figuring out why my string isn't being scanned correctly.
I'm given a string that looks like this:
"ERROR: 1: something happened 'here'"
I'm trying to scan it like this:
n, err := fmt.Sscanf("ERROR: 1: something happened 'here'", "ERROR: 1: something happened '%50s'", &value)
However, every time I check the result of the value, I get something like this:
here'
Where the last single quote is left in.
Any idea how to fix this? I figured this case wouldn't be non-deterministic because the function can't complete formatting without including the quote.
Of course, I can simply remove the last character, but I would prefer a fmt-based solution.
The builtin fmt.Scanner has no way to do what you're trying to do. If the target text was wrapped in double quotes, you could use the %q specifier.
Alternatively, if the target was a single wrapped character, you could use text/scanner. But because your target is neither of those, there's nothing built in. So, your options are regexp, or bufio with a custom scanner, or even just strings.Split. If you insist on using fmt you can do a custom scanner, but it's probably the worst option of everything:
package main
import "fmt"
type quote struct { tok string }
func (q *quote) Scan(state fmt.ScanState, verb rune) error {
tok, err := state.Token(false, func(r rune) bool {
return r != 0x27 // '
})
if err != nil {
return err
}
if _, _, err := state.ReadRune(); err != nil {
if len(tok) == 0 {
panic(err)
}
}
q.tok = string(tok)
return nil
}
Example:
package main
import (
"fmt"
"strings"
)
func main() {
r := strings.NewReader("ERROR: 1: something happened 'here'")
for {
var q quote
_, err := fmt.Fscan(r, &q)
if err != nil {
break
}
fmt.Printf("%q\n", q.tok)
}
}
Result:
"ERROR: 1: something happened "
"here"
Related
I'm new to go and have been using split to my advantage. Recently I came across a problem I wanted to split something, and keep the splitting char in my second slice rather than removing it, or leaving it in the first slice as with SplitAfter.
For example the following code:
strings.Split("email#email.com", "#")
returned: ["email", "email.com"]
strings.SplitAfter("email#email.com", "#")
returned: ["email#", "email.com"]
What's the best way to get ["email", "#email.com"]?
Use strings.Index to find the # and slice to get the two parts:
var part1, part2 string
if i := strings.Index(s, "#"); i >= 0 {
part1, part2 = s[:i], s[i:]
} else {
// handle case with no #
}
Run it on the playground.
Could this work for you?
s := strings.Split("email#email.com", "#")
address, domain := s[0], "#"+s[1]
fmt.Println(address, domain)
// email #email.com
Then combing and creating a string
var buffer bytes.Buffer
buffer.WriteString(address)
buffer.WriteString(domain)
result := buffer.String()
fmt.Println(result)
// email#email.com
You can use bufio.Scanner:
package main
import (
"bufio"
"strings"
)
func email(data []byte, eof bool) (int, []byte, error) {
for i, b := range data {
if b == '#' {
if i > 0 {
return i, data[:i], nil
}
return len(data), data, nil
}
}
return 0, nil, nil
}
func main() {
s := bufio.NewScanner(strings.NewReader("email#email.com"))
s.Split(email)
for s.Scan() {
println(s.Text())
}
}
https://golang.org/pkg/bufio#Scanner.Split
I'm using to fmt.Sscan convert a string to any type, here is what I'm doing:
package main
import (
"fmt"
"reflect"
)
func test() interface{} {
return 0
}
func main() {
a := test() // this could be any type
v := "10" // this could be anything
fmt.Println(reflect.TypeOf(a), reflect.TypeOf(&a))
_, err := fmt.Sscan(v, &a)
fmt.Println(err)
}
This code is failing because Sscan doesn't accept interfaces as the second value: can't scan type: *interface {}. demo
What I find most weird is that the first print prints: int *interface {}, is it a int or an interface?
How can I assert a to the right type (it could be any primitive)? Is there a solution that doesn't include a giant switch statement?
Thank you.
Here's how to convert a string to a value of any type supported by the fmt package:
// convert converts s to the type of argument t and returns a value of that type.
func convert(s string, t interface{}) (interface{}, error) {
// Create pointer to value of the target type
v := reflect.New(reflect.TypeOf(t))
// Scan to the value by passing the pointer SScan
_, err := fmt.Sscan(s, v.Interface())
// Dereference the pointer and return the value.
return v.Elem().Interface(), err
}
Call it like this:
a := test()
a, err := convert("10", a)
fmt.Println(a, err)
Run it on the Playground
currently working with the vishvananda/netns package trying to extract routes from a specific network namespace.
There is a defined Handle struct which is returned when I request a 'handle' for a specific network namespace. As such:
func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error)
This is then a receiver argument (?) to a function that requires that handle,
func (h *Handle) LinkList() ([]Link, error)
I'm new to go and not sure how to tie these together. I'm stuck with:
func (h *Handle) showInts() {
int, err := h.netlink.LinkList()
if err != nil {
log.Fatal(err)
}
for i, r := range int {
log.Printf("%d: %s", i, r.Attrs().Name)
}
}
func main() {
ints, err := netlink.LinkList()
if err != nil {
log.Fatal(err)
}
for i, r := range ints {
log.Printf("%d: %s", i, r.Attrs().Name)
}
pid, err := netns.GetFromPid(9097)
if err != nil {
log.Fatal(err)
}
netlink.NewHandleAt(pid)
showInts()
}
Update
While writing the original answer, touched on a number of things, without any clear structure, so here's a more structured version:
Depending on what you're actually asking (ie "How do I add a receiver function/method to an exported type", or "What the hell is a receiver function"), the answers are as follows:
How do I add a receiver function to an exported type?
Easy, same as you do with any other type. You were close, in fact. This doesn't work:
func (h *Handler) showInts() {}
Because you're adding a method to the Handler type in your package. Given you have a main function, that would be the main package. You're trying to add it to the netlink.Handler type instead. In which case, this will work:
func (h *netlink.Handler) showInts(){}
The type is netlink.Handler in your main package after all... This, however will not work. The compiler will refuse to compile, telling you: "Cannot define new methods on non-local type". This is easily mitigated, though, by creating a new type, and add the method there:
type MyHandler netlink.Handler
func (h *MyHandler) showInts(){}
Be that as it may, the last 2 lines in your code strike me as wrong.
Given that NewHandleAt returns (*Handle, error), and netlink.Handle is a receiver argument, the correct way would be:
var mh *MyHandle
if h, err := netlink.NewHandleAt(pid); err != nil {
log.Fatal(err) // something went wrong
} else {
mh = (*MyHandle)(h)
}
mh.showInts() // call showInts on mh, which is of type *MyHandle
The fact that you've "wrapped" the external type in a custom type does mean you'll find yourself casting the same thing quite a lot. Say netlink.Handle has a Test method, and you want to call it inside showInts:
func (h *MyHandle) showInts() {
nh := (*netlink.Handle)(h) //cast required
nh.Test()
}
I'd also change the varname from pid to nsh or something, because it's a NsHandle, and not a pid after all...
What is a receiver argument?
Because you wrote this:
This is then a receiver argument (?) to a function that requires that handle,
I get the impression you're not entirely clear on what a receiver argument is. Put simply, it's like a function argument, but instead of an argument that is just passed to a function, it's an argument that holds the object/value on which the function is called. Basically, it's the "instance" on which the function/method is called. Think of it as the this keyword in many OOP languages:
func (h *MyHandle) showInts() {
return
}
In something like C++ would be
class MyHandle : Handle
{
public:
void showInts(void) { return; } // replace h with this
}
There are significant differences, however:
The receiver argument can be a pointer, or a value - in case of a value receiver, the method cannot modify the receiver value
There's no such thing as private, public, or protected... at least not in the traditional OO way
...
There's quite a few differences, perhaps consider going through the golang tour. The stuff about go methods can be found here
Other issues/weird things
After looking at your code again, I'm really not sure whether this is correct:
h.netlink.LinkList()
In your main function, you call netlink.LinkList(). h is a *netlink.Handler. If you need to call the netlink.LinkList function, it's highly likely h.netlink.LinkList is not what you want to do. Instead, you should simply call netlink.LinkList().
That's assuming you need to call the function in the first place.
Given that you've already called it in the main function, why not pass it as an argument?
//in main:
ints, err := netlink.LinkList()
//...
h.showInts(ints)
func (h *MyHandle)showInts(ll []netlink.Link) {
}
Thanks Elias, awesome answer!
From that, I've written the following code which will list interfaces belonging to a specific namespace. Thanks!
package main
import (
"github.com/vishvananda/netns"
"github.com/vishvananda/netlink"
"log"
)
type NSHandle netlink.Handle
func (h *NSHandle) showInts() {
nh := (*netlink.Handle)(h) //cast required
int, err := nh.LinkList()
if err != nil {
log.Fatal(err)
}
log.Printf("Namespace Ints:")
for i, r := range int {
log.Printf("%d: %s", i, r.Attrs().Name)
}
}
func getNSFromPID(pid int) (*NSHandle) {
hpid, err := netns.GetFromPid(9115)
if err != nil {
log.Fatal(err)
}
var nsh *NSHandle
if h, err := netlink.NewHandleAt(hpid); err != nil {
log.Fatal(err) // something went wrong
} else {
nsh = (*NSHandle)(h)
}
return nsh
}
func main() {
getNSFromPID(9115).showInts()
}
Is there any way to range over a string in Go templates (that is, from the code in the template itself, not from native Go)? It doesn't seem to be supported directly (The value of the pipeline must be an array, slice, map, or channel.), but is there some hack like splitting the string into an array of single-character strings or something?
Note that I am unable to edit any go source: I'm working with a compiled binary here. I need to make this happen from the template code alone.
You can use FuncMap to split string into characters.
package main
import (
"text/template"
"log"
"os"
)
func main() {
tmpl, err := template.New("foo").Funcs(template.FuncMap{
"to_runes": func(s string) []string {
r := []string{}
for _, c := range []rune(s) {
r = append(r, string(c))
}
return r
},
}).Parse(`{{range . | to_runes }}[{{.}}]{{end}}`)
if err != nil {
log.Fatal(err)
}
err = tmpl.Execute(os.Stdout, "hello world")
if err != nil {
log.Fatal(err)
}
}
This should be:
[h][e][l][l][o][ ][w][o][r][l][d]
here is my code and I don't understand why the decode function doesn't work.
Little insight would be great please.
func EncodeB64(message string) (retour string) {
base64Text := make([]byte, base64.StdEncoding.EncodedLen(len(message)))
base64.StdEncoding.Encode(base64Text, []byte(message))
return string(base64Text)
}
func DecodeB64(message string) (retour string) {
base64Text := make([]byte, base64.StdEncoding.DecodedLen(len(message)))
base64.StdEncoding.Decode(base64Text, []byte(message))
fmt.Printf("base64: %s\n", base64Text)
return string(base64Text)
}
It gaves me :
[Decode error - output not utf-8][Decode error - output not utf-8]
The len prefix is superficial and causes the invalid utf-8 error:
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
str := base64.StdEncoding.EncodeToString([]byte("Hello, playground"))
fmt.Println(str)
data, err := base64.StdEncoding.DecodeString(str)
if err != nil {
log.Fatal("error:", err)
}
fmt.Printf("%q\n", data)
}
(Also here)
Output
SGVsbG8sIHBsYXlncm91bmQ=
"Hello, playground"
EDIT: I read too fast, the len was not used as a prefix. dystroy got it right.
DecodedLen returns the maximal length.
This length is useful for sizing your buffer but part of the buffer won't be written and thus won't be valid UTF-8.
You have to use only the real written length returned by the Decode function.
l, _ := base64.StdEncoding.Decode(base64Text, []byte(message))
log.Printf("base64: %s\n", base64Text[:l])
To sum up the other two posts, here are two simple functions to encode/decode Base64 strings with Go:
// Dont forget to import "encoding/base64"!
func base64Encode(str string) string {
return base64.StdEncoding.EncodeToString([]byte(str))
}
func base64Decode(str string) (string, bool) {
data, err := base64.StdEncoding.DecodeString(str)
if err != nil {
return "", true
}
return string(data), false
}
Try it!
#Denys Séguret's answer is almost 100% correct. As an improvement to avoid wasting memory with non used space in base64Text, you should use base64.DecodedLen. Take a look at how base64.DecodeString uses it.
It should look like this:
func main() {
message := base64.StdEncoding.EncodeToString([]byte("Hello, playground"))
base64Text := make([]byte, base64.StdEncoding.DecodedLen(len(message)))
n, _ := base64.StdEncoding.Decode(base64Text, []byte(message))
fmt.Println("base64Text:", string(base64Text[:n]))
}
Try it here.
More or less like above, but using []bytes and part of a bigger struct:
func (s secure) encodePayload(body []byte) string {
//Base64 Encode
return base64.StdEncoding.EncodeToString(body)
}
func (s secure) decodePayload(body []byte) ([]byte, error) {
//Base64 Decode
b64 := make([]byte, base64.StdEncoding.DecodedLen(len(body)))
n, err := base64.StdEncoding.Decode(b64, body)
if err != nil {
return nil, err
}
return b64[:n], nil
}