读取文本文件,替换其中的单词,输出到另一个文本文件。

4
我正在尝试用GO编写一个程序,将一个充满代码的文本文件转换为GO代码,然后将该文件保存到GO文件或文本文件中。我一直在尝试找出如何保存我对文本文件所做的更改,但是我唯一能看到更改的方法是通过println语句,因为我使用了strings.replace来搜索存储在字符串数组中的文本文件并更改需要更改的每个单词的出现次数(例如:BEGIN -> {和END -> })。那么,是否有其他我不知道的GO中的搜索和替换方式,或者有没有我不知道的编辑文本文件的方法,或者这是不可能的?
谢谢。
以下是我目前的代码。
package main

import (
    "os"
    "bufio"
    "bytes"
    "io"
    "fmt"
    "strings"
)


func readLines(path string) (lines []string, errr error) {
    var (
        file *os.File
        part []byte
        prefix bool
    )
    if file, errr = os.Open(path); errr != nil {
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 0))
    for {
        if part, prefix, errr = reader.ReadLine(); errr != nil {
            break
        }
    buffer.Write(part)
        if !prefix {
            lines = append(lines, buffer.String())
            buffer.Reset()
        }
    }
    if errr == io.EOF {
        errr = nil
    }
    return
}

func writeLines(lines []string, path string) (errr error) {
    var (
        file *os.File
    )

    if file, errr = os.Create(path); errr != nil {
        return
    }
    defer file.Close()


    for _,item := range lines {

        _, errr := file.WriteString(strings.TrimSpace(item) + "\n");

        if errr != nil {

            fmt.Println(errr)
            break
        }
    }

    return
}

func FixBegin(lines []string) (errr error) {
    var(
    a string

    )
for i := 0; ; i++ {
        a = lines[i];

        fmt.Println(strings.Replace(a, "BEGIN", "{", -1))
    }

    return
}

func FixEnd(lines []string) (errr error) {
    var(
    a string

    )
for i := 0; ; i++ {
        a = lines[i];

        fmt.Println(strings.Replace(a, "END", "}", -1))
    }
    return
}

func main() {
    lines, errr := readLines("foo.txt")
    if errr != nil {
        fmt.Println("Error: %s\n", errr)
        return
    }
    for _, line := range lines {
        fmt.Println(line)
    }


    errr = FixBegin(lines)

    errr = writeLines(lines, "beer2.txt")
    fmt.Println(errr)

    errr = FixEnd(lines)
    lines, errr = readLines("beer2.txt")
    if errr != nil {
        fmt.Println("Error: %s\n", errr)
        return
    }
    errr = writeLines(lines, "beer2.txt")
    fmt.Println(errr)
}
3个回答

3
jnml@fsc-r630:~/src/tmp/SO/13789882$ ls
foo.txt  main.go
jnml@fsc-r630:~/src/tmp/SO/13789882$ cat main.go 
package main

import (
        "bytes"
        "io/ioutil"
        "log"
)

func main() {
        src, err := ioutil.ReadFile("foo.txt")
        if err != nil {
                log.Fatal(err)
        }

        src = bytes.Replace(src, []byte("BEGIN"), []byte("{"), -1)
        src = bytes.Replace(src, []byte("END"), []byte("}"), -1)
        if err = ioutil.WriteFile("beer2.txt", src, 0666); err != nil {
                log.Fatal(err)
        }
}
jnml@fsc-r630:~/src/tmp/SO/13789882$ cat foo.txt 
BEGIN
  FILE F(KIND=REMOTE);
  EBCDIC ARRAY E[0:11];
  REPLACE E BY "HELLO WORLD!";
  WRITE(F, *, E);
END.
jnml@fsc-r630:~/src/tmp/SO/13789882$ go run main.go 
jnml@fsc-r630:~/src/tmp/SO/13789882$ cat beer2.txt 
{
  FILE F(KIND=REMOTE);
  EBCDIC ARRAY E[0:11];
  REPLACE E BY "HELLO WORLD!";
  WRITE(F, *, E);
}.
jnml@fsc-r630:~/src/tmp/SO/13789882$ 

非常感谢您的回答!!我不知道它是那么容易的!! - user1889820
简单方法:sed 想成为你的朋友:$ sed -e 's/BEGIN/{/g' -e 's/END/}/g' foo.txt # ;-) - zzzz

3

我同意@jnml使用ioutil来读取文件并写回文件的观点。但是,我认为替换不应该通过多次对[]byte进行操作。代码和数据是字符串/文本,应该作为这样处理(即使处理非ascii/utf8编码需要额外的工作);一次性替换(所有占位符“一次性”)可以避免替换先前更改的结果(即使我的正则表达式提议必须改进以处理非平凡任务)。

package main

import(
    "fmt"
    "io/ioutil"
    "log"
    "regexp"
    "strings"
)

func main() {
    // (1) slurp the file
    data, err := ioutil.ReadFile("../tmpl/xpl.go")
    if err != nil {
        log.Fatal("ioutil.ReadFile: ", err)
    }
    s := string(data)
    fmt.Printf("----\n%s----\n", s)
    // => function that works for files of (known) other encodings that ascii or utf8

    // (2) create a map that maps placeholder to be replaced to the replacements
    x := map[string]string {
        "BEGIN" : "{",
        "END" : "}"}
    ks := make([]string, 0, len(x))
    for k := range x {
        ks = append(ks, k)
    }
    // => function(s) that gets the keys from maps

    // (3) create a regexp that finds the placeholder to be replaced
    p := strings.Join(ks, "|")
    fmt.Printf("/%s/\n", p)
    r := regexp.MustCompile(p)
    // => funny letters & order need more consideration

    // (4) create a callback function for ..ReplaceAllStringFunc that knows
    // about the map x
    f := func(s string) string {
        fmt.Printf("*** '%s'\n", s)
        return x[s]
    }
    // => function (?) to do Step (2) .. (4) in a reusable way

    // (5) do the replacing (s will be overwritten with the result)
    s = r.ReplaceAllStringFunc(s, f)
    fmt.Printf("----\n%s----\n", s)

    // (6) write back
    err = ioutil.WriteFile("result.go", []byte(s), 0644)
    if err != nil {
        log.Fatal("ioutil.WriteFile: ", err)
    }
    // => function that works for files of (known) other encodings that ascii or utf8
}

输出:

go run 13789882.go
----
func main() BEGIN
END
----
/BEGIN|END/
*** 'BEGIN'
*** 'END'
----
func main() {
}
----

1
如果您的文件大小很大,将所有内容读入内存可能不可行,也不建议这样做。尝试使用 BytesReplacingReader 以流式方式进行替换。而且性能还不错。如果您想要替换两个字符串(例如 BEGIN -> {END -> }),只需要在原始读取器上包装两个 BytesReplacingReader,一个用于 BEGIN,另一个用于 END
r := NewBytesReplacingReader(
    NewBytesReplacingReader(inputReader, []byte("BEGIN"), []byte("{"),
    []byte("END"), []byte("}")
// use r normally and all non-overlapping occurrences of
// "BEGIN" and "END" will be replaced with "{" and "}"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接