在 Racket 中,我希望能够查看端口中的任何位置(也在当前位置之前(,并读取那里的内容,而不会以任何方式影响端口。指定的位置(在下面的代码中start-pos
(应该是从头开始的,而不是相对于当前端口位置!
我的第一次尝试:
(define (extract-string port start-pos span)
(define pos (file-position port))
(file-position port start-pos)
(define result (read-string span port))
(file-position port pos)
result)
(define port (open-input-string "Hello world"))
(port-count-lines! port)
(port-next-location port)
(extract-string port 0 3)
(port-next-location port)
输出:
1
0
1
"Hel"
1
3
4
不知何故,(file-position port pos)
没有重置位置......
我的第二次尝试:
(define (extract-string port start-pos span)
(define port2 (peeking-input-port port #:init-position start-pos))
(read-string span port2))
(define port (open-input-string "Hello world"))
(port-count-lines! port)
; port-next-location is not affected; great
(port-next-location port)
(extract-string port 1 3)
(port-next-location port)
; Reading from an earlier point does not work!
(read-string 6 port)
(extract-string port 1 3)
(read-string 5 port)
输出:
1
0
1
"Hel"
1
0
1
"Hello "
"wor"
"world"
编辑: 预期输出:
1
0
1
"Hel"
1
0
1
"Hello "
"Hel"
"world"
一个小的改进,但它仍然没有按预期工作。由于某种原因,port2
的初始位置与port
的初始位置偏移,尽管参考文献说
生成的端口的初始位置(由文件位置报告( 是 (- init-position 1(,无论 in 的位置如何。
在球拍中不可能做到这一点吗?
注释后编辑:
(define port (open-input-string "Hello world"))
(define (extract-string-getter my_port)
(let* ((prev_pos (file-position my_port))
(new_port (open-input-string (port->string my_port))))
(file-position my_port prev_pos)
(lambda (start_pos span)
(peek-string span start_pos new_port))
))
(define runner (extract-string-getter port))
runner
(runner 1 3)
(runner 1 3)
;(runner 5 9)
(port-count-lines! port)
; port-next-location is not affected; great
(port-next-location port)
;(extract-string port 1 3)
(port-next-location port)
; Reading from an earlier point does not work!
(read-string 6 port)
(runner 0 2)
(read-string 5 port)
(runner 6 9)
您仍然有一个范围界定问题:)了解范围输入和输出非常重要。
内部 lambda 有一个状态,通过保存对它的引用"reader",我能够重用它的内部对象状态!
输出:
#<procedure:...Documents1.rkt:18:4>
"ell"
"ell"
1
0
1
1
0
1
"Hello "
"He"
"world"
"world"
重要事项:
- 提取字符串的参数端口最好使用与全局参数端口名称不同的名称。 我做了一个新端口,以免
- 妨碍原始端口,然后读取所有内容并重置文件位置(尽管我确定有一种更漂亮的方法(。
- 在需要封装时将 lambda 用作对象