Evaluate formula in Go - go

Using Go (golang) I'd like to take a string with a formula and evaluate it with pre-defined values. Here's a way to do it with python's parser module:
x = 8
code = parser.expr("(x + 2) / 10").compile()
print eval(code)
# prints 1
Any idea how to do it with Go?

This package will probably work for your needs: https://github.com/Knetic/govaluate
expression, err := govaluate.NewEvaluableExpression("(x + 2) / 10");
parameters := make(map[string]interface{}, 8)
parameters["x"] = 8;
result, err := expression.Evaluate(parameters);

You will probably need to resort to a library that interprets math statements or have to write your own parser. Python being a dynamic language can parse and execute python code at runtime. Standard Go cannot do that.
If you want to write a parser on your own, the go package will be of help. Example (On play):
import (
"go/ast"
"go/parser"
"go/token"
)
func main() {
fs := token.NewFileSet()
tr, _ := parser.ParseExpr("(3-1) * 5")
ast.Print(fs, tr)
}
The resulting AST (Abstract Syntax Tree) can then be traversed and interpreted as you choose (handling '+' tokens as addition for the now stored values, for example).

I have made my own equation evaluator, using Djikstra's Shunting Yard Algorithm.
It supports all operators, nested parenthesis, functions and even user defined variables.
It is written in pure go
https://github.com/marcmak/calc

go-exprtk package will probably meet all kinds of your needs to evaluate any kind of mathematical expression dynamically.
package main
import (
"fmt"
"github.com/Pramod-Devireddy/go-exprtk"
)
func main() {
exprtkObj := exprtk.NewExprtk()
exprtkObj.SetExpression("(x + 2) / 10")
exprtkObj.AddDoubleVariable("x")
exprtkObj.CompileExpression()
exprtkObj.SetDoubleVariableValue("x", 8)
fmt.Println(exprtkObj.GetEvaluatedValue())
}
This package has many capabilities

There is no such module in Go. You have to build your own. You could use subpackages of the go package, but they might be overkill for your application.

For expression or program evaluation, you can build a lexer and parser using lex and yacc, and specify exactly the syntax and semantics of your mini-language. A calculator has always been a standard yacc example, and the go versions of lex and yacc are no different.
Here's a pointer to the calc example: https://github.com/golang-samples/yacc/tree/master/simple

With this code you can evaluate dynamically any formula and return true or false:
package main
import (
"go/token"
"go/types"
)
func main() {
fs := token.NewFileSet()
tv, err := types.Eval(fs, nil, token.NoPos, "(1 + 4) >= 5")
if err != nil {
panic(err)
}
println(tv.Value.String())
}

There's nothing built in that could do that (remember, Go is not a dynamic language).
However, you can always use bufio.Scanner and build your own parser.

Googling around I found this: https://github.com/sbinet/go-eval
It appears to be an eval loop for Go.
go get github.com/sbinet/go-eval/cmd/go-eval
go install github.com/sbinet/go-eval/cmd/go-eval
go-eval

Related

In Go 1.18 strings.Title() is deprecated. What to use now? And how?

As suggested here names of people should be capitalized like John William Smith.
I'm writing a small software in Golang which gets last and first name from user's form inputs.
Until Go 1.18 I was using:
lastname = strings.Title(strings.ToLower(strings.TrimSpace(lastname)))
firstname = strings.Title(strings.ToLower(strings.TrimSpace(firstname)))
It works but now Go 1.18 has deprecated strings.Title().
They suggest to use golang.org/x/text/cases instead.
So I think I should change my code in something like this:
caser := cases.Title(language.Und)
lastname = caser.Title(strings.ToLower(strings.TrimSpace(lastname)))
firstname = caser.Title(strings.ToLower(strings.TrimSpace(firstname)))
It works the same as before.
The difference is for Dutch word like ijsland that should be titled as IJsland and not Ijsland.
The question
In the line caser := cases.Title(language.Und) I'm using Und because I don't know what language Tag to use.
Should I use language.English or language.AmericanEnglish or other?
So far it was like strings.Title() was using Und or English?
As mentioned in documentation strings.Title is deprecated and you should use cases.Title instead.
Deprecated: The rule Title uses for word boundaries does not handle
Unicode punctuation properly. Use golang.org/x/text/cases instead.
Here is an example code of how to use it as from two perspectives:
// Straightforward approach
caser := cases.Title(language.BrazilianPortuguese)
titleStr := caser.String(str)
// Transformer interface aware approach
src := []byte(s)
dest := []byte(s) // dest can also be `dest := src`
caser := cases.Title(language.BrazilianPortuguese)
_, _, err := caser.Transform(dest, src, true)
Make sure to take a look on the transform.Transformer.Transform and cases.Caser in order to understand what each parameter and return values mean, as well as the tool's limitations. For example:
A Caser may be stateful and should therefore not be shared between
goroutines.
Regarding what language to use, you should be aware of their difference in the results, besides that, you should be fine with any choice. Here is a copy from 煎鱼's summary on the differences that cleared it for me:
Go Playground: https://go.dev/play/p/xp59r1BkC9L
func main() {
src := []string{
"hello world!",
"i with dot",
"'n ijsberg",
"here comes O'Brian",
}
for _, c := range []cases.Caser{
cases.Lower(language.Und),
cases.Upper(language.Turkish),
cases.Title(language.Dutch),
cases.Title(language.Und, cases.NoLower),
} {
fmt.Println()
for _, s := range src {
fmt.Println(c.String(s))
}
}
}
With the following output
hello world!
i with dot
'n ijsberg
here comes o'brian
HELLO WORLD!
İ WİTH DOT
'N İJSBERG
HERE COMES O'BRİAN
Hello World!
I With Dot
'n IJsberg
Here Comes O'brian
Hello World!
I With Dot
'N Ijsberg
Here Comes O'Brian
So far it was like strings.Title() was using Und or English?
strings.Title() works based on ASCII, where cases.Title() works based on Unicode, there is no way to get the exact same behavior.
Should I use language.English or language.AmericanEnglish or other?
language.English, language.AmericanEnglish and language.Und all seem to have the same Title rules. Using any of them should get you the closest to the original strings.Title() behavior as you are going to get.
The whole point of using this package with Unicode support is that it is objectively more correct. So pick a tag appropriate for your users.
strings.Title(str) was deprecated, should change to cases.Title(language.Und, cases.NoLower).String(str)
package main
import (
"fmt"
"strings"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
func main() {
fmt.Println(strings.Title("abcABC")) // AbcABC
fmt.Println(cases.Title(language.Und, cases.NoLower).String("abcABC")) // AbcABC
}
Playground : https://go.dev/play/p/i0Eqh3QfxTx
Here is a straightforward example of how to capitalize the initial letter of each string value in the variable using the golang.org/x/text package.
package main
import (
"fmt"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
func main() {
sampleStr := "with value lower, all the letters are lowercase. this is good for poetry perhaps"
caser := cases.Title(language.English)
fmt.Println(caser.String(sampleStr))
}
Output : With Value Lower, All The Letters Are Lowercase. This Is Good For Poetry Perhaps
Playground Example: https://go.dev/play/p/_J8nGVuhYC9

Who does the type checking for golang in visual studo code?

Edit: Please be so kind and read the question before you judge it. Answers like "It typechecks your code" are not helpful and only show that you have not understood the question. This question is not about a typo, it is about the (partial) implementation of the semantics of golang.
I am starting to learn go and thus I am trying to explore the basics of the language.
If I use this statement:
fmt.Println(1 + true)
in Visual Studio Code, I get "invalid operation: 1 + true (mismatched types untyped int and untyped bool)", before running my program.
I am totally fine with the error message, but I am wondering how VSC knows that before compilation.
Go's parser should be happy with this line, since there is no type restriction (like allowing only numeric expressions as operands of "+") in go's grammar:
Expression = UnaryExpr | Expression binary_op Expression .
UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
binary_op = ... | add_op | ... .
add_op = "+" | ... .
So, I am wondering, what is going on here? is there a separate step of type-checking in go's compiler that VSC uses or did VSC write its own type checker?
VSCode uses a language server for language-aware IDE features like autocompletion, diagnostics, jump-to definition, etc.
For Go, the language server implementation is gopls. If you're really curious, feel free to check out the source code of the vscode-go extension, however if you're just learning Go perhaps you have better things to do :-)
The extension is written in TypeScript (like most of VSCode), though gopls is written in Go. It uses Go tooling which supports parsing and type checking Go code with the go/types package. You are correct that for this specific error, type checking is required; just parsing is insufficient.
Here's a basic example of using go/types to typecheck Go code:
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"log"
)
const hello = `package main
import "fmt"
func main() {
fmt.Println("Hello, world")
}`
func main() {
fset := token.NewFileSet()
// Parse the input string, []byte, or io.Reader,
// recording position information in fset.
// ParseFile returns an *ast.File, a syntax tree.
f, err := parser.ParseFile(fset, "hello.go", hello, 0)
if err != nil {
log.Fatal(err) // parse error
}
// A Config controls various options of the type checker.
// The defaults work fine except for one setting:
// we must specify how to deal with imports.
conf := types.Config{Importer: importer.Default()}
// Type-check the package containing only file f.
// Check returns a *types.Package.
pkg, err := conf.Check("cmd/hello", fset, []*ast.File{f}, nil)
if err != nil {
log.Fatal(err) // type error
}
fmt.Printf("Package %q\n", pkg.Path())
fmt.Printf("Name: %s\n", pkg.Name())
fmt.Printf("Imports: %s\n", pkg.Imports())
fmt.Printf("Scope: %s\n", pkg.Scope())
}

Parsefloat give output in scientific format in golang

i am trying to parse this string "7046260" using Parsefloat function in golang , but i am getting output in scientific format 7.04626e+06. i want the output in the format 7046260. how to get this?
package main
import (
"fmt"
"strconv"
)
func main() {
Value := "7046260"
Fval, err := strconv.ParseFloat(Value, 64)
if err == nil {
fmt.Println(Fval)
}
}
ouput :- 7.04626e+06
Parsefloat give output in scientific format in golang
i am trying to parse this string "7046260" using Parsefloat function in golang , but i am getting output in scientific format 7.04626e+06. i want the output in the format 7046260
You're confusing the floating-point value's (default) formatted output with its internal representation.
ParseFloat is working fine.
You just need to specify an output format:
See the fmt package documentation.
Use Printf to specify a format-string.
Use the format %.0f to instruct Go to print the value as-follows:
% marks the start of a placeholder.
. denotes default width (i.e. don't add leading or trailing zeroes).
0 denotes zero radix precision (i.e. don't print any decimal places, even if the value has them)
f denotes the end of the placeholder, and that the placeholder is for a floating-point value.
I have a few other recommendations:
Local variables in Go should use camelCase, not PascalCase. Go does not encourage the use of snake_case.
You should check err != nil after each nil-returning function returns and either fail-fast (if appropriate), pass the error up (and optionally log it), or handle it gracefully.
When working with floating-point numbers, you should be aware of NaN's special status. The IsNaN function is the only way to correctly check for NaN values (because ( aNaNValue1 == math.NaN ) == false).
The same applies in all languages that implement IEEE-754, including Java, JavaScript, C, C#.NET and Go.
Like so:
package main
import (
"fmt"
"strconv"
"math"
"log"
)
func main() {
numberText := "7046260"
numberFloat, err := strconv.ParseFloat(numberText, 64)
if err != nil {
log.Fatal(err)
}
if math.IsNaN(numberFloat) {
log.Fatal("NaN value encountered")
}
fmt.Printf("%.0f",numberFloat)
fmt.Println()
}

golang with compile error: undefined: strings in strings.trim

I try to use golang deal with this problem 557. Reverse Words in a String III
my code as below:
import "fmt"
import ss "strings"
func reverseWords(s string) string {
words := ss.Split(s," ");
res := "";
for i:=0; i < len(words);i++{
curWord := ss.Split(words[i],"");
for j:=len(curWord)-1; j >= 0;j--{
res += curWord[j];
}
if(i!=len(words)-1){
res += " ";
}
}
return res;
}
func main(){
s := "Let's take LeetCode contest";
fmt.Println(reverseWords(s));
}
Everything is ok in my pc, it can pass compile at least.
However, when I submit in leetcode it tell me :
Line 67: undefined: strings in strings.Trim
I google this error but get nothing relevant info. As a beginner in golang, I need help. Everything will be appreciated.
You're importing strings under an alias:
import ss "strings"
That means that everywhere in that file, instead of referring to strings you must refer to ss, for example:
words := ss.Split(s," ")
If you use the default import:
import "strings"
Then you can refer to it as strings as normal.
Note that the currently accepted answer is wrong about two things: you can absolutely use the alias as you have it, you just have to refer to the package with the aliased name. It will not cause any issues if you use the name you gave it. Second, you absolutely do need to import the strings package - with or without an alias, your choice - if you want to refer to it.
On a completely unrelated side note, you should strongly consider running go fmt on your code, as it does not follow Go coding standards; for example, standard Go code omits the vast majority of semicolons. The code will work regardless, but you'll have an easier time getting help from other Go developers if your code is formatted the way everyone else is used to seeing it.
If you import strings package with different name then it will cause issue as it is used by the wrapper code to run the function completely.
No need to import strings package again. It will be added.
Just use it directly.
func reverseWords(s string) string {
words := strings.Split(s," ");
res := "";
for i:=0; i < len(words);i++{
curWord := strings.Split(words[i],"");
for j:=len(curWord)-1; j >= 0;j--{
res += curWord[j];
}
if(i!=len(words)-1){
res += " ";
}
}
return res;
}

Golang equivalent of Python's struct.pack / struct.unpack

In Python, using the struct module, I can do something like this to get a packed representation of a value as a string:
import struct
print struct.pack('L', 64)
"#\x00\x00\x00\x00\x00\x00\x00"
struct.unpack('L', '#\x00\x00\x00\x00\x00\x00\x00')
(64,)
I'd like to do something similar in Go, except I'm a little unclear on how to do so. I know I can do something like this:
import (
"encoding/binary"
"fmt"
)
bs := make([]byte, 8)
binary.PutUvarint(bs, uint64(64))
fmt.Printf("%s", bs)
"#"
But that's very different and probably not what I want.
Yes, "encoding/binary" is what you want, you just don't want the variable length format.
https://play.golang.org/p/e81LuPO_JR
bs := make([]byte, 8)
binary.LittleEndian.PutUint64(bs, uint64(64))
fmt.Printf("%#v\n", bs)
i := binary.LittleEndian.Uint64(bs)
fmt.Println(i)
There are a couple interesting solutions.
1st is gist that's simple to follow and its limitations are clear:
https://gist.github.com/cloveryume/9a59e8d77f5836f11720#file-golang_struct_packed-go
2nd is a package that tries to the job of packing:
https://github.com/lunixbochs/struc

Resources