Iterating over Go string to extract specific substrings - arrays

I started learning Go and I want to implement some algorithm.
I want to iterate over a string and then extract some substrings for example : p -(40) *(GOT) +(FF)
should return an array like this: [p, 40, GOT, FF]
I wrote something like this but it's vague:
import (
"strings"
)
func find(input string){
var result []string
a := strings.SplitN(input, "-(", 2);
result[0] = a[0]
b := strings.SplitN(a[1], ") *(", 2)
result[1] = b[0]
c := strings.SplitN(a[1], ") +(", 2)
result[2] = c[0]
d := strings.SplitN(a[1], ")", 2)
result[3] = d[0]
}
Can someone please correct me or suggest something easier? Thanks!

You may use strings.FieldsFunc, like this working sample code:
package main
import "fmt"
import "strings"
func find(input string) []string {
return strings.FieldsFunc(input, split)
}
func main() {
strs := find("p -(40) *(GOT) +(FF)")
str := strings.Replace(fmt.Sprint(strs), " ", ", ", -1)
fmt.Println(str)
}
func split(r rune) bool {
return r == ' ' || r == '-' || r == '(' || r == ')' || r == '*' || r == '+'
}
output:
[p, 40, GOT, FF]
You may use strings.Fields then strings.Trim, like this working sample code:
package main
import "fmt"
import "strings"
func main() {
fmt.Println(find("p -(40) *(GOT) +(FF)"))
}
func find(input string) []string {
strs := strings.Fields(input)
result := make([]string, 0, len(strs))
for _, v := range strs {
s := strings.Trim(v, "()+-*")
if len(s) > 0 {
result = append(result, s)
}
}
return result
}
output:
[p 40 GOT FF]
Also this works for your special case:
package main
import "fmt"
import "strings"
func main() {
fmt.Println(find("p -(40) *(GOT) +(FF)"))
}
func find(input string) []string {
strs := strings.Fields(input)
for i := 0; i < len(strs); i++ {
strs[i] = strings.Trim(strs[i], "()+-*")
}
return strs
}
output:
[p 40 GOT FF]
And if you need output like this string: [p, 40, GOT, FF], try this working sample code:
package main
import "fmt"
import "strings"
func main() {
strs := find("p -(40) *(GOT) +(FF)")
str := strings.Replace(fmt.Sprint(strs), " ", ", ", -1)
fmt.Println(str)
}
func find(input string) []string {
strs := strings.Fields(input)
for i := 0; i < len(strs); i++ {
strs[i] = strings.Trim(strs[i], "()+-*")
}
return strs
}
output:
[p, 40, GOT, FF]

Related

Assigning return values of a function to elements in Struct array in Golang

I want the Struct array to have return values of the Function I defined later in the code.
In here I defined a struct "array" and info is the array of all those values in the struct, I want every element in the info array to have the respective values I mentioned, info.pos should have the value of the string I'm passing through the function PossibleMoves(), info.bitrep should have the return value from the function converttobit(), info.numrep should have the return value of toNumber(), and v1-v8 should have the values of the moves[] array, (v1=moves[0]).
My code is definitely clumsy can someone help?
package main
import ("bufio"
"fmt"
"os"
"strings")
type array struct{
pos string
bitrep int64
numrep,v1,v2,v3,v4,v5,v6,v7,v8 int8
}
func main() {
file, err := os.Open("chessin.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
valid := []bool{}
for scanner.Scan() {
b := strings.Split(scanner.Text(), ",")
valid = append(valid, isvalid(b))
}
fmt.Println(valid)
info :=[64][11]array {
info.pos = Possiblemoves(pos)
info.bitrep=coverttobit(num)
info.numrep=toNumber(string)
info.v0=moves[0]
info.v1=moves[1]
info.v2=moves[2]
info.v3=moves[3]
info.v4=moves[4]
info.v5=moves[5]
info.v6=moves[6]
info.v7=moves[7]
}
}
func convertingtobit( num int){
n := int64(num)
bit:=strconv.FormatInt(n, 2)
}
func isvalid(b string) bool {
if b[0]<='H' && b[0]>='A' && b[1]<='8' && b[1]>='0' {
return true
}
return false
}
func toNumber(s string) int {
if len(s) != 2 {
fmt.Println("Invalid Input",s,".")
}
num=int(s[0]-'A')*8 + int(s[1]-'0')
return num
}
func PossibleMoves(a string) {
isvalid := isvalid(a)
if isvalid == true {
var moves [8]string
moves[0]=string(a[0]+1)+string(a[1]+2)
moves[1]=string(a[0]+1)+string(a[1]-2)
moves[2]=string(a[0]-1)+string(a[1]+2)
moves[3]=string(a[0]-1)+string(a[1]-2)
moves[4]=string(a[0]+2)+string(a[1]+1)
moves[5]=string(a[0]+2)+string(a[1]-1)
moves[6]=string(a[0]-2)+string(a[1]+1)
moves[7]=string(a[0]-2)+string(a[1]-1)
fmt.Println("Possible moves are : ",moves)
var PosMoves [8] int
for i:=0;i<8;i++ {
if isvalid == true {
PosMoves[i]=toNumber(moves[i])
}
}
fmt.Println("After converting : ",PosMoves)
} else {
fmt.Println("Invalid Input")
}
}
Short Answer ( Compile: Success) :
package main
import "fmt"
type array struct {
pos string
bitrep int64
numrep, v1, v2, v3, v4, v5, v6, v7, v8 int8
}
func toNumber(s string) int8 {
if len(s) != 2 {
fmt.Println("Invalid Input", s, ".")
}
num := int8(s[0]-'A')*8 + int8(s[1]-'0')
return num
}
func PossibleMoves(out *array, a string) {
out.v1 = toNumber(string(a[0]+1) + string(a[1]+2))
}
func main() {
info := &array{
pos: "A1",
bitrep: 1,
}
PossibleMoves(info, "")
}
There are some problems:
1- in your code use := instead of = for new vars:
func toNumber(s string) int {
if len(s) != 2 {
fmt.Println("Invalid Input",s,".")
}
num=int(s[0]-'A')*8 + int(s[1]-'0')
return num
}
Like this:
func toNumber(s string) int {
if !isvalid(s) {
panic("Invalid Input" + s + ".")
}
num := int(s[0]-'A')*8 + int(s[1]-'0')
return num
}
2- your code:
func isvalid(b string) bool {
if b[0]<='H' && b[0]>='A' && b[1]<='8' && b[1]>='0' {
return true
}
return false
}
check for len(b) == 2 like this:
func isvalid(b string) bool {
if len(b) == 2 && b[0] <= 'H' && b[0] >= 'A' && b[1] <= '8' && b[1] >= '1' {
return true
}
return false
}
3- try not to copy paste:
moves[0]=string(a[0]+1)+string(a[1]+2)
moves[1]=string(a[0]+1)+string(a[1]-2)
moves[2]=string(a[0]-1)+string(a[1]+2)
moves[3]=string(a[0]-1)+string(a[1]-2)
moves[4]=string(a[0]+2)+string(a[1]+1)
moves[5]=string(a[0]+2)+string(a[1]-1)
moves[6]=string(a[0]-2)+string(a[1]+1)
moves[7]=string(a[0]-2)+string(a[1]-1)
Answering exact question:
type array struct{
pos string
bitrep int64
numrep,v1,v2,v3,v4,v5,v6,v7,v8 int8
}
func PossibleMoves(out *array, a string) {
out.v1 = tonumber(string(a[0]+1) + string(a[1]+2))
// ...
}
func main() {
// ...
info := &array{
pos: "...",
bitrep: 1234,
}
PossibleMoves(info, line)
}
But instead of this small detail, concentrate on answer by #Amd.

Reading specific characters from file in Golang

I want to read a text file character by character and print invalid input for those characters that exceed "H"and numbers that exceed "8".
eg: my input is
I9,A2
A10,C3
D2,L3
output:
invalid input for all three
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func readLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
func main() {
lines, err := readLines("chessin.txt")
if err != nil {
log.Fatalf("readLines: %s", err)
}
var numLines int = len(lines)
for i := 0; i < numLines; i++ {
for j := 0; j < len(lines[i]); j++ {
if j > 'H' {
fmt.Printf("invalid input")
}
}
}
}
You need to edit the inner loop to check for every input line,
and find the number then comma and so, like this working sample code:
package main
import (
"bufio"
"fmt"
"log"
"os"
"strconv"
"strings"
)
func readLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
func checkOne(letter byte, number, i, j int) {
if letter > 'H' {
fmt.Printf("invalid input %q # (%d, %d) \n", letter, i, j)
}
if number > 8 {
fmt.Printf("invalid input number %d # (%d, %d) \n", number, i, j+1)
}
}
func main() {
lines, err := readLines("chessin.txt")
if err != nil {
log.Fatalf("readLines: %s", err)
}
var numLines int = len(lines)
for i := 0; i < numLines; i++ {
line := lines[i]
j := 0
comma := strings.IndexByte(line, ',')
if comma == -1 {
log.Fatalf("comma not found at line: %d", i)
}
number, err := strconv.Atoi(line[j+1 : comma])
if err != nil {
log.Fatalf("line:%d err: %s", i, err)
}
checkOne(line[j], number, i, j)
j = comma + 1
number, err = strconv.Atoi(line[j+1:])
if err != nil {
log.Fatalf("line:%d err: %s", i, err)
}
checkOne(line[j], number, i, j)
}
}
input file "chessin.txt":
I9,A2
A10,C3
D2,L3
output:
invalid input 'I' # (0, 0)
invalid input number 9 # (0, 1)
invalid input number 10 # (1, 1)
invalid input 'L' # (2, 3)
You can simplify by using string split and slice. Do not read and store all the values in an array and then loop through them again. Assuming the first character is always Caps and there will be no negative values. Working sample code is as follows:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
file, err := os.Open("chessin.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
valid := []bool{}
for scanner.Scan() {
strs := strings.Split(scanner.Text(), ",")
valid = append(valid, validateStrings(strs))
}
fmt.Println(valid)
}
func validateStrings(strs []string) bool {
for _, str := range strs {
char := str[0]
num, err := strconv.Atoi(string(str[1:len(str)]))
if err != nil {
fmt.Println("Invalid input")
os.Exit(1)
}
if char < 'A' || char > 'H' || num > 8 || num < 0 {
return false
}
}
return true
}

Golang Rename unicode file name

How to rename a file in unicode format, the gaps?
When you try to rename the standard library function, the file is not located.
Old: /usr/home/spouk/go/src/simple/Agraba - I Know You Are Smiling Now (Original Mix).mp4 New: /usr/home/spouk/go/src/simple/Agraba_-_I_Know_You_Are_Smiling_Now__Original_Mix_.mp4 [RENAME] rename Agraba - I Know You Are Smiling Now (Original Mix).mp4 /usr/home/spouk/go/src/simple/Agraba_-_I_Know_You_Are_Smiling_Now__Original_Mix_.mp4: no such file or directory
Someone tell me what to use or where to get acquainted with the direction of solution to this problem. Tnx.
package main
import (
"flag"
d "github.com/fiam/gounidecode/unidecode"
"fmt"
"path/filepath"
"os"
"strings"
"strconv"
"os/exec"
)
type (
File struct {
OriginPath string
ConvertPath string
}
FilesStack struct {
Files []File
InPath string
OutPath string
}
)
func NewFilesStack() *FilesStack {
n := new(FilesStack)
n.Files = []File{}
return n
}
func (f *FilesStack) RuneToAscii(r rune) string {
if r < 128 {
return string(r)
} else {
return "\\u" + strconv.FormatInt(int64(r), 16)
}
}
func (f *FilesStack) TransliterCyr(str string) string {
var result []string
for _, sym := range d.Unidecode(str) {
if (f.RuneToAscii(sym) == " ") || (f.RuneToAscii(sym) == "'") || (f.RuneToAscii(sym) == "`") || (f.RuneToAscii(sym) == ")") || (f.RuneToAscii(sym) == "(") {
result = append(result, "_")
} else {
result = append(result, f.RuneToAscii(sym))
}
}
return strings.Join(result, "")
}
func (f *FilesStack) walkFunction(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
res, err := filepath.Abs(filepath.Dir(info.Name()))
if err != nil {
fmt.Printf(err.Error())
}
ext := filepath.Ext(info.Name())
if ext == ".mp4" {
file := new(File)
//make new file name
oldfile := filepath.Join(res, info.Name())
newname := filepath.Join(res, f.TransliterCyr(info.Name()))
file.OriginPath = filepath.Join(res, newname)
fmt.Printf("Old: %s\nNew: %s\n", oldfile, newname)
//rename file
if err_rename := os.Rename(info.Name(), newname); err_rename != nil {
fmt.Printf("[RENAME] %s\n", err_rename.Error())
}
tmpname := []string{}
name := strings.TrimRight(info.Name(), filepath.Ext(info.Name()))
for _, sym := range name {
if f.RuneToAscii(sym) != " " {
tmpname = append(tmpname, string(sym))
}
}
word := strings.Join(tmpname, "")
oo, _ := filepath.Abs(f.OutPath)
rr := strings.Join([]string{f.TransliterCyr(word), ".mp3"}, "")
//fmt.Printf("Res: %v %v\n", rr, word)
file.ConvertPath = filepath.Join(oo, rr)
//fmt.Printf("Infile: %v\n", file.OriginPath)
//fmt.Printf("Outfile: %v\n", file.ConvertPath)
f.Files = append(f.Files, *file)
}
}
return nil
}
func (f *FilesStack) ParseFilesmp4() {
//парсинг файлов
if err := filepath.Walk(f.InPath, f.walkFunction); err != nil {
fmt.Printf(err.Error())
}
//конвертация
for _, file := range f.Files {
fmt.Printf("Start convertation %s \n", file.OriginPath)
command := fmt.Sprintf("ffmpeg -i %s -f mp3 %s", file.OriginPath, file.ConvertPath)
//fmt.Printf("Command %v\n", command)
cmd, err_convert := exec.Command(command).Output()
if err_convert != nil {
fmt.Printf(err_convert.Error())
}
fmt.Printf("Result convert: %v\n", cmd)
}
}
// note, that variables are pointers
var (
inpath = flag.String("inpath", ".", "директория для поиска всех файлов с расширением .mp4")
outpath = flag.String("outpath", ".", "директория для сохранения .mp3")
)
func main() {
//make files structy
f := NewFilesStack()
//parse arguments
flag.Parse()
fmt.Printf("inpath: %s\noutpath: %s\n", *inpath, *outpath)
//set arguments
f.InPath = *inpath
f.OutPath = *outpath
f.ParseFilesmp4()
}

Reading strings, integers and doubles from file with GoLang

How to read data from file in Google Go when my data file looks like this:
SomeString 200.0 2
OtherString 100.6 9
OneMoreString 550.8 1
(String, double and integer). I tried bufio.readLine and bufio.readString but these are reading whole line, while i need seperated variables.
Something like this might work--if you've got spaces in your string, you might need to handle that differently:
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("scan.txt")
if err != nil {
fmt.Println(err)
}
for {
var i int
var flt float64
var str string
var n int
n, err = fmt.Fscanln(f, &str, &flt, &i)
if n == 0 || err != nil {
break
}
fmt.Println("string:", str, "; float:", flt, "; int:", i)
}
}
outputs:
string: SomeString ; float: 200 ; int: 2
string: OtherString ; float: 100.6 ; int: 9
string: OneMoreString ; float: 550.8 ; int: 1
For example,
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type Data struct {
AString string
AFloat float64
AnInt int64
}
func ParseLine(line string) (*Data, error) {
data := new(Data)
var err error
text := strings.TrimRight(line, " ")
i := strings.LastIndex(text, " ")
i++
text = text[i:]
data.AnInt, err = strconv.ParseInt(text, 10, 64)
if err != nil {
return nil, err
}
line = line[:i]
text = strings.TrimRight(line, " ")
i = strings.LastIndex(text, " ")
i++
text = text[i:]
data.AFloat, err = strconv.ParseFloat(text, 64)
if err != nil {
return nil, err
}
line = line[:i]
data.AString = line
return data, nil
}
func main() {
f, err := os.Open("data.txt")
if err != nil {
fmt.Fprintln(os.Stderr, "opening input:", err)
return
}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
data, err := ParseLine(line)
if err != nil {
fmt.Fprintln(os.Stderr, "reading input:", err, ":", line)
continue
}
fmt.Println(*data)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading input:", err)
}
}
Input (data.txt):
Some String 200.0 2
Other String 100.6 9
One More String 550.8 1
Output:
{Some String 200 2}
{Other String 100.6 9}
{One More String 550.8 1}

How to slice a string using a delimiter

In Go, if I have a string variable s:
var s string = "a,b,c,d,e"
How can I convert or split or explode it into a slice or an array of strings so that it will become:
arr[0] = "a"
...
arr[4] = "e"
You should use the strings package for that.
stringSlice := strings.Split(s, ",")
http://play.golang.org/p/UKZbcuJUPP
If you want to ignore empty elements, you can use
strings#FieldsFunc:
package main
import (
"fmt"
"strings"
)
func main() {
s := ",a,,b,c,d,e,"
arr := strings.FieldsFunc(s, func(r rune) bool {
return r == ','
})
fmt.Printf("%q\n", arr) // ["a" "b" "c" "d" "e"]
}
or bufio#Scanner.Split:
package main
import (
"bufio"
"strings"
)
func comma(data []byte, eof bool) (int, []byte, error) {
if eof { return 0, nil, nil }
a := -1
for b, c := range data {
if c == ',' {
if a >= 0 {
return b+1, data[a:b], nil
}
} else if a < 0 {
a = b
}
}
return len(data), data, nil
}
func main() {
s := ",a,,b,c,d,e"
arr := bufio.NewScanner(strings.NewReader(s))
arr.Split(comma)
for arr.Scan() {
println(arr.Text())
}
}

Resources