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)))
}
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"
I am new in GoLang and I am encountering a problem with this condition:
Even if the input of the user is "1", it doesn't enter in the if statement.
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"math"
"strings"
)
func prompt(toprint string) string{
if(toprint == ""){
toprint = "Enter text :";
}
reader := bufio.NewReader(os.Stdin);
fmt.Println(toprint);
text, _ := reader.ReadString('\n');
return text;
}
func main() {
choice := prompt("Please enter '1'");
if(strings.Compare("1",choice)==0||choice=="1"){
// D'ONT ENTER HERE EVEN WHEN choice=="1"
}else{
// Always go here
}
}
Thank you for your help.
This is because reader.ReadString returns all the text including the delimiter, so the string returned will be 1\n not just 1. From the documentation (my emphasis):
func (*Reader) ReadString
func (b *Reader) ReadString(delim byte) (string, error)
ReadString reads until the first occurrence of delim in the input, returning a string containing the data up to and including the delimiter. If ReadString encounters an error before finding a delimiter, it returns the data read before the error and the error itself (often io.EOF). ReadString returns err != nil if and only if the returned data does not end in delim. For simple uses, a Scanner may be more convenient.
Perhaps you want to do
return strings.TrimSpace(text)
at the end of prompt().
Thank you !
Here's the "prompt()" code which returns the correct input :
func prompt(toprint string) string{
if(toprint == ""){
toprint = "Enter text :";
}
reader := bufio.NewReader(os.Stdin);
fmt.Println(toprint);
text, _ := reader.ReadString('\n');
return text[0:len(text)-2];
}
I am playing around with Go. I want to make it so when someone enters 'hi' it prints hiii
Here is my code
package main
import (
"fmt"
"bufio"
"os"
)
func main(){
reader := bufio.NewReader(os.Stdin)
fmt.Println("Simple Shell")
fmt.Println("---------------------")
for {
fmt.Print("-> ")
text, _ := reader.ReadString('\n')
if (text == "hi") {
fmt.Println("hiii")
}
}
}
There is a trick to that: When using ReadString and ReadBytes function with a delimiter, the returned string (and bytes) contains the delimiter. That's why the condition is not true, your actual string is "hi\n" and not "hi".
In order to read from stdin, you can use the ReadLine function, or manually trim the end line characters with packages strings and bytes.
Also, you can use a Scanner, it reads lines by default. Here are some examples which all do the same job:
package main
import (
"bufio"
"bytes"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("-> ")
text, _, _ := reader.ReadLine()
if string(text) == "hi" {
fmt.Println("hii")
}
fmt.Print("-> ")
stext, _ := reader.ReadString('\n') // stext ends with '\n', it reads the delimiter
stext = strings.TrimRight(stext, "\n")
if stext == "hi" {
fmt.Println("hii")
}
fmt.Print("-> ")
text, _ = reader.ReadBytes('\n')
text = bytes.TrimRight(text, "\n")
if string(text) == "hi" {
fmt.Println("hii")
}
fmt.Print("-> ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
stext = scanner.Text()
if stext == "hi" {
fmt.Println("hii")
}
fmt.Print("−> ")
scanner.Scan()
text = scanner.Bytes()
if string(text) == "hi" {
fmt.Println("hii")
}
}
Just add \n such that
if text == "hi\n" {
fmt.Println("hiii")
}
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