我有一个文本文件,其中包含多行,以空行分隔。 在Go中逐行读取该行的最佳方法是什么?
我想我可能必须将扫描仪与我自己的分割功能一起使用,但是只是想知道是否有一种更好/更容易的方式而遗失了。
我尝试使用基于bufio.ScanLines的自己的Splitfunc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | func MyScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.IndexAny(data," "); i >= 0 { return i + 1, dropCR(data[0:i]), nil } if atEOF { return len(data), dropCR(data), nil } return 0, nil, nil } |
但是在IndexAny调用中出现错误:
"语法错误:意外的分号或换行符,期待)"-修复了该问题
更新:按建议修复了上面的语法错误,但是我只得到返回的第一行。 我正在读取文件,如下所示:
1 2 3 | scanner.Split(MyScanLines) scanner.Scan() fmt.Println(scanner.Text()) |
有什么建议么?
我尝试读取的测试文件示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Name ="John" Surname ="Smith" Val1 = 700 Val2 = 800 Name ="Pete" Surname ="Jones" Val1 = 555 Val2 = 666 Val3 = 444 . . . |
- 请提供您尝试读取的文件样本。
- @PrashantThakkar现在在原始帖子中提供了示例。 一些值对可能在一个记录中,而不在其他记录中,顺序也不固定。
- 谢谢,对于您所得到的错误,它清楚地表明缺少")"。 已更正:如果i:= bytes.IndexAny(data," n n"); i> = 0 {
- @PrashantThakkar啊,不! 我一直在盯着那个代码,没有去接它。 啊。 感谢那。 是我推荐的方式吗?
这是使用
下面的
1 2 3 4 5 6 7 8 9 10 | func myReadLine(file *os.File, reader *bufio.Reader) (lines []string, err error){ for { line, _, err := reader.ReadLine() if err != nil || len(line) == 0 { break } lines = append(lines, string(line)) } return lines, err } |
下面的代码示例说明了上述功能的示例用法:
1 2 3 4 5 6 7 8 | reader := bufio.NewReader(file) for { lines, err := myReadLine(file, reader) if err != nil || len(lines) == 0 { break } fmt.Println(lines) } |
您的方式正常,但我建议您使用
然后,您就可以开始逐行读取文件并填充结构。遇到空白行时,将您的结构切成片并从新的结构开始。
这是一个示例,摘自我的一个开源项目进行了演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | buffer := [][]string{} block := []string{} scanner := bufio.NewScanner(strings.NewReader(data)) for scanner.Scan() { l := scanner.Text() if len(strings.TrimSpace(l)) != 0 { block = append(block, l) continue } // At this point, the script has reached an empty line, // which means the block is ready to be processed. // If the block is not empty, append it to the buffer and empty it. if len(block) != 0 { buffer = append(buffer, block) block = []string{} } } if len(block) != 0 { buffer = append(buffer, block) } |
- 您的代码无效。 在Go游乐场中查看它:play.golang.org/p/v5aOCK7zRG
- 感谢您提到它,我有效地颠倒了条件,同时从代码中删除了无关的上下文。 我对其进行了修复,并在最后添加了一张支票以说明文件的末尾。
bufio.Scan()在EOF上返回false。
我们将返回第二个" ok"参数,以便我们的呼叫者可以告诉我们是否
在我们输入的末尾。
最好将我们的记录累积在字符串中,并在末尾进行连接。
将每行依次追加到结果字符串的明显方法是可行的,但行数为O(n ^ 2)。
放在一起:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | func ReadBlock(scanner *bufio.Scanner) (string, bool) { var o []string if scanner.Scan() == false { return"", false } for len(scanner.Text()) > 0 { o = append(o, scanner.Text()) if scanner.Scan() == false { break } } return strings.Join(o,""), true } |
https://play.golang.org/p/C_fB8iaYJo
ps。查看您的输入,我怀疑您想将结果作为映射而不是串联字符串返回。
坏了。首先了解扫描并确保其正常工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package main import ( "bufio" "fmt" "strings" ) func main() { scanner := bufio.NewScanner(strings.NewReader(data)) for scanner.Scan() { l := scanner.Text() fmt.Println(l) } } var data = ` Name ="John" Surname ="Smith" Val1 = 700 Val2 = 800 Name ="Pete" Surname ="Jones" Val1 = 555 Val2 = 666 Val3 = 444 ` |
这是Go操场上的代码。
接下来,将您需要的数据收集到一个切片中。可能有一种方法可以检查文件结尾EOF,但我找不到它。这是我想出的,并且有效:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package main import ( "bufio" "fmt" "strings" ) func main() { buffer := [][]string{} block := []string{} scanner := bufio.NewScanner(strings.NewReader(data)) for scanner.Scan() { l := scanner.Text() if len(l) != 0 { block = append(block, l) continue } if len(l) == 0 && len(block) != 0 { buffer = append(buffer, block) block = []string{} continue } if len(l) == 0 { block = []string{} continue } } if len(block) != 0 { buffer = append(buffer, block) block = []string{} } fmt.Println("PRINTING BUFFER - END OF PROGRAM - ALL DATA PROCESSED:", buffer) } var data = ` Name ="John" Surname ="Smith" Val1 = 700 Val2 = 800 Name ="Pete" Surname ="Jones" Val1 = 555 Val2 = 666 Val3 = 444 ` |
这是操场上的代码。
- 非常感谢!
- 您基本上接受了我的答案并重新发布了它……您甚至都没有更改变量名称来自己模拟解决问题。 可怜…
- 目的是解决方案,而不是IP权利或天才创意。 您的代码无效。 我提供了另一个迭代。 我指出了我可以改进我的代码的地方。 有人改进了它,提供了另一个迭代。 团队合作专注于解决方案。 对我而言,这就是stackoverflow的意义:编码人员聚在一起互相帮助。 我没有试图窃取您的代码。 放松一下,玩的很好。 不需要名称调用。