Print new line from argument in command line - go

Morning All
I am trying to put together an ASCII art generator which accepts a word as a command line argument and prints out in ASCII art. This is working so far however, instead of interpreting "\n" as a new line it is printing these characters as ASCII art as well. Any ideas on how I can print a new line instead?
I have tried splitting the argument using code below but doesn't seem to do anything:
split := strings.Split(wordArg[1], "\n")
fmt.Println(split)
This just prints out [hello\n].
I am printing using printf if there is anything I can add there to help interpret the \n as new line instead of as being part of the string.
I have added the whole code if it helps make sense of what I'm doing:
package main
import (
"bufio"
"fmt"
//"strings"
//"io/ioutil"
"log"
"os"
"strings"
)
func main() {
wordArg := os.Args
split := strings.Split(wordArg[1], "\n")
fmt.Println(split)
wordRune := []rune(wordArg[1])
f, err := os.Open("standard.txt")
if err != nil {
fmt.Println(err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
var lines []string
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
for i := 0; i < 8; i++ {
for j := 0; j < len(wordRune); j++ {
if lines[int(wordRune[j])*9-287+i] == " " {
fmt.Printf(" ")
} else {
fmt.Printf(lines[int(wordRune[j])*9-287+i])
}
}
fmt.Print("\n")
}
}
Any help would be much appreciated.
Thanks

strings.ReplaceAll
func ReplaceAll(str, oldstr, newstr string) string
The Replace All function does as the name suggests, and replaces all occurrences of oldstr with newstr within str.
strings.ReplaceAll(os.Args[1], "\\n", "\n")
This will return a string containing the first argument from the command line, with newlines in place of a literal backslash and letter n.

Related

Is there a way in golang to replace all CR and LF line endings in a byte array?

I am trying to create two separate functions in golang, one that is able to replace any CR line endings (\r) with \u00A0 and any LF line endings (\n) with \u00A1, and a second that is able to reverse the original function, or restore the CR and LF line endings later on.
It should also be noted, that data I am working with, has been read from a file, encrypted, and then compressed. I am trying to just get all the data on one line, so I can later read a file line by line to decompress and decrypt the file's chunks.
I have previously tried these two functions, that convert the byte array to a string, and replace parts of the string, but the after dumping the byte array to a file, it still had multiple CR and LF line endings.
func removeLineBreaks(input []byte) []byte {
str := strings.Replace(string(input), "\r", "\u00A0", -1)
str = strings.Replace(str, "\n", "\u00A1", -1)
return []byte(str)
}
func restoreLineBreaks(input []byte) []byte {
str := strings.Replace(string(input), "\u00A0", "\r", -1)
str = strings.Replace(str, "\u00A1", "\n", -1)
return []byte(str)
}
I have also tried the following two functions, and still have multiple CR and LF line endings.
func removeLineBreaks(input []byte) []byte {
output := make([]byte, 0, len(input))
for i := 0; i < len(input); i++ {
if input[i] == '\r' {
output = append(output, '\u00A0')
} else if input[i] == '\n' {
output = append(output, '\u00A1')
} else {
output = append(output, input[i])
}
}
return output
}
func restoreLineBreaks(input []byte) []byte {
output := make([]byte, 0, len(input))
for i := 0; i < len(input); i++ {
if input[i] == '\u00A0' {
output = append(output, '\r')
} else if input[i] == '\u00A1' {
output = append(output, '\n')
} else {
output = append(output, input[i])
}
}
return output
}
The thing I was mainly expecting, was to be able to view all the data on one line, without any new line endings (CR, LF, or CR LF), that way I can process the data the way I intended later on.
I figured out the answer to my problem, the reason I was not getting the bytes returned as I wanted, was because I did not actually put anything for the function to return the value to.
byteChunk = removeLineBreaks(byteChunk)
The above two functions work as they should, here is the resulting code I used to test that everything worked the way it should:
package main
import (
"fmt"
"os"
"strings"
"github.com/google/brotli/go/cbrotli"
)
func main() {
byteChunk := []byte("hello world\rThis is a test\r\nFor removing lines\nHello\r\nWorld")
fmt.Printf("Original:\n%s\n\n", byteChunk)
compressedChunk, err := cbrotli.Encode(byteChunk, cbrotli.WriterOptions{Quality: 11})
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("Compressed:\n%s\n\n", compressedChunk)
removedLines := removeLineBreaks(compressedChunk)
fmt.Printf("Removed Lines:\n%s\n\n", removedLines)
restoredLines := restoreLineBreaks(removedLines)
fmt.Printf("Restored Lines:\n%s\n\n", restoredLines)
decompressedChunk, err := cbrotli.Decode(restoredLines)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("Decompressed:\n%s\n\n", decompressedChunk)
}
func removeLineBreaks(input []byte) []byte {
str := strings.Replace(string(input), "\r", "\u00A0", -1)
str = strings.Replace(str, "\n", "\u00A1", -1)
return []byte(str)
}
func restoreLineBreaks(input []byte) []byte {
str := string(input)
str = strings.Replace(str, "\u00A0", "\r", -1)
str = strings.Replace(str, "\u00A1", "\n", -1)
return []byte(str)
}

Go regExRepl-Script does not change the text file

my go script should add one newline before matching the regEx-Search-String ^(.+[,]+\n).
The Prototype i had tested before into the editor:
i want add newlines before this lines: \n$1.
This works if i try it into the Text-Editor.
If i try this (see line 24) with my script it is changing nothing and sends no error.
Any ideas what i do wrong?
Example
i like to use PCRE like it works in this Example https://regex101.com/r/sB9wW6/17
Same Example here:
Example source
Dear sir,
Thanks for your interest.
expected result
#### here is a newline ####
Dear sir,
Thanks for your interest.
result is (produced by the script below)
Dear sir,
Thanks for your interest.
go script:
// replace in files and store the new copy of it.
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"time"
)
func visit(path string, fi os.FileInfo, err error) error {
matched, err := filepath.Match("*.csv", fi.Name())
if err != nil {
panic(err)
return err
}
if matched {
read, err := ioutil.ReadFile(path)
if err != nil {
panic(err)
}
newContents := string(read)
newContents = regExRepl(`^(.+[,]+\n)`, newContents, `\n\n\n$1`)
var re = regexp.MustCompile(`[\W]+`)
t_yymmdd := regexp.MustCompile(`[\W]+`).ReplaceAllString(time.Now().Format(time.RFC3339), `-`)[:10]
t_hhss := re.ReplaceAllString(time.Now().Format(time.RFC3339), `-`)[11:19]
t_yymmddhhss := t_yymmdd + "_" + t_hhss
fmt.Println(t_yymmddhhss)
filePath := fileNameWithoutExtension(path) + t_yymmddhhss + ".csv"
err = ioutil.WriteFile(filePath, []byte(newContents), 0)
if err != nil {
panic(err)
}
}
return nil
}
func regExRepl(regExPatt string, newContents string, regExRepl string) string {
return regexp.MustCompile(regExPatt).ReplaceAllString(newContents, regExRepl)
}
func main() {
err := filepath.Walk("./november2020messages.csv", visit) // <== read all files in current folder 20:12:06 22:44:42
if err != nil {
panic(err)
}
}
func fileNameWithoutExtension(fileName string) string {
return strings.TrimSuffix(fileName, filepath.Ext(fileName))
}
for interpretation \n as newline don't us
`\n`` use "\n"
may use ^(.+[,]+) instead ^(.+[,]+\n) and ad (?m) before for multi-line replacements
this suggestion you could test here: https://play.golang.org/p/25_0GJ93oCT
The following example illustrates the difference (in golang-playground here https://play.golang.org/p/FkPwElhx-Xu ):
// example from:
package main
import (
"fmt"
"regexp"
)
func main() {
newContents := `line 1,
line 2
line a,
line b`
newContents1 := regexp.MustCompile(`^(.+[,]+\n)`).ReplaceAllString(newContents, `\n$1`)
fmt.Println("hi\n" + newContents1)
newContents1 = regexp.MustCompile(`(?m)^(.+[,]+\n)`).ReplaceAllString(newContents, "\n$1")
fmt.Println("ho\n" + newContents1)
}
Result:
hi
\nline 1,
line 2
line a,
line b
ho
line 1,
line 2
line a,
line b

Replace a line in text file Golang

How do I replace a line in a text file with a new line?
Assume I've opened the file and have every line in an array of string objects i'm now looping through
//find line with ']'
for i, line := range lines {
if strings.Contains(line, ']') {
//replace line with "LOL"
?
}
}
What matters here is not so much what you do in that loop. It's not like you're gonna be directly editing the file on the fly.
The most simple solution for you is to just replace the string in the array and then write the contents of the array back to your file when you're finished.
Here's some code I put together in a minute or two. It properly compiles and runs on my machine.
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
input, err := ioutil.ReadFile("myfile")
if err != nil {
log.Fatalln(err)
}
lines := strings.Split(string(input), "\n")
for i, line := range lines {
if strings.Contains(line, "]") {
lines[i] = "LOL"
}
}
output := strings.Join(lines, "\n")
err = ioutil.WriteFile("myfile", []byte(output), 0644)
if err != nil {
log.Fatalln(err)
}
}
There's a gist too (with the same code)
https://gist.github.com/dallarosa/b58b0e3425761e0a7cf6

Is there a ReadLine equivalent for a file in Go?

I want to ReadBytes until "\n" for a text file, not a bufio.
Is there a way to do this without converting to a bufio?
There are many ways to do it, but wrapping with bufio is what I would suggest. But if that doesn't work for you (why not?), you can go ahead and read single bytes like this:
Full working example:
package main
import (
"bytes"
"fmt"
"io"
)
// ReadLine reads a line delimited by \n from the io.Reader
// Unlike bufio, it does so rather inefficiently by reading one byte at a time
func ReadLine(r io.Reader) (line []byte, err error) {
b := make([]byte, 1)
var l int
for err == nil {
l, err = r.Read(b)
if l > 0 {
if b[0] == '\n' {
return
}
line = append(line, b...)
}
}
return
}
var data = `Hello, world!
I will write
three lines.`
func main() {
b := bytes.NewBufferString(data)
for {
line, err := ReadLine(b)
fmt.Println("Line: ", string(line))
if err != nil {
return
}
}
}
Output:
Line: Hello, world!
Line: I will write
Line: three lines.
Playground: http://play.golang.org/p/dfb0GHPpnm

How to improve this file reading code

I currently have this piece of code that will read a file line by line (delimited by a \n)
file, _ := os.Open(filename) //deal with the error later
defer file.Close()
buf := bufio.NewReader(file)
for line, err := buf.ReadString('\n'); err != io.EOF; line, err = buf.ReadString('\n')
{
fmt.Println(strings.TrimRight(line, "\n"))
}
However I don't feel comfortable with writing buf.ReadString("\n") twice in the for loop, does anyone have any suggestions for improvement?
bufio.ReadString reads until the first occurrence of delim in the input,
returning a string containing the data up to and including the
delimiter. If ReadString encounters an error before finding a
delimiter, it returns the data read before the error and the error
itself (often io.EOF). ReadString returns err != nil if and only if
the returned data does not end in delim.
If buf.ReadString('\n') returns an error other than io.EOF, for example bufio.ErrBufferFull, you will be in an infinite loop. Also, if the file doesn't end in a '\n', you silently ignore the data after the last '\n'.
Here's a more robust solution, which executes buf.ReadString('\n') once.
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
func main() {
filename := "FileName"
file, err := os.Open(filename)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
buf := bufio.NewReader(file)
for {
line, err := buf.ReadString('\n')
if err != nil {
if err != io.EOF || len(line) > 0 {
fmt.Println(err)
return
}
break
}
fmt.Println(strings.TrimRight(line, "\n"))
}
}
Most code that reads line by line can be improved by not reading line by line. If your goal is to read the file and access the lines, something like the following is almost always better.
package main
import (
"fmt"
"io/ioutil"
"log"
"strings"
)
func main() {
b, err := ioutil.ReadFile("filename")
if err != nil {
log.Fatal(err)
}
s := string(b) // convert []byte to string
s = strings.TrimRight(s, "\n") // strip \n on last line
ss := strings.Split(s, "\n") // split to []string
for _, s := range ss {
fmt.Println(s)
}
}
Any errors come to you at a single point so error handling is simplified. Stripping a newline off the last line allows for files that may or may not have that final newline, as Peter suggested. Most text files are tiny compared to available memory these days, so reading these in one gulp is appropriate.

Resources