Just in time processing on a character stream

From Rosetta Code
Revision as of 00:17, 6 March 2014 by rosettacode>Gerard Schildberger (→‎{{header|REXX}}: added a link to the REXX's input file.)
Just in time processing on a character stream is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given a stream of characters, presumably (simulated) from a keyboard, that contain the separators "formfeed", "linefeed", "tab" and "space" characters. Print out the ith character of the ith tab-field of the ith line of the ith page to reveal a secret password.

Stop processing immediately upon encountering a "!" found uniquely in this i,i,i,i position (least the system self destruct). The "!" may be found/permitted else where however, in which case it should be ignored.

Ideally this can be generalise as follows:

  • The separators (formfeed, linefeed, tab, space) provided from a user supplied array and can include additional/alternative separators, e.g. (formfeed, linefeed, ".", "," ," ",...).
  • These selection criterial is generalised ith,ith,ith,ith to a boolean function of f(page,line,field,word,...) or f(ith,jth,kth,lth,mth,etc...)

Provide a reasonably interesting message to be decoded, e.g. Silence-Dogood. Your choice.

This task was inspired by the movie "National Treasure" with refers to a "book cipher".

REXX

<lang rexx>/*REXX pgm extracts characters by using a book cipher from a text file. */ parse arg iFID /*optional name of file (book). */ if iFID== then iFID="JIT.TXT" /*Not specified? Then use default*/ errTxt= ' is missing or not a positive integer: ' /*error text string.*/ $='abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= '0123456789'$ || _ ask='──────────enter four parameters (all positive integers) or QUIT' pag=1; lin=1; @.= /*assume start of page 1, line 1.*/

                                      /*read the entire book from file.*/
   do  while  lines(iFID)\==0         /*process lines from input stream*/
   _=translate(linein(iFID),,'9'x)    /*obtain a single line from input*/
   if pos('c'x,_)\==0  then do        /*was a ff (form-feed) detected? */
                            pag=pag+1 /*bump page counter for next page*/
                            lin=1     /*reset the line counter to one. */
                            end       /* [↑] handle finding of formfeed*/
   @.pag.lin=_                        /*obtain a single line from input*/
   lin=lin+1                          /*bump the line counter.         */
   end   /*while lines···*/           /* [↑]  read entire input stream.*/

?= /*define the phrase to be null.*/

      do prompt=0; bad=1              /*get J.I.T. positional numbers. */
      say ask;     pull y             /*obtain the numbers from console*/
      if y='QUIT'  then exit 0        /*the user wants out of this loop*/
      y=space(translate(y,$,$||xrange()))   /*allow any sep user wants.*/
      parse var  y  a.1 a.2 a.3 a.4   /*parse the pertinent parameters.*/
      if a.1=='QUIT'  then exit 0     /*the user wants out of this loop*/
      if words(y)>4   then do         /*did the user have fingeritis ? */
                           say 'too many parameters entered.'
                           iterate  prompt
                           end        /*go and try again to get parms. */
        do k=1  for 4                 /*validate parms {positive ints}.*/
        if datatype(a.k,'W') & a.k>0  then iterate  /*found a bad parm.*/
        say 'parameter ' k errTxt a.k /*issue an error message to term.*/
        iterate  prompt               /*go & ask for another set of #s.*/
        a.k=a.k/1                     /*normalize the user's number.   */
        end   /*k*/                   /* [↑]  done with the validations*/
      parse var  y  p l w c           /*parse parameters for names.    */
      x=substr(word(@.p.l,w),c,1)     /*extract the character from book*/
      if x=='!'  then leave           /*if the  stop  char found, done.*/
      say right(x '◄─── a letter',46) /*might as well echo char to term*/
      ?=? || x                        /*append the character to phrase.*/
      end   /*j*/                     /* [↑]  go & keep building phrase*/

say '═════►' ? /*display letters found from book*/

                                      /*stick a fork in it, we're done.*/</lang>

input   supplied to the console (terminal) by the user   (the commas are optional):

  1,   133,   4,   5
  1,    34,   9,   3
  1,  1377,   2,   2
  1,     4,   8,   4
  1,   265,   3,   5
  1,   413,  10,   2
  1,    10,  12,   1
  1,   144,  10,  10
  1,   571,   4,  12

output   (abbridged)

──────────enter four parameters  (all positive integers)   or   QUIT
  1,   133,   4,   5
                               s ◄─── a letter
──────────enter four parameters  (all positive integers)   or   QUIT

  ·
  ·
  ·

═════► so─true. 

The input file used (the IBM jargon file) in the above REXX program can be found here ───►   Just_in_time_processing_on_a_character_stream/REXX/JIT.TXT.

Tcl

Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6

oo::class create JustInTimeStreamExtract {

   variable map counter counters last
   constructor {{pageSeparator "\f"} {lineSeparator "\n"} {fieldSeparator "\t"}} {

dict set map $pageSeparator NextPage dict set map $lineSeparator NextLine dict set map $fieldSeparator NextField set counter 1 array set counters {page 0 line 0 field 0 char 0} set last ""

   }
   method emit {char} {

puts -nonewline $char set last $char

   }
   method finished {} {

if {$last ne "\n"} { puts "" }

   }
   method stream {{channel stdin} {length 1}} {

try { while 1 { set str [read $channel $length] if {[eof $channel]} break foreach c [split $str ""] { if {[dict exists $map $c]} { my [dict get $map $c] } else { my NextChar $c } } } } trap STOP {} { # Do nothing } my finished

   }
   method NextPage {} {

incr counters(page) array set counters {line 0 field 0 char 0}

   }
   method NextLine {} {

incr counters(line) array set counters {field 0 char 0}

   }
   method NextField {} {

incr counters(field) set counters(char) 0

   }
   method NextChar {char} {

incr counters(char) if {[my PrintThisOne?]} { if {$char eq "!"} { throw STOP "stop character found" } incr counter my emit $char array set counters {page 0 line 0 field 0 char 0} }

   }
   method PrintThisOne? {} {

tcl::mathop::== $counter $counters(page) $counters(line) $counters(field) $counters(char)

   }

}</lang> Demonstration of use: <lang tcl>[JustInTimeStreamExtract new] stream [open "sample.txt"]</lang>