可以将字符串作为参数传递给bufio.ReadString()函数作为分隔符吗?

huangapple go评论79阅读模式
英文:

Can i pass a string as a delimiter for bufio.ReadString()?

问题

我有一个包含多行查询的文件。我想逐行读取并打印它们。类似这样:

temp.sql

select * from table1;  
select *  
from table2;

select 1; 

由于我可能有多行查询,我想使用";\n"作为分隔符。这种方法可行吗?有没有比bufio.ReadString更好的方法?

英文:

I have a file which contains multi-line queries. I wanted to read them one by one and print them. Something like :

temp.sql

select * from table1;  
select *  
from table2;

select 1; 

Since i can have multiline queries I wanted to use ;\n as the delimiter. Is that possible ? Is there a better method that i can use instead of bufio.ReadString ?

答案1

得分: 7

首先,bufio.ReadString 的原型是:

func (b *Reader) ReadString(delim byte) (line string, err error)

它只能接受一个字节作为参数,所以你的 ;\n 分隔符不起作用。

请使用 ; 作为分隔符。

但是,如果你使用 ReadString(';'),结果中将包含其他字符,比如 \n

一个例子:

package main

import (
	"bufio"
	"fmt"
	"strings"
)

func main() {

	const raw = `select * from table1;  
select *  
from table2;

select 1;`

	br := bufio.NewReader(strings.NewReader(raw))

	var err error
	var s string
	err = nil
	for err == nil {
		s, err = br.ReadString(';')
		if err == nil {
			fmt.Printf("%q", s)
		}

	}
}

这将得到:

"select * from table1;"  \nselect *  \nfrom table2;"\n\nselect 1;"

在线测试

解决方案:

使用 Scanner 可能更方便,并且可以实现如下效果。

注意:; 将被视为单词的一部分。

package main

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

func main() {
	const raw = `select * from table1;  
select *  
from table2;

select 1;`

	scanner := bufio.NewScanner(strings.NewReader(raw))
	scanner.Split(bufio.ScanWords)
	
	var tmpbuf bytes.Buffer
	
	for scanner.Scan() {
		w := scanner.Text()
		tmpbuf.WriteString(w)
		if w[len(w)-1] == ';' {
		    tmpbuf.WriteString("\n")
			fmt.Printf(tmpbuf.String())
			tmpbuf.Reset()
		} else {
		    tmpbuf.WriteString(" ")
		}
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading input:", err)
	}
}

你将得到:

select * from table1;
select * from table2;
select 1;

在线测试

英文:

firstly, the prototype of bufio.ReadString is

 func (b *Reader) ReadString(delim byte) (line string, err error)

it can only take one byte as arg, so your ;\n delimiter won't work.

use ; as delimiter instead.

But if you use ReadString(';') it will contain other characters in your results, such as '\n'

a example:

package main

import (
	"bufio"
	"fmt"
	"strings"
)

func main() {

	const raw = `select * from table1;  
select *  
from table2;

select 1;`

	br := bufio.NewReader(strings.NewReader(raw))

	var err error
	var s string
	err = nil
	for err == nil {
		s, err = br.ReadString(';')
		if err == nil {
			fmt.Printf("%q", s)
		}

	}

this will get:

"select * from table1;""  \nselect *  \nfrom table2;""\n\nselect 1;"

online test

Solution:

use Scanner may be more convenient, and achieve this as bellow.

ps: ; will be considered as part of words

package main

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

func main() {
	const raw = `select * from table1;  
select *  
from table2;

select 1;`

	scanner := bufio.NewScanner(strings.NewReader(raw))
	scanner.Split(bufio.ScanWords)
	
	var tmpbuf bytes.Buffer
	
	for scanner.Scan() {
		w := scanner.Text()
		tmpbuf.WriteString(w)
		if w[len(w)-1] == ';' {
		    tmpbuf.WriteString("\n")
			fmt.Printf(tmpbuf.String())
			tmpbuf.Reset()
		} else {
		    tmpbuf.WriteString(" ")
		}
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading input:", err)
	}
}

you will get:

select * from table1;
select * from table2;
select 1;

online test

答案2

得分: 2

你可以使用bufio.Scanner来实现这个功能:https://golang.org/pkg/bufio/#Scanner
可以参考这个示例代码:https://golang.org/pkg/bufio/#example_Scanner_lines

英文:

You can use bufio.Scanner for that: https://golang.org/pkg/bufio/#Scanner
See the lines example: https://golang.org/pkg/bufio/#example_Scanner_lines

huangapple
  • 本文由 发表于 2016年1月15日 09:41:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/34803029.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定