在 Racket 中,从端口获取任意子字符串似乎是不可能的



在 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 用作对象

最新更新