go bufio.splitFunc()

本文探讨了如何使用自定义splitFunc在bufio.Scanner中实现数字组的扫描,针对初始缓冲区大小不同(小于和大于数据量),展示了两种场景的执行流程和结果。通过实例演示了如何处理扫描过程中的数据解析和错误处理。

原理

splitFunc有go内置的4中,当然也支持自定义:
	type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
	splitFUnc的功能就是:根据两个参数返回下一次Scan需要前进几个字节(advance),分割出来的数据(token),以及错误(err)。
	参数:
		-- data(字节切片): 	 缓冲区的有效数据
		-- atEOF(bool):		是否已经输入完成(scanner是否扫描到源的结尾了),若没有则duplicate扩容!
	返回值:
		-- advance(int):	Scan需要前进几个字节(advance)
		-- token(字节切片):	 分割出来的数据
		-- err(error):		错误

	返回值可以在go内置4个splitFunc的基础上获取:
		例如scanWord:func bufio.ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)

扫描数字组(初始buffer小于数据量)

func scanIntGroup1() {
	ir := strings.NewReader("10000000000 11111111111 12222222222 13333333333")
	bs := bufio.NewScanner(ir)

	// 再scanWords()基础上实现scanTelephoneNum()
	split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		fmt.Printf("scanner是否扫描到EOF:%t,  缓冲区有效数据的数量:%d,  有效数据的内容:%s\n", atEOF, len(data), data)
		advance, token, err = bufio.ScanWords(data, atEOF)
		// 没有错误且内容不为空的时候进行处理
		if err == nil && token != nil {
			_, err = strconv.ParseInt(string(token), 10, 64) // 将token中10进制的字符串转换为int64
			if err != nil {
				panic(err)
			}
		}
		return
	}

	// 将scanner初始缓冲区长度设置为2字节,max to 65536
	buf := make([]byte, 2)
	bs.Buffer(buf, bufio.MaxScanTokenSize)
	bs.Split(split)

	// 读取
	i := 1
	for bs.Scan() {
		fmt.Printf("扫描到的第%d个匹配项:%v\n", i, bs.Text())
		i++
	}
}

扫描数字组(初始buffer大于数据量)

func scanIntGroup2() {
	ir := strings.NewReader("10000000000 11111111111 12222222222 13333333333")
	bs := bufio.NewScanner(ir)

	// 再scanWords()基础上实现scanTelephoneNum()
	split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		fmt.Printf("scanner是否扫描到EOF:%t,  scanner扫描的数据长度:%d,  scanner扫描数据的内容:%s\n", atEOF, len(data), data)
		advance, token, err = bufio.ScanWords(data, atEOF)
		// 没有错误且内容不为空的时候进行处理
		if err == nil && token != nil {
			_, err = strconv.ParseInt(string(token), 10, 64) // 将token中10进制的字符串转换为int64
			if err != nil {
				panic(err)
			}
		}
		return
	}

	// 将scanner初始缓冲区长度设置为2字节,max to 65536
	// buf := make([]byte, 2)
	// bs.Buffer(buf, bufio.MaxScanTokenSize)
	bs.Split(split)

	// 读取
	i := 1
	for bs.Scan() {
		fmt.Printf("扫描到的第%d个匹配项:%v\n", i, bs.Text())
		i++
	}
}

执行结果

func main() {
	scanIntGroup1()
	fmt.Println()
	fmt.Println("---------------------------------gorgeous separator---------------------------------")
	fmt.Println()
	scanIntGroup2()
}

图片: 在这里插入图片描述

### 关于 `bufio.NewScanner` 的使用 #### 创建 Scanner 对象 为了高效地读取文件或其他输入源中的文本行或字节切片,Go 提供了 `bufio.Scanner` 类型。可以通过调用 `bufio.NewScanner` 函数来创建一个新的 `Scanner` 实例[^1]。 ```go scanner := bufio.NewScanner(file) ``` 这段代码初始化了一个新的 `Scanner` 来从给定的 `file` 中逐行读取数据。这里假设 `file` 是一个已经打开并准备好的文件对象。 #### 设置分隔符模式 默认情况下,`Scanner` 使用换行符作为分隔符来分割输入流。如果需要改变这种行为,比如按单词而不是整行读取,则需调整其分裂函数: ```go // 按空白字符划分token,默认为nil表示按行读取 scanner.Split(bufio.ScanWords) // 自定义splitter逻辑也可以实现更复杂的解析需求 func customSplit(data []byte, atEOF bool) (advance int, token []byte, err error){ // 定义自己的拆分规则... } scanner.Split(customSplit) ``` #### 执行扫描操作 一旦配置好了 `Scanner`,就可以通过循环调用它的 `Scan()` 方法来进行实际的数据读取工作。每次成功调用都会移动到下一个标记(token),直到到达输入结尾或是发生错误为止[^2]。 ```go for scanner.Scan(){ line := scanner.Text() fmt.Println(line) } if err := scanner.Err(); err != nil { log.Fatal(err) } ``` 上述例子展示了如何遍历整个输入序列,并打印每一条记录;同时,在完成所有条目的处理之后检查是否有任何未决异常情况被报告出来。 #### 错误处理机制 值得注意的是,即使当 `Scan()` 返回 `false` 表明迭代结束时,也应当立即查询 `Err()` 以确认是否存在非正常的终止原因(例如 I/O 故障),而不仅仅是达到了自然终点即 EOF。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值