Just in time processing on a character stream

Revision as of 23:07, 13 January 2018 by rosettacode>Gerard Schildberger (→‎{{header|REXX}}: added/deleted/changed statements, comments, and whitespace, used templates for INPUT and OUTPUT.)

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.

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.

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".

C++

Text used to encode:The Raven - by E.A.Poe <lang cpp>

  1. include <vector>
  2. include <iostream>
  3. include <fstream>
  4. include <sstream>

typedef struct {

   int s[4];

}userI;

class jit{ public:

   void decode( std::string& file, std::vector<userI>& ui ) {
       std::ifstream f( file.c_str(), std::ios_base::in );
       fileBuffer = std::string( ( std::istreambuf_iterator<char>( f ) ), std::istreambuf_iterator<char>() );
       f.close();
       for( std::vector<userI>::iterator t = ui.begin(); t != ui.end(); t++ ) {
           if( !decode( ( *t ).s ) ) break;
       }
       std::cout << "\n\n";
   }

private:

   bool decode( int* ui ) {
       int l = 0, t = 0, p = 0, c = 0, a = 0;
       for( std::string::iterator i = fileBuffer.begin(); i != fileBuffer.end(); i++ ) {
           if( p == ui[0] && l == ui[1] && t == ui[2] && c == ui[3] ) {
               if( *i == '!' )  return false;
               std::cout << *i; return true;
           }
           if( *i == '\n' )      { l++; t = c = 0; }  
           else if( *i == '\t' ) { t++; c = 0; }
           else if( *i == '\f' ) { p++; l = t = c = 0; }
           else                  { c++;}
       }
       return false;
   }
   std::string fileBuffer;

}; void getUserInput( std::vector<userI>& u ) {

   std::string h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
                   "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
   //std::getline( std::cin, h );
   std::stringstream ss( h );
   userI a;
   int x = 0;
   while( std::getline( ss, h, ' ' ) ) {
       a.s[x] = atoi( h.c_str() );
       if( ++x == 4 ) {
           u.push_back( a );
           x = 0;
       }
   }

} int main( int argc, char* argv[] ) {

   std::vector<userI> ui;
   getUserInput( ui );
   jit j;
   j.decode( std::string( "theRaven.txt" ), ui );
   return 0;

} </lang>

Output:
Silence-Dogood.

D

Translation of: Kotlin

<lang D>import std.algorithm; import std.array; import std.conv; import std.file; import std.range; import std.stdio;

struct UserInput {

   char formFeed;
   char lineFeed;
   char tab;
   char space;
   this(string ff, string lf, string tb, string sp) {
       formFeed = cast(char) ff.to!int;
       lineFeed = cast(char) lf.to!int;
       tab = cast(char) tb.to!int;
       space = cast(char) sp.to!int;
   }

}

auto getUserInput() {

   auto h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
          ~ "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
   auto ctor = (string[] a) => UserInput(a[0], a[1], a[2], a[3]);
   return h.split(' ').chunks(4).map!ctor.array;

}

void decode(string fileName, UserInput[] uiList) {

   auto text = readText(fileName);
   bool decode2(UserInput ui) {
       char f = 0;
       char l = 0;
       char t = 0;
       char s = 0;
       foreach (c; text) {
           if (f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space) {
               if (c == '!') return false;
               write(c);
               return true;
           }
           if (c == '\u000c') {
               f++; l=0; t=0; s=0;
           } else if (c == '\n') {
               l++; t=0; s=0;
           } else if (c == '\t') {
               t++; s=0;
           } else {
               s++;
           }
       }
       return false;
   }
   foreach (ui; uiList) {
       if (!decode2(ui)) break;
   }
   writeln;

}

void main() {

   auto uiList = getUserInput();
   decode("theRaven.txt", uiList);

}</lang>

Output:
Silence-Dogood.

Kotlin

Translation of: C++

<lang scala>// version 1.2.10

import java.io.File

data class UserInput(val formFeed: Int, val lineFeed: Int, val tab: Int, val space: Int)

fun getUserInput(): List<UserInput> {

   val h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
           "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
   return h.split(' ').chunked(4).map {
       val (ff, lf, tb, sp) = it
       UserInput(ff.toInt(), lf.toInt(), tb.toInt(), sp.toInt())
   }

}

fun decode(fileName: String, uiList: List<UserInput>) {

   val text = File(fileName).readText()
   fun decode2(ui: UserInput): Boolean {
       var f = 0
       var l = 0
       var t = 0
       var s = 0
       val (ff, lf, tb, sp) = ui
       for (c in text) {
           if (f == ff && l == lf && t == tb && s == sp) {
               if (c == '!') return false
               print(c)
               return true
           }
           when (c) {
               '\u000c' -> { f++; l = 0; t = 0; s = 0 }
               '\n'     -> { l++; t = 0; s = 0 }
               '\t'     -> { t++; s = 0 }
               else     -> { s++ }
           }
       }
       return false
   }
   for (ui in uiList) {
       if (!decode2(ui)) break
   }
   println()

}

fun main(args: Array<String>) {

   val uiList = getUserInput()
   decode("theRaven.txt", uiList)

}</lang>

Output:
Silence-Dogood.

REXX

The input file used by this REXX program only contains one page;   it has no   FF   (formfeed)   characters in it),
and the injection of   FF   characters into the file would be like putting pencil marks into a holy book.   <lang rexx>/*REXX program extracts characters by using a book cipher from a text file. */ parse arg iFID /*obtain optional name of file (book).*/ if iFID== | iFID=="," then iFID="JIT.TXT" /*Not specified? Then use the default.*/ $= 'abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= '0123456789'$ || _ prompt= '──────────enter four parameters (all positive integers) or QUIT' pag=1; lin=1; FF='c'x /*assume start of page 1, line 1. */ @.= /*read the entire book from the file. */

   do  while  lines(iFID)\==0                   /*process lines from input stream(file)*/
   _=translate( linein(iFID), , '9'x)           /*obtain a single line from input file.*/
   if pos(FF, _)\==0  then do; pag=pag+1; lin=1 /*bump page counter; reset line counter*/
                           end                  /* [↑]  handle finding of FF (formfeed)*/
   @.pag.lin=_                                  /*obtain a single line from input file.*/
   lin=lin+1                                    /*bump the line counter.               */
   end   /*while lines···*/                     /* [↑]  read the entire input stream.  */

?= /*define the phrase to be null (so far)*/

      do ask=0;   bad=1;   say prompt;   pull y /*get just─in─time positional numbers. */
      if y='QUIT'  then exit 0                  /*the user wants out of this loop, exit*/
      y=space( translate(y, $, $ || xrange() )) /*allow any separator the user wants.  */
      parse var  y  a.1  a.2  a.3  a.4          /*parse the pertinent parameters.      */
      if words(y)>4   then do;    say 'too many parameters entered.'
                                  iterate  ask
                           end                  /*go and try again to obtain the parms.*/
        do k=1  for 4                           /*validate  parms  {positive integers}.*/
        if datatype(a.k,'W') & a.k>0  then iterate            /*found a bad parameter. */
        say 'parameter '    k    " is missing or not a positive integer: "    a.k
        iterate  ask                            /*go and ask for another set of parms. */
        a.k=a.k / 1                             /*normalize the user's parm (number).  */
        end   /*k*/                             /* [↑]  done with the validations.     */
      parse value a.1 a.2 a.3 a.4 with p l w c  /*parse parameters for specific names. */
      x=substr( word( @.p.l, w), c, 1)          /*extract a character from the book.   */
      if x=='!'  then leave                     /*if the  stop  char was found,  done. */
      say right(x '◄─── a letter',46)           /*might as well echo char to terminal. */
      ?=? || x                                  /*append the character to the phrase.  */
      end   /*j*/                               /* [↑]  display letters found in book. */

say '═════►' ? /*stick a fork in it, we're all done. */</lang>

input   supplied to the console (terminal) by the user in response to the prompts,   (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
input   (abbridged)
──────────enter four parameters  (all positive integers)   or   QUIT
  1,   133,   4,   5                            ◄■■■■■■■■■ user input (first reponse).     
                               s ◄─── a letter

    ∙
    ∙                                           (some prompts and reponses elided.)  
    ∙

──────────enter four parameters  (all positive integers)   or   QUIT
  1,   571,   4,  12                            ◄■■■■■■■■■ user input (ninth reponse). 
═════► 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>

zkl

Translation of: C++

<lang zkl>class FlyBy{

  fcn decode(file,tuplets){
     codePad:=File(file).read().mode(String); // blob of text
     tuplets.pump(Console.print, _decode.fp1(codePad));
     println();
   }
   fcn [private] _decode(idx,codePad){ // idx is (ff,lf,tab,chr) offset info codePad
      z:=-1;
      foreach n,c in (idx.zip(T("\f","\n","\t"))){
         do(n){ if(Void==(z=codePad.find(c,z+1))) return(Void.Stop); }
      }
      if(z==-1) z=0;  // (0,0,0,n)
      try{ return(codePad[z + idx[-1] + 1]) }catch{ return(Void.Stop) }
   }

}

fcn getUserInput{

  // I don't know a user would enter this but we have
  // a string of 4 item tuplets : (formfeeds, linefeeds, tabs, characters), ...
  // each tuplet is an offset into a code pad (text)
  h:="0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
     "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
  h.split(" ").pump(List,T(Void.Read,3),
     fcn(ff,lf,t,s){ vm.arglist.apply("toInt") });

}</lang> <lang zkl>input:=getUserInput();

  // our code pad is: http://paulo-jorente.de/text/theRaven.txt

FlyBy.decode("theRaven.txt",input);</lang>

Output:
Silence-Dogood.