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:
 
=={{header|REXX}}==
The input file used by this REXX program only contains one page;   (it has no   ''FF'' or  (''formfeed'')   characters in it),
<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 pgmprogram 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'$ || _
errTxt= ' is missing or not a positive integer: ' /*error text string.*/
askprompt= '──────────enter four parameters (all positive integers) or QUIT'
$='abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= '0123456789'$ || _
?pag=1; lin=1; FF='c'x /*assume start of page 1, /*defineline the1. phrase to be null.*/
ask='──────────enter four parameters (all positive integers) or QUIT'
pag@.=1; lin=1; @.= /*assumeread startthe ofentire pagebook 1,from linethe 1file. */
do while lines(iFID)\==0 /*readprocess thelines entirefrom book frominput stream(file.)*/
do while_=translate( lineslinein(iFID)\==0, , '9'x) /*processobtain a single linesline from input streamfile.*/
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 /*stick a[↑] fork inhandle it,finding we'reof done.FF (formfeed)*/</lang>
if pos('c'x,_)\==0 then do /*was a ff (form-feed) detected? */
@.pag.lin=_ pag=pag+1 /*bumpobtain a pagesingle counterline forfrom nextinput pagefile.*/
lin=lin+1 lin=1 /*resetbump the line counter. to one. */
end /*while lines···*/ end /* [↑] handle findingread the entire input stream. of formfeed*/
?= @.pag.lin=_ /*obtaindefine the phrase ato singlebe linenull from(so inputfar)*/
lin=lin+1 do ask=0; bad=1; say prompt; pull y /*bumpget thejust─in─time linepositional counternumbers. */
end /*whileif y='QUIT' then exit 0 lines···*/ /*the user [↑]wants out readof entirethis inputloop, stream.exit*/
y=space( translate(y, $, $ || xrange() )) /*allow any separator the user wants. */
?= /*define the phrase to be null.*/
doparse prompt=0;var bad= y a.1 a.2 a.3 a.4 /*getparse J.I.T.the positionalpertinent numbersparameters. */
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())) end /*allowgo and try again anyto sepobtain userthe wantsparms.*/
parse var do y a.k=1 a.2 a.3for a.4 /*parsevalidate parms the pertinent{positive parametersintegers}.*/
if datatype(a.1==k,'QUITW') & a.k>0 then exititerate 0 /*the user wants out of this loop/*found a bad parameter. */
if words(y)>4 say 'parameter then' do k " is /*didmissing theor usernot havea fingeritispositive ?integer: */" a.k
iterate ask say 'too many parameters entered /*go and ask for another set of parms.' */
a.k=a.k / 1 iterate prompt /*normalize the user's parm (number). */
end /*k*/ end /*go and[↑] try againdone towith getthe parmsvalidations. */
parse value do k=a.1 a.2 fora.3 a.4 with p l w c /*validateparse parmsparameters {positivefor ints}specific names. */
x=substr( if datatypeword(a @.kp.l,'W' w), c, 1) & a.k>0 then iterate /*foundextract a badcharacter parmfrom 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.*/
say right(x iterate prompt '◄─── a letter',46) /*gomight &as askwell forecho anotherchar setto ofterminal. #s.*/
?=? || x a.k=a.k/1 /*normalizeappend the user'scharacter number.to the phrase. */
end /*kj*/ /* [↑] donedisplay letters found within thebook. validations*/
say '═════►' ? parse var y p l w c /*parsestick parametersa forfork names.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>
1, 133, 4, 5
Line 266 ⟶ 259:
1, 571, 4, 12
</pre>
'''output''' {{out|input|text=&nbsp; (abbridged)}}
<pre>
──────────enter four parameters (all positive integers) or QUIT
1, 133, 4, 5 ◄■■■■■■■■■ user input (first reponse).
1, 133, 4, 5
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.
</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.