Get string length from user input - go

I want to get the string length, here my code:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Text to send: ")
text, _ := reader.ReadString('\n')
fmt.Print(strconv.Itoa(len(text)))
}
For input: aaa
The output is 5 but should be 3.
I know I can just subtract -2 from the result but I want "cleaner" way

You need to remove whitespaces from your input:
import (
"fmt"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Text to send: ")
text, _ := reader.ReadString('\n')
newText := strings.TrimSpace(text)
fmt.Print(strconv.Itoa(len(newText)))
}

Related

How to read a string with fmt.Scan after using bufio for reading a line in Go?

I read a line with bufio.NewReader(os.Stdin), then I read a string with fmt.Scanf.
package main
import (
"fmt"
"bufio"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var str string
inp, _ := reader.ReadString('\n')
fmt.Scanf("%s", &str)
fmt.Println(inp)
fmt.Printf(str)
}
Input:
This is a sentence.
John
I expect the output to be like above, but it isn't.
Output:
This is a sentence.
actually fmt.Scanf("%s", &str) doesn't work.
What is the problem? and How can I fix it?
reader.ReadString(delim) reads everything up to the delim, including the delimiter. So, it adds \n between two inputs. fmt.Printf(str) does not have \n in the end, so the second output sticks to the next thing printed to stdout.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var str string
inp, _ := reader.ReadString('\n')
fmt.Scanf("%s", &str)
fmt.Println(inp)
fmt.Printf(str)
}
Input:
some line
John
Output:
some line
John
Below is the code that runs as you want it to.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var str string
inp, _ := reader.ReadString('\n')
fmt.Scanf("%s", &str)
fmt.Print(inp)
fmt.Printf("%s\n", str)
}

Unexpected StrComp result when string is sent from golang app

In my code below I've set up a ReadString which reads user input and passes it along in a exec.Command.
This works just fine, but when I try to compare the string with a hardcoded string in vbscript (in this case I'm comparing it to "hello") it always fails even when the user input is "hello" as well.
If I just run the vbscript through the command line like this however...
cscript.exe script.vbs hello
...then the StrComp works as intended so I suspect that it's either a data type issue or there's some extra character that's passed along in the golang app.
Here's the main.go:
package main
import (
"fmt"
"os/exec"
"bufio"
"os"
)
func main() {
buf := bufio.NewReader(os.Stdin)
fmt.Print("Type something: ")
text, err := buf.ReadString('\n')
if err != nil {
fmt.Println(err)
} else {
args := []string{"./script.vbs", string(text)}
exec.Command("cscript.exe", args...).Run()
}
}
And here's the script.vbs
MsgBox(WScript.Arguments(0))
If StrComp(WScript.Arguments(0), "hello") = 0 Then
MsgBox("it's the same")
Else
MsgBox("It's not the same...")
End If
When working with windows, line endings are "\r\n". I don't know whether ReadString() should remove the delimiter, but even then text will contain an invisible \r. Use strings.TrimSpace to be on the save side:
package main
import (
"fmt"
"os/exec"
"bufio"
"os"
"strings"
)
func main() {
buf := bufio.NewReader(os.Stdin)
fmt.Print("Type something: ")
text, err := buf.ReadString('\n')
fmt.Printf("0 got: %T %v %q\r\n", text, text, text)
text = strings.TrimSpace(text)
fmt.Printf("1 got: %T %v %q", text, text, text)
if err != nil {
fmt.Println(err)
} else {
args := []string{"./script.vbs", string(text)}
exec.Command("cscript.exe", args...).Run()
}
}
output (of main; use your imagination for the VBScript MsgBoxes):
main
Type something: hello
0 got: string hello
"hello\r\n"
1 got: string hello "hello"

strconv.Atoi in Go (Basic calculator)

I'm trying to make a basic adding calculator in Go (complete noob here), but every time I'm getting an output of 0.
This is the code:
package main
import (
"fmt"
"strconv"
//"flag"
"bufio"
"os"
)
func main(){
reader := bufio.NewReader(os.Stdin)
fmt.Print("What's the first number you want to add?: ")
firstnumber, _ := reader.ReadString('\n')
fmt.Print("What's the second number you want to add?: ")
secondnumber, _ := reader.ReadString('\n')
ifirstnumber, _ := strconv.Atoi(firstnumber)
isecondnumber, _ := strconv.Atoi(secondnumber)
total := ifirstnumber + isecondnumber
fmt.Println(total)
}
bufio.Reader.ReadString() returns data up until and including the separator. So your string actually ends up being "172312\n". strconv.Atoi() doesn't like that and returns 0. It actually returns an error but you're ignoring it with _.
You can see what happens with this example:
package main
import (
"fmt"
"strconv"
)
func main(){
ifirstnumber, err := strconv.Atoi("1337\n")
isecondnumber, _ := strconv.Atoi("1337")
fmt.Println(err)
fmt.Println(ifirstnumber, isecondnumber)
}
You can trim the newlines with strings.Trim(number, "\n").

Passing variable as argument for exec.Command()

I want to read user input and use it as an argument for a command. I got this code:
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter img path: ")
imgPath, _ := reader.ReadString('\n')
args := []string{imgPath, "stdout", "-l spa+eng"}
out, err := exec.Command("tesseract", args...).Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
}
But when I execute it it outputs an error saying exit status 1.
If instead of using the variable imgPath as an argument I write some text directly into the array it works like a charm.
The following code returns a line with the delimiter (I work on Windows and its EOL is '\r\n'), something that wasn't shown when I printed it on the console.
reader := bufio.NewReader(os.Stdin)
imgPath, _ := reader.ReadString('\n')
In my case it ended up working after I trimmed '\r\n' from the input:
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter img path: ")
imgPath, _ := reader.ReadString('\n')
imgPath= strings.TrimRight(line, "\r\n")
args := []string{imgPath, "stdout", "-l spa+eng"}
out, err := exec.Command("tesseract", args...).Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
}

Extract part of string in Golang?

I'm learning Golang so I can rewrite some of my shell scripts.
I have URL's that look like this:
https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value
I want to extract the following part:
https://example-1.example.com/a/c482dfad3573acff324c/list.txt
In a shell script I would do something like this:
echo "$myString" | grep -o 'http://.*.txt'
What is the best way to do the same thing in Golang, only by using the standard library?
There are a few options:
// match regexp as in question
pat := regexp.MustCompile(`https?://.*\.txt`)
s := pat.FindString(myString)
// everything before the query
s := strings.Split(myString, "?")[0] string
// same as previous, but avoids []string allocation
s := myString
if i := strings.IndexByte(s, '?'); i >= 0 {
s = s[:i]
}
// parse and clear query string
u, err := url.Parse(myString)
u.RawQuery = ""
s := u.String()
The last option is the best because it will handle all possible corner cases.
try it on the playground
you may use strings.IndexRune, strings.IndexByte, strings.Split, strings.SplitAfter, strings.FieldsFunc, url.Parse, regexp or your function.
first most simple way:
you may use i := strings.IndexRune(s, '?') or i := strings.IndexByte(s, '?') then s[:i] like this (with commented output):
package main
import "fmt"
import "strings"
func main() {
s := `https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value`
i := strings.IndexByte(s, '?')
if i != -1 {
fmt.Println(s[:i]) // https://example-1.example.com/a/c482dfad3573acff324c/list.txt
}
}
or you may use url.Parse(s) (I'd use this):
package main
import "fmt"
import "net/url"
func main() {
s := `https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value`
url, err := url.Parse(s)
if err == nil {
url.RawQuery = ""
fmt.Println(url.String()) // https://example-1.example.com/a/c482dfad3573acff324c/list.txt
}
}
or you may use regexp.MustCompile(".*\\.txt"):
package main
import "fmt"
import "regexp"
var rgx = regexp.MustCompile(`.*\.txt`)
func main() {
s := `https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value`
fmt.Println(rgx.FindString(s)) // https://example-1.example.com/a/c482dfad3573acff324c/list.txt
}
or you may use splits := strings.FieldsFunc(s, func(r rune) bool { return r == '?' }) then splits[0]:
package main
import "fmt"
import "strings"
func main() {
s := `https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value`
splits := strings.FieldsFunc(s, func(r rune) bool { return r == '?' })
fmt.Println(splits[0]) // https://example-1.example.com/a/c482dfad3573acff324c/list.txt
}
you may use splits := strings.Split(s, "?") then splits[0]:
package main
import "fmt"
import "strings"
func main() {
s := `https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value`
splits := strings.Split(s, "?")
fmt.Println(splits[0]) // https://example-1.example.com/a/c482dfad3573acff324c/list.txt
}
you may use splits := strings.SplitAfter(s, ".txt") then splits[0]:
package main
import "fmt"
import "strings"
func main() {
s := `https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value`
splits := strings.SplitAfter(s, ".txt")
fmt.Println(splits[0]) // https://example-1.example.com/a/c482dfad3573acff324c/list.txt
}
or you may use your function (most independent way):
package main
import "fmt"
func left(s string) string {
for i, r := range s {
if r == '?' {
return s[:i]
}
}
return ""
}
func main() {
s := `https://example-1.example.com/a/c482dfad3573acff324c/list.txt?parm1=value,parm2=value,parm3=https://example.com/a?parm1=value,parm2=value`
fmt.Println(left(s)) // https://example-1.example.com/a/c482dfad3573acff324c/list.txt
}
If you are prosessing only URLs, you can use Go's net/url library https://golang.org/pkg/net/url/ to parse the URL, truncate the Query and Fragment parts (Query would be parm1=value,parm2=value etc.), and extract the remaining portion scheme://host/path, as in the following example (https://play.golang.org/p/Ao0jU22NyA):
package main
import (
"fmt"
"net/url"
)
func main() {
u, _ := url.Parse("https://example-1.example.com/a/b/c/list.txt?parm1=value,parm2=https%3A%2F%2Fexample.com%2Fa%3Fparm1%3Dvalue%2Cparm2%3Dvalue#somefragment")
u.RawQuery, u.Fragment = "", ""
fmt.Printf("%s\n", u)
}
Output:
https://example-1.example.com/a/b/c/list.txt
I used regexp package extract string from string .
In this example I wanted to extract between and <\PERSON> , did this by re expression and and replaced and <\PERSON> by re1 expression.
for loop used for if there there are multiple match and re1 format used for replace.
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`<PERSON>(.*?)</PERSON>`)
string_l := "java -mx500m -cp stanford-ner.jar edu.stanford.nlp.ie.crf.CRFClassifier -loadClassifier classifiers/english.all.3class.distsim.crf.ser.gz -textFile PatrickYe.txt -outputFormat inlineXML 2> /dev/null I complained to <ORGANIZATION>Microsoft</ORGANIZATION> about <PERSON>Bill Gates</PERSON>.They told me to see the mayor of <PERSON>New York</PERSON>.,"
x := re.FindAllString(string_l, -1)
fmt.Println(x)
for v,st:= range x{
re1 := regexp.MustCompile(`<(.?)PERSON>`)
y1 := re1.ReplaceAllLiteralString(st,"")
fmt.Println(v,st," : sdf : ",y1)
}
}
Play with Go

Resources