Find all selected words in a given text - go

I have the below code, where I want the user to enter some key words, then find what from these words are exisiting in a given string, but the resulting matches slice is an empty slice of a length equal to text to be checked
playground
package main
import (
"fmt"
"regexp"
)
func main() {
p := []string{}
p = append(p, "engineer")
p = append(p, "doctor")
var skills string
for _, z := range p {
skills += `|` + z
}
fmt.Println(skills)
re := regexp.MustCompile(`(?i)` + skills)
matches := re.FindAllString("I'm an engineer not a doctor", -1)
fmt.Println(matches)
for i, j := range matches {
fmt.Println(i, j)
}
}

Thanks to the comments provided, I got is as:
package main
import (
"fmt"
"regexp"
"strings"
)
func main() {
p := []string{}
p = append(p, "engineer")
p = append(p, "doctor")
p = append(p, "chemical (permit)")
skills := strings.Join(p, "|")
fmt.Println(skills)
re := regexp.MustCompile(`(?i)` + skills)
matches := re.FindAllString("I'm an engineer not a doctor who is getting chemical permits", -1)
fmt.Println(matches, len(matches))
for i, j := range matches {
fmt.Println(i, j)
}
}
The output is:
engineer|doctor|chemical (permit)
[engineer doctor chemical permit] 3
0 engineer
1 doctor
2 chemical permit

Related

Find largest score word

package main
import (
"bufio"
"fmt"
"os"
"strings"
)
type word struct {
str string
score int
}
func main() {
fmt.Print("Enter a string of words: ")
reader := bufio.NewReader(os.Stdin)
str, _ := reader.ReadString('\n')
strin := strings.Trim(str, "\n")
high_word := get_word(strin)
fmt.Println(high_word)
}
func get_word(in string) []word {
rune_word := strings.Split(in, " ")
stru_sl := make([]word, len(rune_word))
for i := 0; i < len(rune_word); i++ {
stru_sl[i] = word{str: rune_word[i], score: (get_score(rune_word[i]))}
}
return stru_sl
}
func get_score(in_w string) int {
var num int
score_map := make(map[string]int)
alpha := "abcdefghijklmnopqrstuvwxyz"
alpha_run := strings.Split(alpha, "")
for i, a := range alpha_run {
score_map[a] = i + 1
}
for i := 0; i < len(in_w); i++ {
if m, ok := score_map[string(in_w[i])]; ok {
num += m
}
}
return num
}
I've got the code above that gives me a list of structs corresponding to the words you put in, and its score calculated by adding up positions of each letter in the alphabet (1-26). My next step here is to find the word with the highest score. I can do the swap method and sort the structs, but what's the smartest way to achieve this?
If you want to find only the word with the highest score of course sorting isn't necessary, you can scan linearly and update what is highest on every step.
something like that:
highestScoreWord = words[0];
for i := 1; i < len(words); i++ {
if words[i].score > highestScoreWord.score {
highestScoreWord = words[i];
}
}
return highestScoreWord;

How to apply a function to an input of integers in Golang

For example, if the input was this
1 3 4 5
all separated by a space, I want to apply the function of squaring each individual number then adding it.
I just don't know how to apply the function to each number. All I can figure is that I have to put the numbers into a slice then apply the function to each of the numbers. I have looked everywhere and can't find out how to do this.
in Python I just do it like this and I already put the values into a list called "n".
#The list is pasted from the initial puzzle
n=[10, 10, 9, 8, 10, 10, 10]
# The list is first squared
b = (list(map(lambda x:x**2,n)))
b becomes the new list where the function is done to each number.
You can do it like this if your integers are actually a string separated by spaces.
package main
import "fmt"
import "strings"
import "strconv"
func main() {
numbers := "1 3 4 5"
var n []int
for _, v := range strings.Fields(numbers) {
i, err := strconv.Atoi(v)
if err != nil {
fmt.Println(err.Error())
break
}
n = append(n, i*i)
}
fmt.Println(n)
}
https://play.golang.org/p/JcivNd29Gzg
package main
import (
"strconv"
"fmt"
"strings"
)
func main() {
stringwithnumbers := "1 2 3 4 5"
numberarray := strings.Split(stringwithnumbers, " ")
stringwithnumbers = ""
for _, number := range numberarray {
numbernew,err := strconv.Atoi(number)
if err != nil{
return
}
numbernew = numbernew * 2
stringwithnumbers += strconv.Itoa(numbernew)
stringwithnumbers += " "
}
stringwithnumbers = strings.Trim(stringwithnumbers, " ")
//You can check the result...
fmt.Print(stringwithnumbers)
}
You can check the code and your changes here:
https://play.golang.org/

How to adjust the size of two-dimensional array in Go?

I have written a program that reads input lines and checks if a line begins with #.
If so, the current line and the next one will be saved in two columns in the same row in a two-dimensional array:
Go Playground
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
var multiDimArr [3][2]string
var lineCount int
scanner := bufio.NewScanner(strings.NewReader(input))
for line := 0; scanner.Scan(); line++ {
if strings.HasPrefix(scanner.Text(), "#") {
multiDimArr[line][0] = scanner.Text()
scanner.Scan()
multiDimArr[line][1] = scanner.Text()
lineCount++
}
}
for i := 0; i < lineCount; i++ {
for j := 0; j < 2; j++ {
fmt.Printf("multiDimArr[%d][%d] = %s\n", i, j, multiDimArr[i][j])
}
}
}
Output:
multiDimArr[0][0] = #FooBar1
multiDimArr[0][1] = FooBar1
multiDimArr[1][0] = #Foobar2
multiDimArr[1][1] = FooBar2
multiDimArr[2][0] = #FooBar3
multiDimArr[2][1] = FooBar3
My problem is that I need to know the number of lines in the input when building the program, so I can adjust the size of multiDimArr.
Can I do anything to make it take any number of lines?
Try this variation:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
var multiDimArr [][2]string
scanner := bufio.NewScanner(strings.NewReader(input))
for scanner.Scan() {
if strings.HasPrefix(scanner.Text(), "#") {
firstLine := scanner.Text()
scanner.Scan()
secondLine := scanner.Text()
multiDimArr = append(multiDimArr, [2]string{firstLine, secondLine})
}
}
for i, row := range multiDimArr {
for j, line := range row {
fmt.Printf("multiDimArr[%d][%d] = %s\n", i, j, line)
}
}
}
Use this Slice: [][2]string{} , so you don't need to count the number of lines of input:
Try this working sample code:
package main
import "bufio"
import "fmt"
import "strings"
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
multiDimArr := [][2]string{}
for i, r := 0, bufio.NewScanner(strings.NewReader(input)); r.Scan(); i++ {
line1 := r.Text()
if !strings.HasPrefix(line1, "#") || !r.Scan() {
break
}
multiDimArr = append(multiDimArr, [2]string{line1, r.Text()})
}
fmt.Println(multiDimArr)
}
output:
[[#FooBar1 FooBar1] [#Foobar2 FooBar2] [#FooBar3 FooBar3]]
Also you may use this working sample code if you need to pre scan input to count the number of lines, using multiDimArr := make([][2]string, n) makes this slice [][2]string with length = capacity = n:
package main
import "bufio"
import "fmt"
import "strings"
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
n := 0
for r := bufio.NewScanner(strings.NewReader(input)); r.Scan() && strings.HasPrefix(r.Text(), "#") && r.Scan(); n++ {
}
multiDimArr := make([][2]string, n)
for i, r := 0, bufio.NewScanner(strings.NewReader(input)); r.Scan(); i++ {
line1 := r.Text()
if !strings.HasPrefix(line1, "#") || !r.Scan() {
break
}
multiDimArr[i] = [2]string{line1, r.Text()}
}
fmt.Println(multiDimArr)
}
Output:
[[#FooBar1 FooBar1] [#Foobar2 FooBar2] [#FooBar3 FooBar3]]
Array types:
The length is part of the array's type; it must evaluate to a
non-negative constant representable by a value of type int.
So you can't use array because its length is constant, using multiDimArr := [n][2]string{} makes compile time error: non-constant array bound n:
n := preScan(input)
//multiDimArr := [n][2]string{} // error: non-constant array bound n

Generate all possible n-character passwords

As part of a learning-Go exercise, I'm writing a simplistic brute-force password cracker.
To generate all possible 2-character passwords that use the characters A-E in Python, I would use itertools.product():
from itertools import product
for permutation in product('ABCDE', repeat=2):
print permutation
However, I'm struggling to do this in Go.
Other questions seem to be about permutations, which isn't quite what I want. And while the Python docs include a sample implementation of the function, I don't know how to translate yield into Go.
I suppose I should mention two restrictions:
I'd like the length of the password to be variable. That is, I may want to do 8-character passwords, or 6-character, or something else. This means we can't just nest n loops.
I don't want to have all of them in memory at once.
What you want is basically the n-ary cartesian product of a set with itself. So for all 3-character passwords you want Prod(set,set,set). This can be constructed iteratively. First construct the n-1 product, then for each product and each element of the initial set, add the element. So for instance all 2 character passwords -> 3 character passwords where the only valid characters are 'a' or 'b'.
"ab" = {a,b} -> {(a,a),(a,b),(b,a),(b,b)} -> {(a,a,a),(a,a,b),(a,b,a),(a,b,b),(b,a,a),(b,a,b),(b,b,a),(b,b,b)}
func NAryProduct(input string, n int) []string {
if n <= 0 {
return nil
}
// Copy input into initial product set -- a set of
// one character sets
prod := make([]string, len(input))
for i, char := range input {
prod[i] = string(char)
}
for i := 1; i < n; i++ {
// The bigger product should be the size of the input times the size of
// the n-1 size product
next := make([]string, 0, len(input)*len(prod))
// Add each char to each word and add it to the new set
for _, word := range prod {
for _, char := range input {
next = append(next, word + string(char))
}
}
prod = next
}
return prod
}
Playground version: http://play.golang.org/p/6LhApeJ1bv
It should be noted that there's a lot of room for improvement on this solution. If you want to construct all passwords of length, say, 6-18, calling this method independently for each one will recalculate previously computed sets. I'll leave writing the better version up to you. Given what I've shown you, it shouldn't be too difficult to modify the code to take an arbitrary (n-m)ary product and compute the n-ary product from it. (Hint: think about how you'd do this recursively)
For example, satisfying your restrictions,
package main
import "fmt"
func nextPassword(n int, c string) func() string {
r := []rune(c)
p := make([]rune, n)
x := make([]int, len(p))
return func() string {
p := p[:len(x)]
for i, xi := range x {
p[i] = r[xi]
}
for i := len(x) - 1; i >= 0; i-- {
x[i]++
if x[i] < len(r) {
break
}
x[i] = 0
if i <= 0 {
x = x[0:0]
break
}
}
return string(p)
}
}
func main() {
np := nextPassword(2, "ABCDE")
for {
pwd := np()
if len(pwd) == 0 {
break
}
fmt.Println(pwd)
}
}
Output:
AA
AB
AC
AD
AE
BA
BB
BC
BD
BE
CA
CB
CC
CD
CE
DA
DB
DC
DD
DE
EA
EB
EC
ED
EE
package main
import (
"fmt"
"strings"
"strconv"
// permutation and combination of charactersList
"github.com/ernestosuarez/itertools"
)
func main() {
passwordLength := "1,2,4"
characters := "abcdefghijklmnopqrstuvwxyz0123456789!##$%^&*()+-./"
passwordLengthList := strings.Split(passwordLength, ",")
charactersList := strings.Split(characters, "")
for _, passLen := range passwordLengthList {
passLenInt, err := strconv.Atoi(passLen)
if err != nil {
panic(err)
}
for v := range itertools.PermutationsStr(charactersList, passLenInt) {
fmt.Println(strings.Join(v, ""))
}
}
}
uses select for channels to generate unique passwords
func randombitsGen(l int) (out chan string) {
Capschar := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
smallchar := "abcdefghijklmnopqrstuvwxyz"
nums := "0123456789"
specials := "!##$%ˆ&*()?><"
out = make(chan string, l)
defer close(out)
for {
select {
case out <- string(Capschar[rand.Intn(len(strings.Split(Capschar, "")))]):
case out <- string(Capschar[rand.Intn(len(strings.Split(Capschar, "")))]):
case out <- string(Capschar[rand.Intn(len(strings.Split(Capschar, "")))]):
case out <- string(smallchar[rand.Intn(len(strings.Split(smallchar, "")))]):
case out <- string(smallchar[rand.Intn(len(strings.Split(smallchar, "")))]):
case out <- string(smallchar[rand.Intn(len(strings.Split(smallchar, "")))]):
case out <- string(nums[rand.Intn(len(strings.Split(nums, "")))]):
case out <- string(specials[rand.Intn(len(strings.Split(specials, "")))]):
default:
return
}
}
}

Looking for Go equivalent of scanf

I'm looking for the Go equivalent of scanf().
I tried with following code:
1 package main
2
3 import (
4 "scanner"
5 "os"
6 "fmt"
7 )
8
9 func main() {
10 var s scanner.Scanner
11 s.Init(os.Stdin)
12 s.Mode = scanner.ScanInts
13 tok := s.Scan()
14 for tok != scanner.EOF {
15 fmt.Printf("%d ", tok)
16 tok = s.Scan()
17 }
18 fmt.Println()
19 }
I run it with input from a text with a line of integers.
But it always output -3 -3 ...
And how to scan a line composed of a string and some integers?
Changing the mode whenever encounter a new data type?
The Package documentation:
Package scanner
A general-purpose scanner for UTF-8
encoded text.
But it seems that the scanner is not for general use.
Updated code:
func main() {
n := scanf()
fmt.Println(n)
fmt.Println(len(n))
}
func scanf() []int {
nums := new(vector.IntVector)
reader := bufio.NewReader(os.Stdin)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
i, _ := strconv.Atoi(f)
nums.Push(i)
}
str, err = reader.ReadString('\n')
}
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
}
Improved version:
package main
import (
"bufio"
"os"
"io"
"fmt"
"strings"
"strconv"
"container/vector"
)
func main() {
n := fscanf(os.Stdin)
fmt.Println(len(n), n)
}
func fscanf(in io.Reader) []int {
var nums vector.IntVector
reader := bufio.NewReader(in)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = reader.ReadString('\n')
}
return nums
}
Your updated code was much easier to compile without the line numbers, but it was missing the package and import statements.
Looking at your code, I noticed a few things. Here's my revised version of your code.
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"container/vector"
)
func main() {
n := scanf(os.Stdin)
fmt.Println()
fmt.Println(len(n), n)
}
func scanf(in io.Reader) []int {
var nums vector.IntVector
rd := bufio.NewReader(os.Stdin)
str, err := rd.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = rd.ReadString('\n')
}
return nums
}
I might want to use any input file for scanf(), not just Stdin; scanf() takes an io.Reader as a parameter.
You wrote: nums := new(vector.IntVector), where type IntVector []int. This allocates an integer slice reference named nums and initializes it to zero, then the new() function allocates an integer slice reference and initializes it to zero, and then assigns it to nums. I wrote: var nums vector.IntVector, which avoids the redundancy by simply allocating an integer slice reference named nums and initializing it to zero.
You didn't check the err value for strconv.Atoi(), which meant invalid input was converted to a zero value; I skip it.
To copy from the vector to a new slice and return the slice, you wrote:
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
First, I simply replaced that with an equivalent, the IntVector.Data() method: return nums.Data(). Then, I took advantage of the fact that type IntVector []int and avoided the allocation and copy by replacing that by: return nums.
Although it can be used for other things, the scanner package is designed to scan Go program text. Ints (-123), Chars('c'), Strings("str"), etc. are Go language token types.
package main
import (
"fmt"
"os"
"scanner"
"strconv"
)
func main() {
var s scanner.Scanner
s.Init(os.Stdin)
s.Error = func(s *scanner.Scanner, msg string) { fmt.Println("scan error", msg) }
s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
txt := s.TokenText()
fmt.Print("token:", tok, "text:", txt)
switch tok {
case scanner.Int:
si, err := strconv.Atoi64(txt)
if err == nil {
fmt.Print(" integer: ", si)
}
case scanner.String, scanner.RawString:
fmt.Print(" string: ", txt)
default:
if tok >= 0 {
fmt.Print(" unicode: ", "rune = ", tok)
} else {
fmt.Print(" ERROR")
}
}
fmt.Println()
}
}
This example always reads in a line at a time and returns the entire line as a string. If you want to parse out specific values from it you could.
package main
import (
"fmt"
"bufio"
"os"
"strings"
)
func main() {
value := Input("Please enter a value: ")
trimmed := strings.TrimSpace(value)
fmt.Printf("Hello %s!\n", trimmed)
}
func Input(str string) string {
print(str)
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
return input
}
In a comment to one of my answers, you said:
From the Language Specification: "When
memory is allocated to store a value,
either through a declaration or make()
or new() call, and no explicit
initialization is provided, the memory
is given a default initialization".
Then what's the point of new()?
If we run:
package main
import ("fmt")
func main() {
var i int
var j *int
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j)
j = new(int)
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j, "; *j (a value) = ", *j)
}
The declaration var i int allocates memory to store an integer value and initializes the value to zero. The declaration var j *int allocates memory to store a pointer to an integer value and initializes the pointer to zero (a nil pointer); no memory is allocated to store an integer value. We see program output similar to:
i (a value) = 0 ; j (a pointer) = <nil>
The built-in function new takes a type T and returns a value of type *T. The memory is initialized to zero values. The statement j = new(int) allocates memory to store an integer value and initializes the value to zero, then it stores a pointer to this integer value in j. We see program output similar to:
i (a value) = 0 ; j (a pointer) = 0x7fcf913a90f0 ; *j (a value) = 0
The latest release of Go (2010-05-27) has added two functions to the fmt package: Scan() and Scanln(). They don't take any pattern string. like in C, but checks the type of the arguments instead.
package main
import (
"fmt"
"os"
"container/vector"
)
func main() {
numbers := new(vector.IntVector)
var number int
n, err := fmt.Scan(os.Stdin, &number)
for n == 1 && err == nil {
numbers.Push(number)
n, err = fmt.Scan(os.Stdin, &number)
}
fmt.Printf("%v\n", numbers.Data())
}

Resources