2017-01-27 9 views
5

Я пытаюсь сделать awk как инструмент, который использует Rebol 3 для обработки больших текстовых файлов с помощью труб и инструментов bash. У меня проблема с чтением STDIN по строчке в Rebol 3?Rebol 3: чтение STDIN эффективно по строкам (чтобы сделать awk как инструмент)

Например, эта команда оболочки производит 3 линии:

$ (echo "first line" ; echo "second line" ; echo "third line") 
first line 
second line 
third line 

Но вход слово в Rebol читает все 3 линии одновременно. Я ожидал бы, что он остановится на новой линии, поскольку он остановится, если вы используете ввод интерактивно.

r3 --do 'while [ x: input ] [ if empty? x [ break ] print x print "***" ]' 
abcdef 
abcdef 
*** 
blabla 
blabla 
*** 

Но когда я запускаю его все вместе, он считывает весь ввод сразу. Я мог прочитать все это сразу и разделить на строки, но я хочу, чтобы он работал «потоковым» образом, как обычно cat во многих 1000-х строках.

$ (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 
*** 

Я также посмотрел на источник ввода сделать подобную функцию. Я мог читать символ на символ в , а, и проверять на новые строки, но это не кажется эффективным.

ответ

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 
]  

Он работает, как это. чтение/строки считывает несколько символов из потока и возвращает блок строк. Каждый раз, когда он называется, он читает следующую партию таких символов, так что все это завернуто в цикл while. Код обрабатывает (делает блок кода) как циклы while (а не в конце).

Партия символов не заканчивается на новой строке, поэтому последняя строка частично каждый раз. И это первая строка в следующей партии, поэтому она объединяет их вместе. В конце он должен обработать последнюю (на этот раз не частичную) линию. Попробуйте, потому что некоторые строки вызвали ошибки кодирования 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 

Вещи, чтобы улучшить: сделать функцию в целом лучше, дедуплицировать некоторый код. Проверьте, что произойдет, если чтение/строки заканчиваются точно на новой строке.

+0

Хорошо находкой о 'прочитать lines' буферизацию/на STDIN. Однако он не работает полностью для меня в MacOS (OSX) :(Вместо «block!» Он возвращает «двоичный!» Из 34815 байтов (до тех пор, пока STDIN не будет исчерпан). NB. Фактически '/ lines' (и '/ string') ничего не делают на MacOS :( – draegtun

3

Я столкнулся с той же проблемой с input пару лет назад. Я не думаю, что это запланированные изменения, а скорее неполная реализация (коснитесь дерева!).

Вот обходная функция, которую я написал в то время (которая отлично работала для меня на MacOS & Linux).

input-line: function [ 
    {Return next line (string!) from STDIN. Returns NONE when nothing left} 
    /part size [integer!] "Internal read/part (buffer) size" 
    ][ 
    buffer: {} ;; static 
    if none? part [size: 1024] 

    forever [ 
     if f: find buffer newline [ 
      remove f ;; chomp newline (NB. doesn't cover Windows CRLF?) 
      break 
     ] 

     if empty? data: read/part system/ports/input size [ 
      f: length? buffer 
      break 
     ] 

     append buffer to-string data 
    ] 

    unless all [empty? data empty? buffer] [take/part buffer f] 
] 

Пример использования:

while [not none? line: input-line] [ 
    ;; do something with LINE of data from STDIN 
] 

 Смежные вопросы

  • Нет связанных вопросов^_^