How to convert string of []bytes to []bytes - go

main.go
package main
import "fmt"
func main() {
rawString := "Hello World"
myStringBytes := fmt.Sprint([]byte(rawString))
myResultString := string([]byte(myStringBytes))
fmt.Println(myResultString)
fmt.Println(rawString)
}
Output
[72 101 108 108 111 32 87 111 114 108 100]
Hello World
Why myResultString still in bytes form?
How to convert the string of []bytes to []bytes?
I want myResultString == rawString

Just used this function to resolve this problem.
Fyi, I used this method to parse semi colon query param from HTML request (:
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
rawString := "Hello World"
myStringBytes := fmt.Sprint([]byte(rawString))
myResultString, _ := string(StringBytesParseString(myStringBytes))
fmt.Println(myResultString)
fmt.Println(rawString)
}
func StringBytesParseString(byteString string) (string, error) {
byteString = strings.TrimSuffix(byteString, "]")
byteString = strings.TrimLeft(byteString, "[")
sByteString := strings.Split(byteString, " ")
var res []byte
for _, s := range sByteString {
i, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return "", err
}
res = append(res, byte(i))
}
return string(res), nil
}

Related

Find byte offset of a pattern in Golang

We can find the byte offset of a pattern from file by
"grep -ob pattern filename";
However, grep is not utf8 safe.
How do I find byte offset of a pattern in Go? The file is process log, which can be in TB.
This is what I want to get in Go:
$ cat fname
hello world
findme
hello 世界
findme again
...
$ grep -ob findme fname
12:findme
32:findme
FindAllStringIndex(s string, n int) returns byte start/finish indexes (i.e., slices) of all successive matches of the expression:
package main
import "fmt"
import "io/ioutil"
import "regexp"
func main() {
fname := "C:\\Users\\UserName\\go\\src\\so56798431\\fname"
b, err := ioutil.ReadFile(fname)
if err != nil {
panic(err)
}
re, err := regexp.Compile("findme")
if err != nil {
// handle error
}
fmt.Println(re.FindAllStringIndex(string(b), -1))
}
Output:
[[12 18] [32 38]]
Note: I did this on Microsoft Windows, but saved the file in UNIX format (linefeed); if input file saved in Windows format (carriage return & linefeed) the byte offsets would increment to 13 and 35, respectively.
UPDATE: for large files, use bufio.Scanner; for example:
package main
import (
"bufio"
"fmt"
"log"
"os"
"regexp"
)
func main() {
fname, err := os.Open("C:\\Users\\UserName\\go\\src\\so56798431\\fname")
if err != nil {
log.Fatal(err)
}
defer fname.Close()
re, err := regexp.Compile("findme")
if err != nil {
// handle error
}
scanner := bufio.NewScanner(fname)
bytesRead := 0
for scanner.Scan() {
b := scanner.Text()
//fmt.Println(b)
results := re.FindAllStringIndex(b, -1)
for _, result := range results {
fmt.Println(bytesRead + result[0])
}
// account for UNIX EOL marker
bytesRead += len(b) + 1
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
Output:
12
32

Convert slice of string input from console to slice of numbers

I'm trying to write a Go script that takes in as many lines of comma-separated coordinates as the user wishes, split and convert the string of coordinates to float64, store each line as a slice, and then append each slice in a slice of slices for later usage.
Example inputs are:
1.1,2.2,3.3
3.14,0,5.16
Example outputs are:
[[1.1 2.2 3.3],[3.14 0 5.16]]
The equivalent in Python is
def get_input():
print("Please enter comma separated coordinates:")
lines = []
while True:
line = input()
if line:
line = [float(x) for x in line.replace(" ", "").split(",")]
lines.append(line)
else:
break
return lines
But what I wrote in Go seems way too long (pasted below), and I'm creating a lot of variables without the ability to change variable type as in Python. Since I literally just started writing Golang to learn it, I fear my script is long as I'm trying to convert Python thinking into Go. Therefore, I would like to ask for some advice as to how to write this script shorter and more concise in Go style? Thank you.
package main
import (
"fmt"
"os"
"bufio"
"strings"
"strconv"
)
func main() {
inputs := get_input()
fmt.Println(inputs)
}
func get_input() [][]float64 {
fmt.Println("Please enter comma separated coordinates: ")
var inputs [][]float64
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
if len(scanner.Text()) > 0 {
raw_input := strings.Replace(scanner.Text(), " ", "", -1)
input := strings.Split(raw_input, ",")
converted_input := str2float(input)
inputs = append(inputs, converted_input)
} else {
break
}
}
return inputs
}
func str2float(records []string) []float64 {
var float_slice []float64
for _, v := range records {
if s, err := strconv.ParseFloat(v, 64); err == nil {
float_slice = append(float_slice, s)
}
}
return float_slice
}
Using only string functions:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
var result [][]float64
var txt string
for scanner.Scan() {
txt = scanner.Text()
if len(txt) > 0 {
values := strings.Split(txt, ",")
var row []float64
for _, v := range values {
fl, err := strconv.ParseFloat(strings.Trim(v, " "), 64)
if err != nil {
panic(fmt.Sprintf("Incorrect value for float64 '%v'", v))
}
row = append(row, fl)
}
result = append(result, row)
}
}
fmt.Printf("Result: %v\n", result)
}
Run:
$ printf "1.1,2.2,3.3
3.14,0,5.16
2,45,76.0, 45 , 69" | go run experiment2.go
Result: [[1.1 2.2 3.3] [3.14 0 5.16] [2 45 76 45 69]]
With given input, you can concatenate them to make a JSON string and then unmarshal (deserialize) that:
func main() {
var lines []string
for {
var line string
fmt.Scanln(&line)
if line == "" {
break
}
lines = append(lines, "["+line+"]")
}
all := "[" + strings.Join(lines, ",") + "]"
inputs := [][]float64{}
if err := json.Unmarshal([]byte(all), &inputs); err != nil {
fmt.Println(err)
return
}
fmt.Println(inputs)
}

Go Lang Scan doesent scan for next line

This scanner dosent scan for the next line. I will explain it in more detail when you see results...
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
var inputFileName string
var write string
fmt.Scanln(&inputFileName)
//func Join(a []string, sep string) string
s := []string{inputFileName, ".txt"}
inputFileName = strings.Join(s, "")
creator, err := os.Create(inputFileName)
check(err)
/*
*Writing
*/
fmt.Printf("The file name with %s what do you want to write?", inputFileName)
fmt.Scanln(&write)
if len(write) <= 0 {
panic("Cant be empty")
}
byteStringWrite := []byte(write)
//func (f *File) Write(b []byte) (n int, err error)
fmt.Println("BYTE : ", byteStringWrite)
fmt.Println("NONBYTE : ", write)
_, errWriter := creator.Write(byteStringWrite)
check(errWriter)
/**
*Reading File
*/
read, errRead := ioutil.ReadFile(inputFileName)
check(errRead)
readString := string(read)
fmt.Println("*******************FILE*********************")
fmt.Println(readString)
}
func check(e error) {
if e != nil {
panic(e)
}
}
Results:
Sample.txt //My User Input
The file name with Sample.txt what do you want to write?Hello World
BYTE : [72 101 108 108 111]
NONBYTE : Hello
*******************FILE*********************
Hello
So Here you can see it dosent look for the space. Meaning after the space it automatically quits. Can someone help me figure out this problem? Thankyou.
EDIT
Using bufio.ReadString();
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
"bufio"
)
func main() {
var inputFileName string
var write string
bio := bufio.NewReader(os.Stdin)
inputFileName, err := bio.ReadString('\n')
fmt.Println(inputFileName)
//func Join(a []string, sep string) string
s := []string{inputFileName, ".txt"}
inputFileName = strings.Join(s, "")
creator, err := os.Create(inputFileName)
check(err)
/*
*Writing
*/
fmt.Printf("The file name with %s what do you want to write?", inputFileName)
fmt.Scanln(&write)
if len(write) <= 0 {
panic("Cant be empty")
}
byteStringWrite := []byte(write)
//func (f *File) Write(b []byte) (n int, err error)
fmt.Println("BYTE : ", byteStringWrite)
fmt.Println("NONBYTE : ", write)
_, errWriter := creator.Write(byteStringWrite)
check(errWriter)
/**
*Reading File
*/
read, errRead := ioutil.ReadFile(inputFileName)
check(errRead)
readString := string(read)
fmt.Println("*******************FILE*********************")
fmt.Println(readString)
}
func check(e error) {
if e != nil {
panic(e)
}
}
Results:
amanuel2:~/workspace/pkg_os/07_Practice $ go run main.go
Sample
The file name with Sample
.txt what do you want to write?Something Else
BYTE : [83 111 109 101 116 104 105 110 103]
NONBYTE : Something
*******************FILE*********************
Something
Gives me correct .txt .. But same issue as above, it dosent take spaces
This is exactly what fmt.Scanln is supposed to do:
Scan scans text read from standard input, storing successive
space-separated values into successive arguments. Newlines count as
space. It returns the number of items successfully scanned. If that is
less than the number of arguments, err will report why.
If you want to read a line of text use bufio.Reader:
bio := bufio.NewReader(os.Stdin)
// in case you want a string which doesn't contain the newline
line, hasMoreInLine, err := bio.ReadLine()
s := string(line)
fmt.Println(s)
// in case you need a string which contains the newline
s, err := bio.ReadString('\n')
fmt.Println(s)

Go - How to convert binary string as text to binary bytes?

I have a text dump file with strings like this one:
x\x9cK\xb42\xb5\xaa.\xb6\xb2\xb0R\xcaK-\x09J\xccKOU
I need to convert them to []byte.
Can someone please suggest how this can be done in Go?
The python equivalent is decode('string_escape').
Here is one way of doing it. Note this isn't a complete decode of the python string_escape format, but may be sufficient given the example you've given.
playground link
package main
import (
"fmt"
"log"
"regexp"
"strconv"
)
func main() {
b := []byte(`x\x9cK\xb42\xb5\xaa.\xb6\xb2\xb0R\xcaK-\x09J\xccKOU`)
re := regexp.MustCompile(`\\x([0-9a-fA-F]{2})`)
r := re.ReplaceAllFunc(b, func(in []byte) []byte {
i, err := strconv.ParseInt(string(in[2:]), 16, 64)
if err != nil {
log.Fatalf("Failed to convert hex: %s", err)
}
return []byte{byte(i)}
})
fmt.Println(r)
fmt.Println(string(r))
}
I did have the idea of using the json decoder, but unfortunately it doesn't understand the \xYY syntax.
Here's how you might approach write a little parser (if you needed to support other esc things in the future):
import (
"fmt"
"encoding/hex"
)
func decode(bs string) ([]byte,error) {
in := []byte(bs)
res := make([]byte,0)
esc := false
for i := 0; i<len(in); i++ {
switch {
case in[i] == '\\':
esc = true
continue
case esc:
switch {
case in[i] == 'x':
b,err := hex.DecodeString(string(in[i+1:i+3]))
if err != nil {
return nil,err
}
res = append(res, b...)
i = i+2
default:
res = append(res, in[i])
}
esc = false
default:
res = append(res, in[i])
}
}
return res,nil
}
playground

How to read a file, abort with error if it's not valid UTF-8?

In Go, I want to read in a file line by line, into str's or []rune's.
The file should be encoded in UTF-8, but my program shouldn't trust it. If it contains invalid UTF-8, I want to properly handle the error.
There is bytes.Runes(s []byte) []rune, but that has no error return value. Will it panic on encountering invalid UTF-8?
For example,
package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"
"unicode/utf8"
)
func main() {
tFile := "text.txt"
t := []byte{'\xFF', '\n'}
ioutil.WriteFile(tFile, t, 0666)
f, err := os.Open(tFile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer f.Close()
r := bufio.NewReader(f)
s, err := r.ReadString('\n')
if err != nil {
fmt.Println(err)
os.Exit(1)
}
s = strings.TrimRight(s, "\n")
fmt.Println(t, s, []byte(s))
if !utf8.ValidString(s) {
fmt.Println("!utf8.ValidString")
}
}
Output:
[255 10] � [255]
!utf8.ValidString
For example:
import (
"io/ioutil"
"log"
"unicode/utf8"
)
// ...
buf, err := ioutil.ReadAll(fname)
if error != nil {
log.Fatal(err)
}
size := 0
for start := 0; start < len(buf); start += size {
var r rune
if r, size = utf8.DecodeRune(buf[start:]); r == utf8.RuneError {
log.Fatalf("invalid utf8 encoding at ofs %d", start)
}
}
utf8.DecodeRune godocs:
DecodeRune unpacks the first UTF-8 encoding in p and returns the rune
and its width in bytes. If the encoding is invalid, it returns
(RuneError, 1), an impossible result for correct UTF-8.

Resources