all words are contained in sentence by golang - string

How can i match all word in the sentence?
words: ["test", "test noti", "result alarm", "alarm test"]
sentence: "alarm result test"
I expected something like this
[o] test
[x] test noti
[o] result alarm
[o] alarm test
I tried split by words,
var words []string
words = append(words, "test", "test noti", "result alarm", "alarm test")
sentence := "alarm result test"
for i := 0; i < len(words); i++ {
log.Info(strings.Split(words[i], " "))
}

Take a look at go strings package.
It contains necessary functions to achieve your goal.
As an example:
package main
import (
"fmt"
"strings"
)
const s = "alarm result test"
var words = []string{"test", "test noti", "result alarm", "alarm test"}
func main() {
for _, w := range words {
var c bool
for _, substr := range strings.Split(w, " ") {
c = strings.Contains(s, substr)
if !c {
break
}
}
fmt.Printf("%t %s \n", c, w)
}
}
https://go.dev/play/p/PhGLePCwhho

Related

Replacing duplicate substrings in a string replaces only one of them

I'm making a simple hangman game in Go, but I have come across an error, the unknow_string string (will be shown in the code) has _ characters so the other player guessing the letters can see the length of the word, whenever the player enters a correct letter, I want it to replace the nth (n depending on which index the letter is found in the word) _ character with the letter, which has been successful, but with one problem. If the word has two duplicate letters, only one of them is replaced.
I created a separate function called iterate (function because I want to avoid nested code), to iterate over all indexes. but it didn't work, here's the code:
package main
import (
"fmt"
"strings"
)
var input string
var word string
var unknown_word []string
var unknown_word_string string
var index int
var guesses int
var change_unknown_word_string []byte
func main() {
fmt.Println("Welcome to hangman")
fmt.Println("Player 1, choose a word!")
fmt.Scan(&word)
for i := 1; i <= len(word); i++ {
unknown_word = append(unknown_word, "_")
}
unknown_word_string = strings.Join(unknown_word, "")
for {
fmt.Println("Player 2, guess a letter or a word")
fmt.Println(unknown_word_string)
fmt.Scan(&input)
if guesses == 6 {
fmt.Println("Player 2 lost! Player 1's word was: ", word)
break
} else if unknown_word_string == input {
fmt.Println("Player 1 lost! Player 2 guessed the word by guessing the letter!")
}
if strings.Contains(word, input) && word != input {
index = strings.Index(word, input)
iterate()
fmt.Println("You guessed a letter!")
} else if word == input {
fmt.Println("Player 1 lost! Player 2 guessed the word by guessing the whole word!")
break
} else {
fmt.Println("Nothing found")
guesses++
}
}
}
func iterate() {
change_unknown_word_string = []byte(unknown_word_string)
for i := 0; i < len(change_unknown_word_string); i++ {
if change_unknown_word_string[i] == change_unknown_word_string[index] {
change_unknown_word_string[i] = []byte(input)[0]
}
}
unknown_word_string = string(change_unknown_word_string)
}
The comparison if change_unknown_word_string[i] == change_unknown_word_string[index] makes no sense, as unknown_word_string obviously contains _ at those positions.
You should be comparing word[i] == input[0] in the loop instead.
But note that converting a string to a byte array is not Unicode-friendly. It's better to work with runes (Unicode code points) instead, this way you're not limited to latin1 characters.
func iterate() {
needle := []rune(input)[0]
haystack := []rune(word)
buf := []rune(unknown_word_string)
for i := range haystack {
if haystack[i] == needle {
buf[i] = needle
}
}
unknown_word_string = string(buf)
}
Bonus note: this comparison is wrong
if unknown_word_string == input {
fmt.Println("Player 1 lost! Player 2 guessed the word by guessing the letter!")
}
It should be if unknown_word_string == word and be located immediately after the call to iterate().

How to check whether the given word exists in a sentence(string) without using the contains function in golang

I need an alternative method instead of strings.contains() to to check whether the given word exists in a sentence(string).
As an example I need to check the word "can" is inside the sentence "I can run fast" . If I use strings strings.Contains("can", "I can run fast") this gives true . But strings.Contains("can", "I cannot run fast") also gives true as it contains can . How can I check exactly the word can gives true and cannot gives false in the above mentioned scenario ?
Just as a first attempt, you can try using a regular expression:
import "regexp"
var containsCanRegex = regexp.MustCompile(`\b[Cc]an\b`)
func containsCan(s string) bool {
return containsCanRegex.MatchString(s)
}
Note that this matches title-case, so it matches "Can I go?".
The \b in a regular expression matches a "word boundary". It just means there is a word character on one side, and a non-word character, beginning of text, or end of text on the other side.
Note that this will match "can't" because \b treats ' as a word boundary (since it's a non-word character). It sounds like this is not what you want. In order to come up with a more general solution, you may want to know just how general you want the solution to be. A very basic approach would be to split the words first, and then check if any of those words match "can". You could split the words with a regular expression or by using a text segmentation library.
I don't know how to write a regular expression that would accept "can" but reject "can't" in a sentence--the "regexp" package does not support negative lookahead.
I need an alternative method instead of strings.contains() to to check
whether the given word exists in a sentence(string).
I'm trying to implement a filter for given set of words.
Here's a solution which uses simple algorithms for a word. The algorithms can distinguish between "can", "cannot", and "can't".
package main
import (
"fmt"
"strings"
"unicode"
)
func newFilter(words []string) map[string]struct{} {
filter := make(map[string]struct{}, len(words))
for _, word := range words {
word = strings.TrimSpace(word)
word = strings.ToLower(word)
if len(word) > 0 {
filter[word] = struct{}{}
}
}
return filter
}
func applyFilter(text string, filter map[string]struct{}) bool {
const (
rApostrophe = '\u0027'
sApostrophe = string(rApostrophe)
sApostropheS = string(rApostrophe) + "s"
rSoftHyphen = '\u00AD'
sSoftHyphen = string(rSoftHyphen)
sHyphenLF = "-\n"
sHyphenCRLF = "-\r\n"
)
split := func(r rune) bool {
return !unicode.IsLetter(r) && r != rApostrophe
}
text = strings.ToLower(text)
if strings.Contains(text, sSoftHyphen) {
text = strings.ReplaceAll(text, sSoftHyphen, "")
}
if strings.Contains(text, sHyphenLF) {
text = strings.ReplaceAll(text, sHyphenLF, "")
} else if strings.Contains(text, sHyphenCRLF) {
text = strings.ReplaceAll(text, sHyphenCRLF, "")
}
words := strings.FieldsFunc(text, split)
for _, word := range words {
if strings.HasSuffix(word, sApostrophe) {
word = word[:len(word)-len(sApostrophe)]
} else if strings.HasSuffix(word, sApostropheS) {
word = word[:len(word)-len(sApostropheS)]
}
if _, ok := filter[word]; ok {
return true
}
}
return false
}
func main() {
filter := newFilter([]string{"can"})
text := "I can run fast"
fmt.Println(applyFilter(text, filter))
text = "I cannot run fast"
fmt.Println(applyFilter(text, filter))
text = "I can-\nnot run fast"
fmt.Println(applyFilter(text, filter))
text = "I can't run fast"
fmt.Println(applyFilter(text, filter))
filter = newFilter([]string{"cannot", "can't"})
text = "I can run fast"
fmt.Println(applyFilter(text, filter))
text = "I cannot run fast"
fmt.Println(applyFilter(text, filter))
text = "I can-\nnot run fast"
fmt.Println(applyFilter(text, filter))
text = "I can't run fast"
fmt.Println(applyFilter(text, filter))
}
https://go.dev/play/p/sQpTt5JY8Qt

Why the string.Replace is not working in golang

I'm making a program to remove the letters from a string if they exsists. But the expected result will not come. The Program I have tried is below:-
package main
import (
"fmt"
"strings"
)
func main() {
strValue := "This is a string"
stringRemove := []string{"a", "an"}
var removalString string
for _, wordToRemove := range stringRemove {
removalString = strings.Replace(strValue, wordToRemove, "", -1)
}
fmt.Println(removalString)
result := strings.Replace(strValue, " ", "", -1)
result1 := strings.ToLower(result)
fmt.Println(result1)
}
Output:-
This is a string
thisisastring
If I use the line fmt.Println(removalString) in the for loop then it will print the result:-
output:-
This is string
This is a string
This is a string
thisisastring
Expected output:-
thisisstring
kheedn li link
You always apply the replace operation on the original string strValue, so after the loop only the last removable word will be removed (which is not even contained in your example). You should store the result of strings.Replace() (you do that), and use this in the next iteration:
removalString := strValue
for _, wordToRemove := range stringRemove {
removalString = strings.Replace(removalString, wordToRemove, "", -1)
}
And also use this in your last replacement:
result := strings.Replace(removalString, " ", "", -1)
result1 := strings.ToLower(result)
Then output will be (try it on the Go Playground):
This is string
thisisstring
Also note that to remove spaces, you can add that to the list of removable words, and you don't need to always create new variables, you can reuse existing ones.
This will also perform the same transformation:
s := "This is a string"
words := []string{"a", "an", " "}
for _, word := range words {
s = strings.Replace(s, word, "", -1)
}
s = strings.ToLower(s)
fmt.Println(s)
Try it on the Go Playground.
this is what youre looking for:
package main
import (
"fmt"
"strings"
)
func main() {
strValue := "This is a string"
stringRemove := []string{"a", "an"}
removalString := strValue
for _, wordToRemove := range stringRemove {
removalString = strings.Replace(removalString, wordToRemove, "", -1)
}
fmt.Println(removalString)
result := strings.Replace(strValue, " ", "", -1)
result1 := strings.ToLower(result)
fmt.Println(result1)
}
removalString will be set new value each loop. So fmt.Println(removalString) will show the result of last loop.
var removalString string
for _, wordToRemove := range stringRemove {
removalString = strings.Replace(strValue, wordToRemove, "", -1)
}
fmt.Println(removalString)
You may do like this
strValue := "This is a string"
stringRemove := []string{"a", "an"}
for _, wordToRemove := range stringRemove {
strValue = strings.Replace(strValue, wordToRemove, "", -1)
}
fmt.Println(strValue)

Splitting a string at Space, except inside quotation marks

I was wondering if there is any way I could easily split a string at spaces, except when the space is inside quotation marks?
For example, changing
Foo bar random "letters lol" stuff
into
Foo, bar, random, "letters lol", stuff
Think about it. You have a string in comma separated values (CSV) file format, RFC4180, except that your separator, outside quote pairs, is a space (instead of a comma). For example,
package main
import (
"encoding/csv"
"fmt"
"strings"
)
func main() {
s := `Foo bar random "letters lol" stuff`
fmt.Printf("String:\n%q\n", s)
// Split string
r := csv.NewReader(strings.NewReader(s))
r.Comma = ' ' // space
fields, err := r.Read()
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("\nFields:\n")
for _, field := range fields {
fmt.Printf("%q\n", field)
}
}
Playground: https://play.golang.org/p/Ed4IV97L7H
Output:
String:
"Foo bar random \"letters lol\" stuff"
Fields:
"Foo"
"bar"
"random"
"letters lol"
"stuff"
Using strings.FieldsFunc try this:
package main
import (
"fmt"
"strings"
)
func main() {
s := `Foo bar random "letters lol" stuff`
quoted := false
a := strings.FieldsFunc(s, func(r rune) bool {
if r == '"' {
quoted = !quoted
}
return !quoted && r == ' '
})
out := strings.Join(a, ", ")
fmt.Println(out) // Foo, bar, random, "letters lol", stuff
}
Using simple strings.Builder and range over string and keeping or not keeping " at your will, try this
package main
import (
"fmt"
"strings"
)
func main() {
s := `Foo bar random "letters lol" stuff`
a := []string{}
sb := &strings.Builder{}
quoted := false
for _, r := range s {
if r == '"' {
quoted = !quoted
sb.WriteRune(r) // keep '"' otherwise comment this line
} else if !quoted && r == ' ' {
a = append(a, sb.String())
sb.Reset()
} else {
sb.WriteRune(r)
}
}
if sb.Len() > 0 {
a = append(a, sb.String())
}
out := strings.Join(a, ", ")
fmt.Println(out) // Foo, bar, random, "letters lol", stuff
// not keep '"': // Foo, bar, random, letters lol, stuff
}
Using scanner.Scanner, try this:
package main
import (
"fmt"
"strings"
"text/scanner"
)
func main() {
var s scanner.Scanner
s.Init(strings.NewReader(`Foo bar random "letters lol" stuff`))
slice := make([]string, 0, 5)
tok := s.Scan()
for tok != scanner.EOF {
slice = append(slice, s.TokenText())
tok = s.Scan()
}
out := strings.Join(slice, ", ")
fmt.Println(out) // Foo, bar, random, "letters lol", stuff
}
Using csv.NewReader which removes " itself, try this:
package main
import (
"encoding/csv"
"fmt"
"log"
"strings"
)
func main() {
s := `Foo bar random "letters lol" stuff`
r := csv.NewReader(strings.NewReader(s))
r.Comma = ' '
record, err := r.Read()
if err != nil {
log.Fatal(err)
}
out := strings.Join(record, ", ")
fmt.Println(out) // Foo, bar, random, letters lol, stuff
}
Using regexp, try this:
package main
import (
"fmt"
"regexp"
"strings"
)
func main() {
s := `Foo bar random "letters lol" stuff`
r := regexp.MustCompile(`[^\s"]+|"([^"]*)"`)
a := r.FindAllString(s, -1)
out := strings.Join(a, ", ")
fmt.Println(out) // Foo, bar, random, "letters lol", stuff
}
You could use regex
This (go playground) will cover all use cases for multiple words inside quotes and multiple quoted entries in your array:
package main
import (
"fmt"
"regexp"
)
func main() {
s := `Foo bar random "letters lol" stuff "also will" work on "multiple quoted stuff"`
r := regexp.MustCompile(`[^\s"']+|"([^"]*)"|'([^']*)`)
arr := r.FindAllString(s, -1)
fmt.Println("your array: ", arr)
}
Output will be:
[Foo, bar, random, "letters lol", stuff, "also will", work, on, "multiple quoted stuff"]
If you want to learn more about regex here is a great SO answer with super handy resources at the end - Learning Regular Expressions
Hope this helps

Why wont these chars show when reversing string?

I'm just wondering why these asian characters in this string wont show up when I reverse and print the individual characters in the string.
package main
import "fmt"
func main() {
a := "The quick brown 狐 jumped over the lazy 犬"
var lenght int = len(a) - 1
for ; lenght > -1; lenght-- {
fmt.Printf("%c", a[lenght])
}
fmt.Println()
}
You are accessing the string array by byte not by 'logical character'
To better understand this example breaks the string first as an array of runes and then prints the rune backwards.
http://play.golang.org/p/bzbo7k6WZT
package main
import "fmt"
func main() {
msg := "The quick brown 狐 jumped over the lazy 犬"
elements := make([]rune, 0)
for _, rune := range msg {
elements = append(elements, rune)
}
for i := len(elements) - 1; i >= 0; i-- {
fmt.Println(string(elements[i]))
}
}
Shorter Version: http://play.golang.org/p/PYsduB4Rgq
package main
import "fmt"
func main() {
msg := "The quick brown 狐 jumped over the lazy 犬"
elements := []rune(msg)
for i := len(elements) - 1; i >= 0; i-- {
fmt.Println(string(elements[i]))
}
}

Resources