Just in time processing on a character stream: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added D)
(→‎{{header|REXX}}: added/deleted/changed statements, comments, and whitespace, used templates for INPUT and OUTPUT.)
Line 210: Line 210:


=={{header|REXX}}==
=={{header|REXX}}==
The input file used by this REXX program only contains one page (it has no ''FF'' or ''formfeed'' characters in it),
The input file used by this REXX program only contains one page;   it has no   ''FF''   (''formfeed'')   characters in it),
<br>and the injection of ''FF'' characters into the file would be like putting pencil marks into a holy book.
<br>and the injection of &nbsp; ''FF'' &nbsp; characters into the file would be like putting pencil marks into a holy book. &nbsp; <big><big><big> ☺ </big></big></big>
<lang rexx>/*REXX pgm extracts characters by using a book cipher from a text file. */
<lang rexx>/*REXX program extracts characters by using a book cipher from a text file. */
parse arg iFID /*optional name of file (book). */
parse arg iFID /*obtain optional name of file (book).*/
if iFID=='' then iFID="JIT.TXT" /*Not specified? Then use default*/
if iFID=='' | iFID=="," then iFID="JIT.TXT" /*Not specified? Then use the default.*/
$= 'abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= '0123456789'$ || _
errTxt= ' is missing or not a positive integer: ' /*error text string.*/
prompt= '──────────enter four parameters (all positive integers) or QUIT'
$='abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= '0123456789'$ || _
pag=1; lin=1; FF='c'x /*assume start of page 1, line 1. */
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 the file. */
/*read the entire book from file.*/
do while lines(iFID)\==0 /*process lines from input stream(file)*/
do while lines(iFID)\==0 /*process lines from input stream*/
_=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*/
_=translate(linein(iFID),,'9'x) /*obtain a single line from input*/
end /* [↑] handle finding of FF (formfeed)*/
if pos('c'x,_)\==0 then do /*was a ff (form-feed) detected? */
pag=pag+1 /*bump page counter for next page*/
@.pag.lin=_ /*obtain a single line from input file.*/
lin=1 /*reset the line counter to one. */
lin=lin+1 /*bump the line counter. */
end /* [↑] handle finding of formfeed*/
end /*while lines···*/ /* [↑] read the entire input stream. */
@.pag.lin=_ /*obtain a single line from input*/
?= /*define the phrase to be null (so far)*/
lin=lin+1 /*bump the line counter. */
do ask=0; bad=1; say prompt; pull y /*get just─in─time positional numbers. */
end /*while lines···*/ /* [↑] read entire input stream.*/
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. */
?= /*define the phrase to be null.*/
do prompt=0; bad=1 /*get J.I.T. positional numbers. */
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.'
say ask; pull y /*obtain the numbers from console*/
if y='QUIT' then exit 0 /*the user wants out of this loop*/
iterate ask
y=space(translate(y,$,$||xrange())) /*allow any sep user wants.*/
end /*go and try again to obtain the parms.*/
parse var y a.1 a.2 a.3 a.4 /*parse the pertinent parameters.*/
do k=1 for 4 /*validate parms {positive integers}.*/
if a.1=='QUIT' then exit 0 /*the user wants out of this loop*/
if datatype(a.k,'W') & a.k>0 then iterate /*found a bad parameter. */
if words(y)>4 then do /*did the user have fingeritis ? */
say 'parameter ' k " is missing or not a positive integer: " a.k
say 'too many parameters entered.'
iterate ask /*go and ask for another set of parms. */
iterate prompt
a.k=a.k / 1 /*normalize the user's parm (number). */
end /*go and try again to get parms. */
end /*k*/ /* [↑] done with the validations. */
do k=1 for 4 /*validate parms {positive ints}.*/
parse value a.1 a.2 a.3 a.4 with p l w c /*parse parameters for specific names. */
if datatype(a.k,'W') & a.k>0 then iterate /*found a bad parm.*/
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 'parameter ' k errTxt a.k /*issue an error message to term.*/
iterate prompt /*go & ask for another set of #s.*/
say right(x '◄─── a letter',46) /*might as well echo char to terminal. */
a.k=a.k/1 /*normalize the user's number. */
?=? || x /*append the character to the phrase. */
end /*k*/ /* [↑] done with the validations*/
end /*j*/ /* [↑] display letters found in book. */
parse var y p l w c /*parse parameters for names. */
say '═════►' ? /*stick a fork in it, we're all done. */</lang>
{{out|input|text=&nbsp; supplied to the console (terminal) by the user in response to the prompts, &nbsp; (the commas are optional):}}
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''' &nbsp; supplied to the console (terminal) by the user &nbsp; (the commas are optional):
<pre>
<pre>
1, 133, 4, 5
1, 133, 4, 5
Line 266: Line 259:
1, 571, 4, 12
1, 571, 4, 12
</pre>
</pre>
'''output''' &nbsp; (abbridged)
{{out|input|text=&nbsp; (abbridged)}}
<pre>
<pre>
──────────enter four parameters (all positive integers) or QUIT
──────────enter four parameters (all positive integers) or QUIT
1, 133, 4, 5 ◄■■■■■■■■■ user input (first reponse).
1, 133, 4, 5
s ◄─── a letter
s ◄─── a letter
──────────enter four parameters (all positive integers) or QUIT


·
∙ (some prompts and reponses elided.)
·
·


──────────enter four parameters (all positive integers) or QUIT
1, 571, 4, 12 ◄■■■■■■■■■ user input (ninth reponse).
═════► so─true.
═════► so─true.
</pre>
</pre>

Revision as of 23:07, 13 January 2018

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

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.