String 从读卡器读取,直到到达字符串为止
我正试图编写一个函数,以保持从缓冲读取器读取数据,直到命中某个字符串,然后停止读取并返回该字符串之前读取的所有内容 换句话说,我想做与String 从读卡器读取,直到到达字符串为止,string,go,String,Go,我正试图编写一个函数,以保持从缓冲读取器读取数据,直到命中某个字符串,然后停止读取并返回该字符串之前读取的所有内容 换句话说,我想做与reader.ReadString()相同的事情,不同的是使用字符串而不是单个字节 例如: mydata, err := reader.ReadString("\r\n.\r\n") //obviously will not compile 我该怎么做 提前感谢, 特维奇 修正案1:以前的尝试 这是我以前的尝试;它写得很糟糕,不起作用,但希望
reader.ReadString()
相同的事情,不同的是使用字符串而不是单个字节
例如:
mydata, err := reader.ReadString("\r\n.\r\n") //obviously will not compile
我该怎么做
提前感谢,
特维奇
修正案1:以前的尝试
这是我以前的尝试;它写得很糟糕,不起作用,但希望它能证明我在努力做什么
func readDotData(reader *bufio.Reader)(string, error){
delims := []byte{ '\r', '\n', '.', '\r', '\n'}
curpos := 0
var buffer []byte
for {
curpos = 0
data, err := reader.ReadSlice(delims[0])
if err!=nil{ return "", err }
buffer = append(buffer, data...)
for {
curpos++
b, err := reader.ReadByte()
if err!=nil{ return "", err }
if b!=delims[curpos]{
for curpos >= 0{
buffer = append(buffer, delims[curpos])
curpos--
}
break
}
if curpos == len(delims){
return string(buffer[len(buffer)-1:]), nil
}
}
}
panic("unreachable")
}
比如说,
package main
import (
"bufio"
"bytes"
"fmt"
"strings"
)
var delim = []byte{'\r', '\n', '.', '\r', '\n'}
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
for i := 0; i+len(delim) <= len(data); {
j := i + bytes.IndexByte(data[i:], delim[0])
if j < i {
break
}
if bytes.Equal(data[j+1:j+len(delim)], delim[1:]) {
// We have a full delim-terminated line.
return j + len(delim), data[0:j], nil
}
i = j + 1
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), data, nil
}
// Request more data.
return 0, nil, nil
}
func main() {
delims := string(delim)
input := "1234" + delims + "5678" + delims + "1234567901234567890" + delims
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(ScanLines)
for scanner.Scan() {
fmt.Printf("%s\n", scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Printf("Invalid input: %s", err)
}
}
输出:
1234
5678
1234567901234567890
"123deli456elim789"
"ABC"
2009/11/10 23:00:00 EOF
因为字符串中有相同的字节,所以可以按如下方式执行:
func readWithEnd(reader *bufio.Reader) ([]byte, error) {
message, err := reader.ReadBytes('#')
if err != nil {
return nil, err
}
a1, err := reader.ReadByte()
if err != nil {
return nil, err
}
message = append(message, a1)
if a1 != '\t' {
message2, err := readWithEnd(reader)
if err != nil {
return nil, err
}
ret := append(message, message2...)
return ret, nil
}
a2, err := reader.ReadByte()
if err != nil {
return nil, err
}
message = append(message, a2)
if a2 != '#' {
message2, err := readWithEnd(reader)
if err != nil {
return nil, err
}
ret := append(message, message2...)
return ret, nil
}
return message, nil
}
这个示例可以识别TCP连接中的
“#\t#”
,很好的答案。我还没有发现append变量的用法。它真的很有用。(对于其他还不知道这一点的人)只需指出,这个答案不是很有效,因为您正在将所有内容读入内存p:=b.Bytes()
。内存方面,它只是在某种程度上比同样的操作、转换为字符串和执行字符串查找更有效。我喜欢您实现scanner接口的方式,并从中开始。我相信很多其他人会发现这很有用,因为这是一件让我困惑的事情:)如果要做成千上万的定界操作,这绝对是一个很好的选择。我喜欢你把它作为一个界面绑定在一起,这样我就可以轻松地对读卡器进行操作;它非常有用。谢谢肯定比公认的答案要好。这将产生更少的垃圾
package main
import (
"bytes"
"fmt"
)
func main() {
b := bytes.NewBuffer([]byte("Hello, playground!\r\n.\r\nIrrelevant trailer."))
c := make([]byte, 0, b.Len())
for {
p := b.Bytes()
if bytes.Equal(p[:5], []byte("\r\n.\r\n")) {
fmt.Println(string(c))
return
}
c = append(c, b.Next(1)...)
}
}
func readWithEnd(reader *bufio.Reader) ([]byte, error) {
message, err := reader.ReadBytes('#')
if err != nil {
return nil, err
}
a1, err := reader.ReadByte()
if err != nil {
return nil, err
}
message = append(message, a1)
if a1 != '\t' {
message2, err := readWithEnd(reader)
if err != nil {
return nil, err
}
ret := append(message, message2...)
return ret, nil
}
a2, err := reader.ReadByte()
if err != nil {
return nil, err
}
message = append(message, a2)
if a2 != '#' {
message2, err := readWithEnd(reader)
if err != nil {
return nil, err
}
ret := append(message, message2...)
return ret, nil
}
return message, nil
}