Syntax rule for opening brace in Go for-loop - for-loop

Case 1
This program compiles successfully:
package main
import (
"fmt"
)
func main() {
i := 0
for ; i < 3; i++ {
fmt.Println(i)
}
}
Case 2
But this does not:
package main
import (
"fmt"
)
func main() {
i := 0
for ; i < 3; i++
{
fmt.Println(i)
}
}
This leads to error:
./prog.go:9:18: syntax error: unexpected newline, expecting { after for clause
Case 3
But this compiles successfully:
package main
import (
"fmt"
)
func main() {
i := 0
for
{
fmt.Println(i)
}
}
Question
Why is it that in case 2, the opening brace for for is not allowed in the next line but in case 3 it is allowed?

In short, when you have this in line:
for ; i < 3; i++
a semicolon will be inserted automatically, resulting in syntax error.
Spec: Semicolons:
When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is
an identifier
an integer, floating-point, imaginary, rune, or string literal
one of the keywords break, continue, fallthrough, or return
one of the operators and punctuation ++, --, ), ], or }
So in Case 2 the lexer will automatically insert a semicolon at the end of the line which when present will "render" the code syntactically incorrect.
Not in Case 3 when there is only a for in a line, no semicolon is inserted (as per the quoted rules above, semicolon is only inserted after the break, continue, fallthrough and return keywords). So in Case 3 the code will not be extended with a semicolon and will remain syntactically correct.
For more details, see How to break a long line of code in Golang?

package main
import (
"fmt"
)
func main() {
i := 0
for ; i < 3; i++{
fmt.Println(i)
}
}
works its just that putting { in a new line causes the error you get.
in case 3 you don't have any statement to evaluate, so new line doesn't cause an y problem.

Related

How can I clean the text for search using RegEx

I can use the below code to search if the text str contains any or both of the keys, i.e.if it contains "MS" or "dynamics" or both of them
package main
import (
"fmt"
"regexp"
)
func main() {
keys := []string{"MS", "dynamics"}
keysReg := fmt.Sprintf("(%s %s)|%s|%s", keys[0], keys[1], keys[0], keys[1]) // => "(MS dynamics)|MS|dynamics"
fmt.Println(keysReg)
str := "What is MS dynamics, is it a product from MS?"
re := regexp.MustCompile(`(?i)` + keysReg)
matches := re.FindAllString(str, -1)
fmt.Println("We found", len(matches), "matches, that are:", matches)
}
I want the user to enter his phrase, so I trim unwanted words and characters, then doing the search as per above.
Let's say the user input was: This,is,a,delimited,string and I need to build the keys variable dynamically to be (delimited string)|delimited|string so that I can search for my variable str for all the matches, so I wrote the below:
s := "This,is,a,delimited,string"
t := regexp.MustCompile(`(?i),|\.|this|is|a`) // backticks are used here to contain the expression, (?i) for case insensetive
v := t.Split(s, -1)
fmt.Println(len(v))
fmt.Println(v)
But I got the output as:
8
[ delimited string]
What is the wrong part in my cleaning of the input text, I'm expecting the output to be:
2
[delimited string]
Here is my playground
To quote the famous quip from Jamie Zawinski,
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
Two things:
Instead of trying to weed out garbage from the string ("cleaning" it), extract complete words from it instead.
Unicode is a compilcated matter; so even after you have succeeded with extracting words, you have to make sure your words are properly "escaped" to not contain any characters which might be interpreted as RE syntax before building a regexp of them.
package main
import (
"errors"
"fmt"
"regexp"
"strings"
)
func build(words ...string) (*regexp.Regexp, error) {
var sb strings.Builder
switch len(words) {
case 0:
return nil, errors.New("empty input")
case 1:
return regexp.Compile(regexp.QuoteMeta(words[0]))
}
quoted := make([]string, len(words))
for i, w := range words {
quoted[i] = regexp.QuoteMeta(w)
}
sb.WriteByte('(')
for i, w := range quoted {
if i > 0 {
sb.WriteByte('\x20')
}
sb.WriteString(w)
}
sb.WriteString(`)|`)
for i, w := range quoted {
if i > 0 {
sb.WriteByte('|')
}
sb.WriteString(w)
}
return regexp.Compile(sb.String())
}
var words = regexp.MustCompile(`\pL+`)
func main() {
allWords := words.FindAllString("\tThis\v\x20\x20,\t\tis\t\t,?a!,¿delimited?,string‽", -1)
re, err := build(allWords...)
if err != nil {
panic(err)
}
fmt.Println(re)
}
Further reading:
https://pkg.go.dev/regexp/syntax
https://pkg.go.dev/regexp#QuoteMeta
https://pkg.go.dev/unicode#pkg-variables and https://pkg.go.dev/unicode#Categories

how to realize mismatch of regexp in golang?

This is a multiple choice question example. I want to get the chinese text like "英国、法国", "加拿大、墨西哥", "葡萄牙、加拿大", "墨西哥、德国" in the content of following code in golang, but it does not work.
package main
import (
"fmt"
"regexp"
"testing"
)
func TestRegex(t *testing.T) {
text := `( B )38.目前,亚马逊美国站后台,除了有美国站点外,还有( )站点。
A.英国、法国B.加拿大、墨西哥
C.葡萄牙、加拿大D.墨西哥、德国
`
fmt.Printf("%q\n", regexp.MustCompile(`[A-E]\.(\S+)?`).FindAllStringSubmatch(text, -1))
fmt.Printf("%q\n", regexp.MustCompile(`[A-E]\.`).Split(text, -1))
}
text:
( B )38.目前,亚马逊美国站后台,除了有美国站点外,还有( )站点。
A.英国、法国B.加拿大、墨西哥
C.葡萄牙、加拿大D.墨西哥、德国
pattern: [A-E]\.(\S+)?
Actual result: [["A.英国、法国B.加拿大、墨西哥" "英国、法国B.加拿大、墨西哥"] ["C.葡萄牙、加拿大D.墨西哥、德国" "葡萄牙、加拿大D.墨西哥、德国"]].
Expect result: [["A.英国、法国" "英国、法国"] ["B.加拿大、墨西哥" "加拿大、墨西哥"] ["C.葡萄牙、加拿大" "葡萄牙、加拿大"] ["D.墨西哥、德国" "墨西哥、德国"]]
I think it might be a greedy mode problem. Because in my code, it reads option A and option B as one option directly.
Non-greedy matching won't solve this, you need positive lookahead, which re2 doesn't support.
As a workaround can just search on the labels and extract the text in between manually.
re := regexp.MustCompile(`[A-E]\.`)
res := re.FindAllStringIndex(text, -1)
results := make([][]string, len(res))
for i, m := range res {
if i < len(res)-1 {
results[i] = []string{text[m[0]:m[1]], text[m[1]:res[i+1][0]]}
} else {
results[i] = []string{text[m[0]:m[1]], text[m[1]:]}
}
}
fmt.Printf("%q\n", results)
Should print
[["A." "英国、法国"] ["B." "加拿大、墨西哥\n"] ["C." "葡萄牙、加拿大"] ["D." "墨西哥、德国\n"]]

Regular Expression with If Else Condition

I have a problem with If Else Condition in Regex. I have a file which contains the below format. I was looking for return value to be either 0.0.985 or 3.3.5-3811.
I was trying to use if else condition in regex but unable to do so, can anyone explain me while solving the problem please.
random-app-0.0.985.tgz
busy-app-7.3.1.2-3.3.5-3811-a19874elkc-123254376584.zip
Below is the Go code I am trying to use
package main
import (
"fmt"
"io/ioutil"
"regexp"
)
func main(){
content, err:= ioutil.ReadFile("version.txt")
if err != nil{
fmt.Println(err)
}
version:= string(content)
re:= regexp.MustCompile(`(\d+).(\d+).(\d+)|(\d+).(\d+).(\d+).(\d+)`)
result:= re.FindAllStringSubmatch(version,-1)
for i:= range(result){
fmt.Println(result[i][0])
}
}
Output is coming like
0.0.985
7.3.1
2-3.3
5-3811
19874
123254376584
The following regexp can be used: [\d\.]+[\.-][\d]{2,}
package main
import (
"regexp"
"fmt"
)
func main() {
var re = regexp.MustCompile(`(?m)[\d\.]+[\.-][\d]{2,}`)
var str = `random-app-0.0.985.tgz
busy-app-7.3.1.2-3.3.5-3811-a19874elkc-123254376584.zip`
for i, match := range re.FindAllString(str, -1) {
fmt.Println(match, "found at index", i)
}
}
The output
0.0.985 found at index 0
3.3.5-3811 found at index 1
playground
?m multi line modifier. Causes ^ and $ to match the begin/end of each line (not only begin/end of string). In this case it does not make to much difference. It will work without it.
[\d\.]+ matches at least once (quantifier +) a sequence of a digit or a dot
[\.-] matches a dot or a hypen
[\d]{2,} matches at least two digits (quantifier {2,})
One problem with your code is that in a regular expression . matches any character but you're intending it to match a literal dot. Use \. or [.] instead.

Problem yacc in golang: syntax error: unexpected $end

A cordial greeting.
I'm learning yacc in golang and i created this file:
%{
package main
import (
"fmt"
)
%}
%union{
ex string
}
%token <ex> DB OTHER_DB
%%
query: other
|
db
;
db: DB
{
fmt.Printf("\tDB: %s\n", $1 )
}
;
other: OTHER_DB
{
fmt.Printf("\tOTHER_DB: %s\n", $1 )
}
;
%%
type mlex struct {
expr string
result int
}
func (f *mlex) Lex(lval *yySymType) int {
yyErrorVerbose = true
return 0
}
func (f *mlex) Error(s string) {
fmt.Printf("syntax error: %s\n", s)
}
func Parse(expr string) int {
m := &mlex{expr, 0}
yyParse(m)
return m.result
}
but when executing it I get this error:
syntax error: syntax error: unexpected $end, expecting DB or OTHER_DB
I have been testing this yacc file with this code:
package main
import (
"fmt"
)
func main() {
res := Parse("db")
fmt.Println(res)
}
What could it be ? Will I need anything else in the yacc file?
I am trying to make a very simple, fully functional example to understand it well.
Thanks for your time.
When your parser needs to know what the next input symbol ("token") is, it calls the yyLexer's Lex method. Your implementation of that makes no attempt to read a token. Instead, it just returns 0:
func (f *mlex) Lex(lval *yySymType) int {
yyErrorVerbose = true
return 0
}
So from the parser's perspective, it is being given an empty input stream, regardless of what input you might actually have provided. It then attempts to parse this empty input, but your grammar doesn't permit it. The only valid inputs start with the tokens DB or OTHER_DB, and it doesn't see either of those things.
So it produces the error message, detailing exactly what its problem is. (The parser represents the end of input with the internal pseudo-token $end, in case that was confusing you.)

Post-increment operator in function argument in Go, not possible?

How come, in Go (1.2.1), this works?
package main
import (
"fmt"
)
func main() {
var i = 0
for i < 10 {
fmt.Println(i)
i++
}
}
But this (with the increment operator in the function argument) doesn't?
package main
import (
"fmt"
)
func main() {
var i = 0
for i < 10 {
fmt.Println(i++)
}
}
In Go, i++ is a statement, not an expression. So you can't use its value in another expression such as a function call.
This eliminates the distinction between post-increment and pre-increment, which is a source of confusion and bugs.

Resources