Go strings.Replace(input, "\n", "", -1) did not recognized - go

I'm trying to process the strings inputted by users, and wrote following code.
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
var input string
fileScanner := bufio.NewScanner(os.Stdin)
fileScanner.Scan()
input = fileScanner.Text()
replaced := strings.Replace(input, "\n", "", -1)
fmt.Println(replace)
}
But I found "\n" was not replaced to "". "\n" does not seems as a string.
I tried it "." or "," instead of "\n" and it works.
I just started learning Go and this question might be too fundamental, but I appreciate for any advice.

"\" characters are processed as escape characters within a formated string and hence wont be replaced by strings.Replace
If you are really trying to replace the \n character itself, not the new line putting it inside a raw string literal should help. Refer the code below:
package main
import (
"fmt"
"strings"
)
func main() {
var input string
input = `\naaa`
replaced := strings.Replace(input, `\n`, "", -1)
fmt.Println(replaced)
}

Related

Generated valid label value (Kubernetes)

Label values in Kubernetes need to be valid.
See IsValidLabelValue()
For example the input I receive from a rest-API of a provider, which I want to write to a label: Dedicated Server 1U.
Is there a way to generate a valid label via Go from an arbitrary string?
you can have a function to do this, for example:
func generateLabel(input string) string {
input = strings.Replace(input, " ", "-", -1)
return "api-label=" + input
}
the function replaces the spaces in the received string to "-"
you can change the key to any string you like.
you can also add a regex check to make sure that the generated value complies with the label constraints. (this depends if any special characters are being received from the API)
To accept the string even when there are unwanted characters, check the below:
package main
import (
"regexp"
"strings"
"fmt"
)
func generateLabel(input string) string {
input = strings.Replace(input, " ", "-", -1)
re := regexp.MustCompile("[^a-zA-Z0-9-]")
input = re.ReplaceAllString(input, "")
re = regexp.MustCompile("^[^a-zA-Z0-9]([-a-zA-Z0-9]*[a-zA-Z0-9])?$")
input = re.ReplaceAllString(input, "")
return "api-label=" + input
}
func main() {
label := generateLabel("Dedicated Server 1U")
fmt.Println(label) // Output: "api-label=Dedicated-Server-1U"
label1 := generateLabel("Dedicated&test")
fmt.Println(label1) // Output: "api-label=Dedicatedtest"
label2 := generateLabel("Dedicated,test##&(*!great")
fmt.Println(label2) // Output: "api-label=Dedicatedtestgreat"
}

Go: CSV NewReader not getting the correct number of fields

How to get the correct number of fields when using NewReader ?
package main
import (
"encoding/csv"
"fmt"
"log"
"strings"
)
func main() {
parser := csv.NewReader(strings.NewReader(`||""FOO""||`))
parser.Comma = '|'
parser.LazyQuotes = true
record, err := parser.Read()
if err != nil {
log.Fatal(err)
}
fmt.Printf("record length: %v\n", len(record))
}
https://go.dev/play/p/gg-KYRciWFH
It should return 5, but instead I'm getting 3:
record length: 3
Program exited.
EDIT
I'm actually working with a big CSV file containing many double quotes.
After examining your code, I decided to modify it slightly and then print the results:
package main
import (
"encoding/csv"
"fmt"
"log"
"strings"
)
func main() {
parser := csv.NewReader(strings.NewReader(`x||""FOO""|x|x\n`))
parser.Comma = '|'
parser.LazyQuotes = true
record, err := parser.Read()
if err != nil {
log.Fatal(err)
}
fmt.Printf("record length: %v, Data: %v\n", len(record), strings.Join(record, ", "))
}
When you run this, the data is printed as x, , "FOO"||x|x\n". My thought is that when you end your entry with two double-quotes, the parser is assuming the string is still being quoted and therefore lumps the rest of the line into the third entry. This appears to be a bug with how lazy-quoting works in the csv package, however, when examining the documentation for LazyQuotes, you'll see this:
If LazyQuotes is true, a quote may appear in an unquoted field and a non-doubled quote may appear in a quoted field.
This doesn't mention anything about finding double quotes within double quotes. To fix this, you should either remove the quotes altogether or replace the double double-quotes ("") with double quotes (").
One other thing you might consider would be using the gocsv package. I've worked with this package in the past and it's reasonably stable. I'm not sure how it would respond to this specific issue, but it might be worth your time checking it out.
Note:
The encoding/csv package implements the RFC 4180 standard. If you have such input, that's not an RFC 4180 compliant CSV file and encoding/csv will not parse it properly.
You're misusing the quotes. Quoting a single field FOO is like this:
parser := csv.NewReader(strings.NewReader(`||"FOO"||`))
If you want the field to have the "FOO" value, you have to use 2 double quotes in a quoted field, so it should be:
parser := csv.NewReader(strings.NewReader(`||"""FOO"""||`))
This will output 5. Try it on the Go Playground.
What you have is this:
parser := csv.NewReader(strings.NewReader(`||""FOO""||`))
Since the second " character is not followed by a separator character, the field is not interrupted and the rest is processed as the content of the quoted field (which will terminate at the end of the line).
If you print the record:
fmt.Println(record)
fmt.Printf("%#v", record)
Output will be (try it on the Go Playground):
[ "FOO"||]
[]string{"", "", "\"FOO\"||"}
Quotes are a part of csv format.
There is a problem with go/csv shielding, you can try something like this:
package main
import (
"encoding/csv"
"fmt"
"log"
"strings"
)
func main() {
parser := csv.NewReader(strings.NewReader(`||FOO||`))
parser.Comma = '|'
parser.LazyQuotes = true
record, err := parser.Read()
if err != nil {
log.Fatal(err)
}
fmt.Printf("record length: %v\n", len(record))
fmt.Println(strings.Join(record, " /SEP/ "))
}
or like this:
package main
import (
"encoding/csv"
"fmt"
"log"
"strings"
)
func main() {
parser := csv.NewReader(strings.NewReader(`||"""FOO"""||`))
parser.Comma = '|'
parser.LazyQuotes = true
record, err := parser.Read()
if err != nil {
log.Fatal(err)
}
fmt.Printf("record length: %v\n", len(record))
fmt.Println(strings.Join(record, " SEP "))
}

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.

godoc Example output with CRLF

I have written the following method:
func (c *Component) Encode(w io.Writer){
//encodes c and writes the bytes into w, containing a few CRLF linebreaks
}
I also wrote the function demonstrating the encoder:
func ExampleComponent_Encode() {
c := &Component{
Name: "DESCRIPTION",
}
c.Encode(os.Stdout)
//Output:
//BEGIN:DESCRIPTION
//END:DESCRIPTION
}
The Problem is now that this example fails the go test command because the linebreaks in the comments are \n linebreaks (I'm on Linux) while the linebreaks generated by c.Encode have to be \r\n(CRLF) linebreaks (as defined by some spec).
How can i get the example to not fail go test while also keeping it straightforward? Is there perhaps a way to hint go test/godoc on the linebreaks or get them to be more lenient?
I propably can hand-edit the linebreaks on these two lines or possibly the whole codebase but that will be pretty fragile and I want to avoid this solution.
Redirect the Encode io.Writer to a buffer. In the buffer, replace CRLF (\r\n) with LF (\n) for the example output. For example,
example_test.go:
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
)
type Component struct{ Name string }
func (c *Component) Encode(w io.Writer) {
//encodes c and writes the bytes into w, containing a few CRLF linebreaks
w.Write([]byte("BEGIN:" + c.Name + "\r\n"))
w.Write([]byte("END:" + c.Name + "\r\n"))
}
func ExampleComponent_Encode() {
var buf bytes.Buffer
c := &Component{
Name: "DESCRIPTION",
}
c.Encode(&buf)
output := strings.Replace(buf.String(), "\r\n", "\n", -1)
fmt.Fprintf(os.Stdout, "%s", output)
//Output:
//BEGIN:DESCRIPTION
//END:DESCRIPTION
}
Output:
$ go test -v example_test.go
=== RUN ExampleComponent_Encode
--- PASS: ExampleComponent_Encode (0.00s)
PASS

string replace backslash with slash

I need to replace \ with / in a path string, but following code failed.
package main
import (
"fmt"
"strings"
)
func main() {
string := "P:\Project\project-name/content/topic/"
fmt.Println(strings.Replace(string, "\\", "/", -1))
}
Any helpful suggestions?
Use the function filepath.ToSlash to replace the operating system path separator with '/' in a path.
On Windows, the function returns strings.Replace(path, string(filepath.Separator), "/", -1). On other operating systems, the function returns the path argument as is.
You didn't escape backslashes in string. The following code works:
package main
import (
"fmt"
"strings"
)
func main() {
string := "P:\\Project\\project-name/content/topic/"
fmt.Println(strings.Replace(string, "\\", "/", -1))
}
Play this on playground: https://play.golang.org/p/T3XE5uiIkk
You can also use back-quotes (`) to create a raw string:
func main() {
string := `P:\Project\project-name/content/topic/`
fmt.Println(strings.Replace(string, "\\", "/", -1))
}
Note that the raw string above would still have its internal representation as
"P:\\Project\\project-name/content/topic/"
Hence the need to use "\\" in strings.Replace function.

Resources