Just in time processing on a character stream

From Rosetta Code
Revision as of 14:07, 15 May 2019 by SqrtNegInf (talk | contribs) (Added Perl example)
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.

C#

Translation of: D

<lang csharp>using System; using System.Collections.Generic; using System.Linq;

namespace JustInTimeProcessing {

   struct UserInput {
       public UserInput(string ff, string lf, string tb, string sp) {
           FormFeed = (char)int.Parse(ff);
           LineFeed = (char)int.Parse(lf);
           Tab = (char)int.Parse(tb);
           Space = (char)int.Parse(sp);
       }
       public char FormFeed { get; }
       public char LineFeed { get; }
       public char Tab { get; }
       public char Space { get; }
   }
   class Program {
       static List<UserInput> GetUserInput() {
           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";
           return h.Split(' ')
               .Select((x, idx) => new { x, idx })
               .GroupBy(x => x.idx / 4)
               //.Select(g => g.Select(a => a.x))
               .Select(g => {
                   var ge = g.Select(a => a.x).ToArray();
                   return new UserInput(ge[0], ge[1], ge[2], ge[3]);
               })
               .ToList();
       }
       static void Decode(string filename, List<UserInput> uiList) {
           string text = System.IO.File.ReadAllText(filename);
           bool Decode2(UserInput ui) {
               char f = (char)0;
               char l = (char)0;
               char t = (char)0;
               char s = (char)0;
               foreach (char c in text) {
                   if (f == ui.FormFeed && l == ui.LineFeed && t == ui.Tab && s == ui.Space) {
                       if (c == '!') return false;
                       Console.Write(c);
                       return true;
                   }
                   if (c == '\u000c') {
                       f++; l = (char)0; t = (char)0; s = (char)0;
                   } else if (c == '\n') {
                       l++; t = (char)0; s = (char)0;
                   } else if (c == '\t') {
                       t++; s = (char)0;
                   } else {
                       s++;
                   }
               }
               return false;
           }
           foreach (UserInput ui in uiList) {
               if (!Decode2(ui)) {
                   break;
               }
           }
           Console.WriteLine();
       }
       static void Main(string[] args) {
           var uiList = GetUserInput();
           Decode("theraven.txt", uiList);
           Console.ReadLine();
       }
   }

}</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.

Go

Translation of: C++

<lang go>package main

import (

   "fmt"
   "io/ioutil"
   "log"
   "strconv"
   "strings"

)

type userInput struct{ formFeed, lineFeed, tab, space int }

func getUserInput() []userInput {

   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"
   flds := strings.Fields(h)
   var uis []userInput
   var uif [4]int
   for i := 0; i < len(flds); i += 4 {
       for j := 0; j < 4; j++ {
           uif[j], _ = strconv.Atoi(flds[i+j])
       }
       uis = append(uis, userInput{uif[0], uif[1], uif[2], uif[3]})
   }
   return uis

}

func decode(fileName string, uis []userInput) error {

   text, err := ioutil.ReadFile(fileName)
   if err != nil {
       return err
   }
   decode2 := func(ui userInput) bool {
       var f, l, t, s int
       for _, c := range text {
           if f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space {
               if c == '!' {
                   return false
               }
               fmt.Printf("%c", c)
               return true
           }
           switch c {
           case '\f':
               f++
               l = 0
               t = 0
               s = 0
           case '\n':
               l++
               t = 0
               s = 0
           case '\t':
               t++
               s = 0
           default:
               s++
           }
       }
       return true
   }
   for _, ui := range uis {
       if !decode2(ui) {
           break
       }
   }
   fmt.Println()
   return nil

}

func main() {

   uis := getUserInput()
   err := decode("theRaven.txt", uis)
   if err != nil {
       log.Fatal(err)
   }

}</lang>

Output:
Silence-Dogood.

Java

Translation of: Kotlin

<lang java>import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate;

public class Processing {

   private static class UserInput {
       private char formFeed;
       private char lineFeed;
       private char tab;
       private char space;
       private UserInput(char formFeed, char lineFeed, char tab, char space) {
           this.formFeed = formFeed;
           this.lineFeed = lineFeed;
           this.tab = tab;
           this.space = space;
       }
       char getFormFeed() {
           return formFeed;
       }
       char getLineFeed() {
           return lineFeed;
       }
       char getTab() {
           return tab;
       }
       char getSpace() {
           return space;
       }
   }
   private static List<UserInput> getUserInput() {
       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";
       String[] s = h.split(" ");
       List<UserInput> uiList = new ArrayList<>();
       for (int idx = 0; idx + 3 < s.length; idx += 4) {
           char c0 = (char) Integer.parseInt(s[idx + 0]);
           char c1 = (char) Integer.parseInt(s[idx + 1]);
           char c2 = (char) Integer.parseInt(s[idx + 2]);
           char c3 = (char) Integer.parseInt(s[idx + 3]);
           UserInput userInput = new UserInput(c0, c1, c2, c3);
           uiList.add(userInput);
       }
       return uiList;
   }
   private static void decode(String fileName, List<UserInput> uiList) throws IOException {
       Path path = Paths.get(fileName);
       byte[] bytes = Files.readAllBytes(path);
       String text = new String(bytes, StandardCharsets.UTF_8);
       Predicate<UserInput> decode2 = (UserInput ui) -> {
           char f = 0;
           char l = 0;
           char t = 0;
           char s = 0;
           char ff = ui.getFormFeed();
           char lf = ui.getLineFeed();
           char tb = ui.getTab();
           char sp = ui.getSpace();
           for (char c : text.toCharArray()) {
               if (f == ff && l == lf && t == tb && s == sp) {
                   if (c == '!') {
                       return false;
                   }
                   System.out.print(c);
                   return true;
               }
               switch (c) {
                   case '\u000c':
                       f++;
                       l = 0;
                       t = 0;
                       s = 0;
                       break;
                   case '\n':
                       l++;
                       t = 0;
                       s = 0;
                       break;
                   case '\t':
                       t++;
                       s = 0;
                       break;
                   default:
                       s++;
                       break;
               }
           }
           return false;
       };
       for (UserInput ui : uiList) {
           if (!decode2.test(ui)) {
               break;
           }
       }
       System.out.println();
   }
   public static void main(String[] args) throws IOException {
       List<UserInput> 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.

Perl

Translation of: Perl 6
Library: ntheory

<lang perl>use strict; use warnings; use feature 'say'; use feature 'state';

use ntheory qw/fromdigits todigitstring/;

my $key = 'perl5'; srand fromdigits($key,36) % 2**63;

my @stream;

sub stream {

   my($i) = shift;
   state @chars;
   push @chars, chr($_) for 14..127;
   $stream[$i] = $chars[rand 1+127-14] unless $stream[$i];

}

sub jit_encode {

   my($str) = shift;
   my $i = 0;
   my $last = 0;
   my $enc = ;
   for my $c (split , $str) {
       my $h;
       my $l = ;
       ++$i until $c eq stream($i);
       my $o = $i - $last;
       $l    = $o % 26;
       $h    = $o - $l if $o > 26;
       $l   += 10;
       $enc .= ($h ? uc todigitstring($h,36) : ) . lc todigitstring($l,36);
       $last = $i;
   }
   $enc

}

sub jit_decode {

   my($str) = shift;
   my @matches = $str =~ /((.*?) ([a-z]))/gx;
   my $dec = ;
   my $i = 0;
   for my $j (0 .. @matches/3 - 1) {
       my $o = ( fromdigits($matches[3*$j+1],36) - 10 // 0) +
               ( fromdigits($matches[3*$j+2],36)      // 0);
       $i   += $o;
       $dec .= $stream[$i];
   }
   $dec

}

my $enc = jit_encode('The slithey toves did gyre and gimble in the wabe'); say my $result = "Encoded\n$enc\n\nDecoded\n" . jit_decode($enc);</lang>

Output:
Encoded
bQh52yf9Ex2Wi4Cv1GcyoAUcBKbke3Mo5Ss2WybQlvQs1GviQc1GnQg5Sv26j1Gm26m3Mp26iQz78lQx2Wel1Gcs52y5Sds3Me26l52au1Gwe1Gl

Decoded
The slithey toves did gyre and gimble in the wabe

Perl 6

Works with: Rakudo version 2019.03

This is a somewhat fragile toy encoder / decoder and shouldn't be used for anything serious.

<lang perl6>#`[ Set srand to set the encode / decode "key", and generate a lazy, reproducible stream of "random" characters. Need to use the same key and same implementation of Perl 6 to encode / decode. Gain "security" by exchanging keys by a second channel. Default key is 'Perl 6' ]

unit sub MAIN ($key = 'Perl 6');

srand $key.comb(/<.alnum>/).join.parse-base(36) % 2**63;

  1. random but reproducible infinite stream of characters

my @stream = (flat ' ' .. '~').roll(*);

sub jit-encode (Str $str) {

   my $i = 0;
   my $last = 0;
   my $enc = ;
   for $str.comb -> $c {
       my $h;
       my $l = ;
       ++$i until $c eq @stream[$i];
       my $o = $i - $last;
       $l    = $o % 26;
       $h    = $o - $l if $o > 26;
       $l   += 10;
       $enc ~= ($h ?? $h.base(36).uc !! ) ~ ($l.base(36).lc);
       $last = $i;
   }
   $enc

}

sub jit-decode (Str $str) {

   $str ~~ m:g/((.*?) (<:Ll>))/;
   my $dec = ;
   my $i = 0;
   for $/.List -> $l {
       my $o = ($l[0][1].Str.parse-base(36) - 10 // 0) +
               ($l[0][0].Str.parse-base(36) // 0);
       $i += $o;
       $dec ~= @stream[$i];
   }
   $dec

}

my $enc = jit-encode('In my opinion, this task is pretty silly.');

say "Encoded\n$enc\n\nDecoded\n", jit-decode($enc);</lang>

Encoded
26j52dhl2Wp1Gw2WceQj1Go3MyQc1Gd52a1Gb1Ga2Wcq26o4Cwf3MiQsQn2Wglk3MhkQyeQjas3MkQn2Wd26aaQcQj

Decoded
In my opinion, this task is pretty silly.

Python

Translation of: D

<lang python>import sys

class UserInput:

   def __init__(self,chunk):
       self.formFeed = int(chunk[0])
       self.lineFeed = int(chunk[1])
       self.tab = int(chunk[2])
       self.space = int(chunk[3])
   def __str__(self):
       return "(ff=%d; lf=%d; tb=%d; sp%d)" % (self.formFeed,self.lineFeed,self.tab,self.space)

def chunks(l,n):

   for i in xrange(0, len(l), n):
       yield l[i:i+n]

def getUserInput():

   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"
   ha = h.split()
   return [UserInput(chunk) for chunk in chunks(ha, 4)]

def decode(filename,uiList):

   f = open(filename, "r")
   text = f.read()
   def decode2(ui):
       f = 0
       l = 0
       t = 0
       s = 0
       for c in text:
           if f == ui.formFeed and l == ui.lineFeed and t == ui.tab and s == ui.space:
               if c == '!':
                   return False
               sys.stdout.write(c)
               return True
           if c == '\u000c':
               f=f+1
               l=0
               t=0
               s=0
           elif c == '\n':
               l=l+1
               t=0
               s=0
           elif c == '\t':
               t=t+1
               s=0
           else:
               s=s+1
       return False
   for ui in uiList:
       if not decode2(ui):
           break
   print
          1. Main #####

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 (that is 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"$ || _; $$=$ || xrange() prompt= '────────── enter four 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*/                              /* [↑]  read the entire input stream.  */

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

      do ask=0;       say prompt;       pull y  /*get just─in─time positional numbers. */
      if abbrev('QUIT', y, 1)  then exit 0      /*the user wants out of here, so exit. */
      y=space( translate(y, $, $$) )            /*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;  is#= datatype(a.k, 'W') /*validate  parms  {positive integers}.*/
        if is#  then a.k= a.k / 1               /*normalize the number (for indexing). */
        if is#  &  a.k>0  then iterate          /*found a good parameter?   Then skip. */
        say 'parameter '      k      " is missing or not a positive integer: "      a.k
        iterate  ask                            /*go and ask for another set of parms. */
        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.