Rebol 3:逐行有效地读取STDIN(使awk像工具一样)

mid*_*ayc 5 stdin rebol rebol3

我试图制作一个类似awk的工具,它使用Rebol 3来处理带有bash管道和工具的更大的文本文件.我在Rebol 3中逐行读取STDIN时遇到问题?

例如,这个shell命令产生3行:

$ (echo "first line" ; echo "second line" ; echo "third line" )
first line
second line
third line
Run Code Online (Sandbox Code Playgroud)

但是Rebol的输入字同时读取所有3行.如果您以交互方式使用输入,我会期望它停止在换行符处停止.

r3 --do 'while [ x: input ] [ if empty? x [ break ] print x print   "***" ]' 
abcdef
abcdef
***
blabla
blabla
***
Run Code Online (Sandbox Code Playgroud)

但是当我一起运行它时,它会立即读取整个输入.我可以同时阅读这一切,并分割成线,但我希望它在"流"的方式,因为我平时工作中的行许多1000-S.

$ (echo "first line" ; echo "second line" ; echo "third line" )  \
  | r3 --do 'while [ x: input ] [ if empty? x [ break ] print x print "***" ]' 
first linesecond linethird line
***
Run Code Online (Sandbox Code Playgroud)

我还查看了输入源以制作类似的功能.我可以在while循环中读取每个字符的字符并检查换行符,但这看起来效率不高.

mid*_*ayc 4

我想通了,即使在 10000 行的大文件上,它似乎也能很好地工作。不过,它还可以写得更优雅和改进。

函数r3awk接受STDIN和每行执行的代码块,将行变量绑定到它:

r3awk: func [ code /local a lines line partial ] [ 
    partial: copy ""
    lines: read/lines/string system/ports/input
    while [ not empty? lines ] [
        lines/1: rejoin [ partial lines/1 ]
        partial: pull lines
        foreach line lines [
            do bind code 'line
        ] 
        if error? try [ lines: read/lines/string system/ports/input ] [ lines: copy [] ]
    ]
    line: partial
    do bind code 'line
]    
Run Code Online (Sandbox Code Playgroud)

它的工作原理是这样的。read/lines从流中读取多个字符并返回一个行块。每次调用它时,它都会像这样读取下一批字符,因此所有内容都包含在 while 循环中。代码作为 while 循环(而不是在最后)处理(执行代码块)。

这批字符不会以换行符结束,因此最后一行 每次都是部分的。下一批中的第一行也是如此,因此它将它们连接在一起。最后它必须处理最后一行(这次是非部分行)。Try是因为有些行导致了utf编码错误。

它可以在命令行中像这样使用:

(echo "first line" ; echo "second line" ; echo "third line" ) | \
 r3 --import utils.r --do 'r3awk [ parse line [ copy x to space (print x) ] ]'
first
second
third
Run Code Online (Sandbox Code Playgroud)

需要改进的地方:使功能总体上更好,删除一些重复代码。检查如果读取/行确实在换行符处结束会发生什么。