TrimRight not working as I expected - go

Below is the code of TrimRight, on latest Go version
I am observing a behavior, which maybe I am misunderstanding but as my understanding, the below code should throw output as
Hello
But the output is coming as
Hell
Why is that so ? Note, I have kept a space before the Gophers in cutset, so fundamentally it should remove the " Gophers" from the primary string, leaving behind just Hello
package main
import (
"fmt"
"strings"
)
func main() {
result := strings.TrimRight("Hello Gophers", " Gophers")
fmt.Println(result, len(result))
}

As documented, TrimRight removes all matching characters from the right. Because o is included in your list (" Gophers"), it is also trimmed. If you want to trim that exact substring use TrimSuffix instead.

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

Regular Expression with If Else Condition

I have a problem with If Else Condition in Regex. I have a file which contains the below format. I was looking for return value to be either 0.0.985 or 3.3.5-3811.
I was trying to use if else condition in regex but unable to do so, can anyone explain me while solving the problem please.
random-app-0.0.985.tgz
busy-app-7.3.1.2-3.3.5-3811-a19874elkc-123254376584.zip
Below is the Go code I am trying to use
package main
import (
"fmt"
"io/ioutil"
"regexp"
)
func main(){
content, err:= ioutil.ReadFile("version.txt")
if err != nil{
fmt.Println(err)
}
version:= string(content)
re:= regexp.MustCompile(`(\d+).(\d+).(\d+)|(\d+).(\d+).(\d+).(\d+)`)
result:= re.FindAllStringSubmatch(version,-1)
for i:= range(result){
fmt.Println(result[i][0])
}
}
Output is coming like
0.0.985
7.3.1
2-3.3
5-3811
19874
123254376584
The following regexp can be used: [\d\.]+[\.-][\d]{2,}
package main
import (
"regexp"
"fmt"
)
func main() {
var re = regexp.MustCompile(`(?m)[\d\.]+[\.-][\d]{2,}`)
var str = `random-app-0.0.985.tgz
busy-app-7.3.1.2-3.3.5-3811-a19874elkc-123254376584.zip`
for i, match := range re.FindAllString(str, -1) {
fmt.Println(match, "found at index", i)
}
}
The output
0.0.985 found at index 0
3.3.5-3811 found at index 1
playground
?m multi line modifier. Causes ^ and $ to match the begin/end of each line (not only begin/end of string). In this case it does not make to much difference. It will work without it.
[\d\.]+ matches at least once (quantifier +) a sequence of a digit or a dot
[\.-] matches a dot or a hypen
[\d]{2,} matches at least two digits (quantifier {2,})
One problem with your code is that in a regular expression . matches any character but you're intending it to match a literal dot. Use \. or [.] instead.

Why does slicing the result of a ReadString() operation result in weird output?

package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("Input: ")
input, _ := reader.ReadString('\n')
fmt.Println("thing\n"[:5] + "\"")
fmt.Println(input[:len(input)-1] + "\"")
return
}
Running the code:
Input: thing
thing"
"hing
Why does the second concatenation behave oddly? It should produce identical results, assuming the ReadString() operation returns a string with a newline at the end. Please explain what is going on here.
That's because you're presumably on windows.
The actual input you make from your keyboard is not thing\n but thing\r\n
So when you do fmt.Println(input[:len(input)-1] + "\"") it only truncates the latest \n and leaves \r.
So the terminal prints thing, then reaches \r that returns carriage to the beginning of the string, then you print a double quote. But the carriage is in the first position now, and it effectively overwrites the first character of the line, leaving you with "hing

Don't understand func strings.TrimLeft in Go

I'm trying to test code that uses func strings.TrimLeft. I needed to see an MVCE of it in action, so I went to the API specification.
It came with an example, which I exported, with the following code:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Print(strings.TrimLeft("¡¡¡Hello, Gophers!!!", "!¡"))
}
Upon running it, you get Hello, Gophers!!!
I decided to prepend the input string, changing the code to
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Print(strings.TrimLeft("irrelevant text¡¡¡Hello, Gophers!!!", "!¡"))
}
The result string is the whole input string: irrelevant text¡¡¡Hello, Gophers!!!
Aren't at least the cutset characters supposed to be removed?!
It is an industry standard that trim implies a proper suffix or prefix.
trimLeft will only remove matching characters from the beginning of the string and stop on the first non-match. In your example, the "i" of "irrelevant" is the first character it checks. It fails the check, so it stops trimming (i.e. it does nothing).
trimRight, by comparison, removes matches starting from the end of the string in descending index order.
Aren't at least the cutset characters supposed to be removed?!
All of the ones at the beginning of the string. There are zero of those, so zero characters are removed.

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;
}

Resources