I was trying to write a stringReverse function which reverses the given string:
func reverseString(s string) []rune
well, i did succeed but the problem is there are spaces after reversing it.
Input: "Hello, 世界"
Output: [界 世 , o l l e H]
code of function :
func reverseString(s string) []rune {
// sir: string in rune
sir := []rune(s)
for i, _ := range sir {
sir[i], sir[len(sir)-i-1] = sir[len(sir)-i-1], sir[i]
if i >= len(sir)-i-1 {
return sir
}
}
return sir
}
i did not do any error implementation since i am new to go.
Thanks for your help.
To reverse strings,you can declare an empty string and then start appending the characters from the end, one by one.Here is a sample code for the same logic:
package main
import "fmt"
func reverse(str string) (result string) {
for _, v := range str {
result = string(v) + result
}
return
}
func main() {
runeStr := "Hello, 世界"
fmt.Println(runeStr)
runeRev := reverse(runeStr)
fmt.Println(runeRev)
}
Output:
Hello, 世界
界世 ,olleH
try to
func reverseString(s string) []rune {
// sir: string in rune
sir := []rune(s)
for i, _ := range sir {
sir[i], sir[len(sir)-i-1] = sir[len(sir)-i-1], sir[i]
if i+1 >= len(sir)/2 {
return sir
}
}
return sir
}
Related
I am new to the language GO and working on an assignment where i should write a code that return the word frequencies of the text. However I know that the words 'Hello', 'HELLO' and 'hello' are all counted as 'hello', so I need to convert all strings to lower case.
I know that I should use strings.ToLower(), however I dont know where I should Included that in the class. Can someone please help me?
package main
import (
"fmt"
"io/ioutil"
"log"
"strings"
"time"
)
const DataFile = "loremipsum.txt"
// Return the word frequencies of the text argument.
func WordCount(text string) map[string]int {
fregs := make(map[string]int)
words := strings.Fields(text)
for _, word := range words {
fregs[word] += 1
}
return fregs
}
// Benchmark how long it takes to count word frequencies in text numRuns times.
//
// Return the total time elapsed.
func benchmark(text string, numRuns int) int64 {
start := time.Now()
for i := 0; i < numRuns; i++ {
WordCount(text)
}
runtimeMillis := time.Since(start).Nanoseconds() / 1e6
return runtimeMillis
}
// Print the results of a benchmark
func printResults(runtimeMillis int64, numRuns int) {
fmt.Printf("amount of runs: %d\n", numRuns)
fmt.Printf("total time: %d ms\n", runtimeMillis)
average := float64(runtimeMillis) / float64(numRuns)
fmt.Printf("average time/run: %.2f ms\n", average)
}
func main() {
// read in DataFile as a string called data
data, err:= ioutil.ReadFile("loremipsum.txt")
if err != nil {
log.Fatal(err)
}
// Convert []byte to string and print to screen
text := string(data)
fmt.Println(text)
fmt.Printf("%#v",WordCount(string(data)))
numRuns := 100
runtimeMillis := benchmark(string(data), numRuns)
printResults(runtimeMillis, numRuns)
}
You should convert words to lowercase when you are using them as map key
for _, word := range words {
fregs[strings.ToLower(word)] += 1
}
I get [a:822 a.:110 I want all a in the same. How do i a change the code so that a and a. is the same? – hello123
You need to carefully define a word. For example, a string of consecutive letters and numbers converted to lowercase.
func WordCount(s string) map[string]int {
wordFunc := func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
}
counts := make(map[string]int)
for _, word := range strings.FieldsFunc(s, wordFunc) {
counts[strings.ToLower(word)]++
}
return counts
}
to remove all non-word characters you could use a regular expression:
package main
import (
"bufio"
"fmt"
"log"
"regexp"
"strings"
)
func main() {
str1 := "This is some text! I want to count each word. Is it cool?"
re, err := regexp.Compile(`[^\w]`)
if err != nil {
log.Fatal(err)
}
str1 = re.ReplaceAllString(str1, " ")
scanner := bufio.NewScanner(strings.NewReader(str1))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
fmt.Println(strings.ToLower(scanner.Text()))
}
}
See strings.EqualFold.
Here is an example.
my problem is that Im only allowed to use the command PrintRune, i must range over a string and print one by one the characters of any string
package piscine
import "github.com/01-edu/z01"
func PrintStr(s string) {
slice := []string{
s,
}
for x, word := range slice {
z01.PrintRune(rune(word[x]))
}
}
here's my code, this only prints the first character of the string, how can i make the slice continue until the end of the given string please ?
Here is the code snippets:
package piscine
import "github.com/01-edu/z01"
func PrintStr(s string) {
slice := []string{
s,
}
for _, word := range slice {
for _, r := range word {
z01.PrintRune(rune(r))
}
}
}
i have a string in golang :
"hi hi hi ho ho hello"
I would like to remove duplicates word to keep only one to obtain this :
"hi ho hello"
There are multiple way to achive this. One is this:
import "strings"
func Dedup(input string) string {
unique := []string{}
words := strings.Split(input, " ")
for _, word := range words {
// If we alredy have this word, skip.
if contains(unique, word) {
continue
}
unique = append(unique, word)
}
return strings.Join(unique, " ")
}
func contains(strs []string, str string) bool {
for _, s := range strs {
if s == str {
return true
}
}
return false
}
package main
import "fmt"
func removeDuplicates(arr []string) []string {
words_string := map[string]bool{}
for i:= range arr {
words_string[arr[i]] = true
}
desired_output := []string{} // Keep all keys from the map into a slice.
for j, _ := range words_string {
desired_output = append(desired_output, j)
}
return desired_output
}
func main() {
arr := []string{"hi", "hi", "hi", "ho", "ho", "hello"}
fmt.Println(arr)
desired_output := removeDuplicates(arr) // Remove the duplicates
fmt.Println(desired_output)
}
I want to parse a string xxxxx:yyyyy:zzz.aaa.bbb.cc:dd:ee:ff to a struct in Go, how can I do it with multiple delimiter ':' and '.'.
Edit:
I want to split the string "xxxxx:yyyyy:zzz.aaa.bbb.cc:dd" into below struct type
type Target struct {
Service string
Type string
Domain string
Plan string
Host string
Region string
Other string
}
So that
Service = xxxxx
Type = yyyyy
Domain = zzzz
Plan = aaa
Host = bbb
Region = cc
Other = dd
You may use
strings.FieldsFunc(input, Split)
Try it on The Go Playground:
package main
import (
"fmt"
"strings"
)
func main() {
input := `xxxxx:yyyyy:zzz.aaa.bbb.cc:dd:ee:ff`
a := strings.FieldsFunc(input, Split)
t := Target{a[0], a[1], a[2], a[3], a[4], a[5], a[6]}
fmt.Println(t) // {xxxxx yyyyy zzz aaa bbb cc dd}
}
func Split(r rune) bool {
return r == ':' || r == '.'
}
type Target struct {
Service string
Type string
Domain string
Plan string
Host string
Region string
Other string
}
output:
{xxxxx yyyyy zzz aaa bbb cc dd}
You can use regex for splitting your string
import "regexp"
func splitWord(word string) []string {
array := regexp.MustCompile("[\\:\\,\\.\\s]+").Split(word, -1)
return array
}
You can use this function, which can split a string by multiple runes:
import "fmt"
import "strings"
func SplitAny(s string, seps string) []string {
splitter := func(r rune) bool {
return strings.ContainsRune(seps, r)
}
return strings.FieldsFunc(s, splitter)
}
func main() {
words := SplitAny("xxxxx:yyyyy:zzz.aaa.bbb.cc:dd:ee:ff", ".:")
fmt.Println(strings.Join(words, " "))
}
Output:
xxxxx yyyyy zzz aaa bbb cc dd ee ff
Or even with one line of code:
words := strings.FieldsFunc(s, func(r rune) bool { return strings.ContainsRune(" .:", r) })
Here is a generic function that will take a string as a set of runes to split on.
func Splitter(s string, splits string) []string {
m := make(map[rune]int)
for _, r := range splits {
m[r] = 1
}
splitter := func(r rune) bool {
return m[r] == 1
}
return strings.FieldsFunc(s, splitter)
}
func TestSplit() {
words := Splitter("orange apple-banana", " -")
}
Alright. This isn't a very elegant solution but it should at least get you started and works for the specific example you've given. In reality you'd probably want to add some error handling or generalize the logic a bit to work with a broader set of inputs.
type Target struct {
Service string
Type string
Domain string
Plan string
Host string
Region string
Other string
}
func main() {
input := `xxxxx:yyyyy:zzz.aaa.bbb.cc:dd:ee:ff`
t := Target{}
tokens := strings.Split(input, ":")
t.Service = tokens[0]
t.Type = tokens[1]
subtokens := strings.Split(tokens[2], ".")
t.Domain = subtokens[0]
t.Plan = subtokens[1]
t.Host = subtokens[2]
t.Region = subtokens[3]
t.Other = tokens[3]
fmt.Printf("%v", t)
}
Working example here;
https://play.golang.org/p/57ZyOfdbvo
How can I access a capture group from inside ReplaceAllFunc()?
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName]")
search := regexp.MustCompile("\\[([a-zA-Z]+)\\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
// How can I access the capture group here?
})
fmt.Println(string(body))
}
The goal is to replace [PageName] with PageName.
This is the last task under the "Other tasks" section at the bottom of the Writing Web Applications Go tutorial.
I agree that having access to capture group while inside of your function would be ideal, I don't think it's possible with regexp.ReplaceAllFunc.
Only thing that comes to my mind right now regard how to do this with that function is this:
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName] [OtherPageName]")
search := regexp.MustCompile("\\[[a-zA-Z]+\\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
m := string(s[1 : len(s)-1])
return []byte("" + m + "")
})
fmt.Println(string(body))
}
EDIT
There is one other way I know how to do what you want. First thing you need to know is that you can specify non capturing group using syntax (?:re) where re is your regular expression. This is not essential, but will reduce number of not interesting matches.
Next thing to know is regexp.FindAllSubmatcheIndex. It will return slice of slices, where each internal slice represents ranges of all submatches for given matching of regexp.
Having this two things, you can construct somewhat generic solution:
package main
import (
"fmt"
"regexp"
)
func ReplaceAllSubmatchFunc(re *regexp.Regexp, b []byte, f func(s []byte) []byte) []byte {
idxs := re.FindAllSubmatchIndex(b, -1)
if len(idxs) == 0 {
return b
}
l := len(idxs)
ret := append([]byte{}, b[:idxs[0][0]]...)
for i, pair := range idxs {
// replace internal submatch with result of user supplied function
ret = append(ret, f(b[pair[2]:pair[3]])...)
if i+1 < l {
ret = append(ret, b[pair[1]:idxs[i+1][0]]...)
}
}
ret = append(ret, b[idxs[len(idxs)-1][1]:]...)
return ret
}
func main() {
body := []byte("Visit this page: [PageName] [OtherPageName][XYZ] [XY]")
search := regexp.MustCompile("(?:\\[)([a-zA-Z]+)(?:\\])")
body = ReplaceAllSubmatchFunc(search, body, func(s []byte) []byte {
m := string(s)
return []byte("" + m + "")
})
fmt.Println(string(body))
}
If you want to get group in ReplaceAllFunc, you can use ReplaceAllString to get the subgroup.
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName]")
search := regexp.MustCompile("\\[([a-zA-Z]+)\\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
// How can I access the capture group here?
group := search.ReplaceAllString(string(s), `$1`)
fmt.Println(group)
// handle group as you wish
newGroup := "<a href='/view/" + group + "'>" + group + "</a>"
return []byte(newGroup)
})
fmt.Println(string(body))
}
And when there are many groups, you are able to get each group by this way, then handle each group and return desirable value.
You have to call ReplaceAllFunc first and within the function call FindStringSubmatch on the same regex again. Like:
func (p parser) substituteEnvVars(data []byte) ([]byte, error) {
var err error
substituted := p.envVarPattern.ReplaceAllFunc(data, func(matched []byte) []byte {
varName := p.envVarPattern.FindStringSubmatch(string(matched))[1]
value := os.Getenv(varName)
if len(value) == 0 {
log.Printf("Fatal error substituting environment variable %s\n", varName)
}
return []byte(value)
});
return substituted, err
}