Odd word problem: Difference between revisions

From Rosetta Code
Content added Content deleted
m (added whitespace before the TOC (table of contents), added other whitespace to the task's preamble.)
Line 1: Line 1:
{{task}}
{{task}}

;Task:
Write a program that solves the [http://c2.com/cgi/wiki?OddWordProblem odd word problem] with the restrictions given below.
Write a program that solves the [http://c2.com/cgi/wiki?OddWordProblem odd word problem] with the restrictions given below.



'''Description''': You are promised an input stream consisting of English letters and punctuations. It is guaranteed that
'''Description''': You are promised an input stream consisting of English letters and punctuations. It is guaranteed that
Line 7: Line 10:
* the words will be at least one letter long; and that
* the words will be at least one letter long; and that
* a full stop (.) appears after, and only after, the last word.
* a full stop (.) appears after, and only after, the last word.



For example, <code>what,is,the;meaning,of:life.</code> is such a stream with six words. Your task is to reverse the letters in every other word while leaving punctuations intact, producing e.g. "what,si,the;gninaem,of:efil.", while observing the following restrictions:
For example, <code>what,is,the;meaning,of:life.</code> is such a stream with six words. Your task is to reverse the letters in every other word while leaving punctuations intact, producing e.g. "what,si,the;gninaem,of:efil.", while observing the following restrictions:
Line 12: Line 16:
# You '''are not''' to explicitly save characters in a collection data structure, such as arrays, strings, hash tables, etc, for later reversal;
# You '''are not''' to explicitly save characters in a collection data structure, such as arrays, strings, hash tables, etc, for later reversal;
# You '''are''' allowed to use recursions, closures, continuations, threads, coroutines, etc., even if their use implies the storage of multiple characters.
# You '''are''' allowed to use recursions, closures, continuations, threads, coroutines, etc., even if their use implies the storage of multiple characters.



'''Test case''': work on both the "life" example given above, and the text <code>we,are;not,in,kansas;any,more.</code>
'''Test case''': work on both the "life" example given above, and the text <code>we,are;not,in,kansas;any,more.</code>
<br><br>


=={{header|Ada}}==
=={{header|Ada}}==

Revision as of 03:33, 27 May 2016

Task
Odd word problem
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Write a program that solves the odd word problem with the restrictions given below.


Description: You are promised an input stream consisting of English letters and punctuations. It is guaranteed that

  • the words (sequence of consecutive letters) are delimited by one and only one punctuation; that
  • the stream will begin with a word; that
  • the words will be at least one letter long; and that
  • a full stop (.) appears after, and only after, the last word.


For example, what,is,the;meaning,of:life. is such a stream with six words. Your task is to reverse the letters in every other word while leaving punctuations intact, producing e.g. "what,si,the;gninaem,of:efil.", while observing the following restrictions:

  1. Only I/O allowed is reading or writing one character at a time, which means: no reading in a string, no peeking ahead, no pushing characters back into the stream, and no storing characters in a global variable for later use;
  2. You are not to explicitly save characters in a collection data structure, such as arrays, strings, hash tables, etc, for later reversal;
  3. You are allowed to use recursions, closures, continuations, threads, coroutines, etc., even if their use implies the storage of multiple characters.


Test case: work on both the "life" example given above, and the text we,are;not,in,kansas;any,more.

Ada

This is a rather straightforward approach, using recursion.

<lang Ada>with Ada.Text_IO;

procedure Odd_Word_Problem is

  use Ada.Text_IO; -- Get, Put, and Look_Ahead

  function Current return Character is
     -- reads the current input character, without consuming it
     End_Of_Line: Boolean;
     C: Character;
  begin
     Look_Ahead(C, End_Of_Line);
     if End_Of_Line then
        raise Constraint_Error with "end of line before the terminating '.'";
     end if;
     return C;
  end Current;

  procedure Skip is
     -- consumes the current input character
     C: Character;
  begin
     Get(C);
  end Skip;

  function Is_Alpha(Ch: Character) return Boolean is
  begin
     return (Ch in  'a' .. 'z') or (Ch in 'A' .. 'Z');
  end Is_Alpha;

  procedure Odd_Word(C: Character) is
  begin
     if Is_Alpha(C) then
        Skip;
        Odd_Word(Current);
        Put(C);
     end if;
  end Odd_Word;

begin -- Odd_Word_Problem

  Put(Current);
  while Is_Alpha(Current) loop -- read an even word
     Skip;
     Put(Current);
  end loop;
  if Current /= '.' then -- read an odd word
     Skip;
     Odd_Word(Current);
     Put(Current);
     if Current /= '.' then -- read the remaining words
        Skip;
        Odd_Word_Problem;
     end if;
  end if;

end Odd_Word_Problem;</lang>

Output:

> ./odd_word_problem 
what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.
> ./odd_word_problem 
we,are;not,in,kansas;any,more.
we,era;not,ni,kansas;yna,more.

ALGOL 68

Works with: ALGOL 68G version Any - tested with release 2.8.win32

The words and punctuation should be on a single line. Uses recursion. <lang algol68># recursively reverses the current word in the input and returns the #

  1. the character that followed it #
  2. "ch" should contain the first letter of the word on entry and will be #
  3. updated to the punctuation following the word on exit #

PROC reverse word = ( REF CHAR ch )VOID: BEGIN

   CHAR    next ch;
   read( ( next ch ) );
   IF ( next ch <= "Z" AND next ch >= "A" )
   OR ( next ch <= "z" AND next ch >= "a" )
   THEN
       reverse word( next ch )
   FI;
   print( ( ch ) );
   ch := next ch

END; # reverse word #


  1. recursively prints the current word in the input and returns the #
  2. character that followed it #
  3. "ch" should contain the first letter of the word on entry and will be #
  4. updated to the punctuation following the word on exit #

PROC normal word = ( REF CHAR ch )VOID: BEGIN

   print( ( ch ) );
   read ( ( ch ) );
   IF ( ch <= "Z" AND ch >= "A" )
   OR ( ch <= "z" AND ch >= "a" )
   THEN
       normal word( ch )
   FI

END; # normal word #


  1. read and print words and punctuation from the input stream, reversing #
  2. every second word #

PROC reverse every other word = VOID: BEGIN

   CHAR ch;
   read( ( ch ) );
   WHILE
       ch /= "."
   DO
       normal word( ch );
       IF ch /= "."
       THEN
           print( ( ch ) );
           read ( ( ch ) );
           reverse word( ch )
       FI
   OD;
   print( ( ch ) )

END; # reverse every other word #


main: (

   reverse every other word

)</lang>

Output:
what,si,the;gninaem,of:efil.
we,era;not,ni,kansas;yna,more.

AutoHotkey

<lang AutoHotkey>str := "what,is,the;meaning,of:life." loop, parse, str if (A_LoopField ~= "punct:") res .= A_LoopField, toggle:=!toggle else res := toggle ? RegExReplace(res, ".*punct:\K", A_LoopField ) : res A_LoopField MsgBox % res</lang>

Outputs:

what,si,the;gninaem,of:efil.

Bracmat

<lang bracmat>( ( odd-word

 =   dothis doother forward backward
   .   ( forward
       =   ch
         .   fil$:?ch
           & put$!ch
           & ( low$!ch:~<a:~>z&forward$
             | !ch:~"."
             )
       )
     & ( backward
       =   ch
         .   fil$:?ch
           & (   low$!ch:~<a:~>z
               & backward$() (put$!ch&)    { This reduces to the return value of backwards$()}
             | '(.put$($ch)&$ch:~".")      { Macro, evaluates to a function with actual ch.  }
             )
       )
     & fil$(!arg,r)
     &   ((=forward$).(=(backward$)$))
       : (?dothis.?doother)
     &   whl
       ' ( !(dothis.)
         & (!doother.!dothis):(?dothis.?doother)
         )
     & (fil$(,SET,-1)|)                 { This is how a file is closed: seek the impossible. }
 )

& put$("what,is,the;meaning,of:life.","life.txt",NEW) & put$("we,are;not,in,kansas;any,more.","kansas.txt",NEW) & odd-word$"life.txt" & put$\n & odd-word$"kansas.txt" { Real file, as Bracmat cannot read a single character from stdin. } );</lang> Output:

what,si,the;gninaem,of:efil.
we,era;not,ni,kansas;yna,more.

C

Using GCC nested function as closures. This can only be passed up the stack, not the other way around. It's also doable with makecontext, and may be possible with setjmp.

<lang c>#include <stdio.h>

  1. include <ctype.h>

int do_char(int odd, void (*f)(void)) { int c = getchar();

void write_out(void) { putchar(c); if (f) f(); }

if (!odd) putchar(c);

if (isalpha(c)) return do_char(odd, write_out);

if (odd) { if (f) f(); putchar(c); }

return c != '.'; }

int main() { int i = 1; while (do_char(i = !i, 0));

return 0; }</lang>

C++

Translation of: Python
Works with: C++11
Works with: gcc version 4.5

Tested with gcc 4.5, with "-std=c++0x" option.

<lang cpp>#include <iostream>

  1. include <cctype>
  2. include <functional>

using namespace std;

bool odd() {

 function<void ()> prev = []{};
 while(true) {
   int c = cin.get();
   if (!isalpha(c)) {
     prev();
     cout.put(c);
     return c != '.';
   }
   prev = [=] { cout.put(c); prev();  };
 }

}

bool even() {

 while(true) {
   int c;
   cout.put(c = cin.get());
   if (!isalpha(c)) return c != '.';
 }

}


int main() {

 bool e = false;
 while( e ? odd() : even() ) e = !e;
 return 0;

}</lang>

Clojure

Translation of: Common Lisp

<lang Clojure>(defn next-char []

 (char (.read *in*)))

(defn forward []

 (let [ch (next-char)]
   (print ch)
   (if (Character/isLetter ch)
     (forward)
     (not= ch \.))))

(defn backward []

 (let [ch (next-char)]
   (if (Character/isLetter ch)
     (let [result (backward)]
       (print ch)
       result)
     (fn [] (print ch) (not= ch \.)))) )

(defn odd-word [s]

 (with-in-str s
   (loop [forward? true]
     (when (if forward?
             (forward)
             ((backward)))
       (recur (not forward?)))) )
   (println))</lang>

Examples:

<lang clojure>user=> (odd-word "what,is,the;meaning,of:life.") what,si,the;gninaem,of:efil. nil user=> (odd-word "we,are;not,in,kansas;any,more.") we,era;not,ni,kansas;yna,more. nil</lang>

CoffeeScript

<lang CoffeeScript>isWordChar = (c) -> /^\w/.test c isLastChar = (c) -> c is '.'

  1. Pass a function that returns an input character and one that outputs a
  2. character. JS platforms' ideas of single-character I/O vary widely, but this
  3. abstraction is adaptable to most or all.

oddWord = (get, put) -> forwardWord = -> loop # No magic here; buffer then immediately output. c = get() put(c) unless isWordChar(c) return not isLastChar(c)

# NB: (->) is a CoffeeScript idiom for no-op. reverseWord = (outputPending = (->)) -> c = get() if isWordChar(c) # Continue word. # Tell recursive call to output this character, then any previously # pending characters, after the next word character, if any, has # been output. reverseWord -> put(c) outputPending() else # Word is done. # Output previously pending characters, then this punctuation. outputPending() put(c) return not isLastChar(c)

# Alternate between forward and reverse until one or the other reports that # the end-of-input mark has been reached (causing a return of false). continue while forwardWord() and reverseWord()</lang>

Same without comments

<lang CoffeeScript>isWordChar = (c) -> /^\w/.test c isLastChar = (c) -> c is '.'

oddWord = (get, put) -> forwardWord = -> loop c = get() put(c) unless isWordChar(c) return not isLastChar(c)

reverseWord = (outputPending = (->)) -> c = get() if isWordChar(c) reverseWord -> put(c) outputPending() else outputPending() put(c) return not isLastChar(c)

continue while forwardWord() and reverseWord()</lang>

Testing code

<lang CoffeeScript># Redefine as necessary for target platform. println = (z) -> console.log z

testData = [ [ "what,is,the;meaning,of:life." "what,si,the;gninaem,of:efil." ] [ "we,are;not,in,kansas;any,more." "we,era;not,ni,kansas;yna,more." ] ]

results = for [testString, expectedResult] in testData # This test machinery uses string buffers for input and output. If your JS # platform sports single-character I/O, by all means, adapt to taste. getCursor = 0 putBuffer = "" get = -> testString.charAt getCursor++ put = (c) -> putBuffer += c oddWord(get,put) [testString, expectedResult, putBuffer, putBuffer is expectedResult]

println result for result in results</lang>

Output in node.js:

[ 'what,is,the;meaning,of:life.',
  'what,si,the;gninaem,of:efil.',
  'what,si,the;gninaem,of:efil.',
  true ]
[ 'we,are;not,in,kansas;any,more.',
  'we,era;not,ni,kansas;yna,more.',
  'we,era;not,ni,kansas;yna,more.',
  true ]

Common Lisp

Even words are straightforward. For odd words, the final punctuation is printed by a closure passed back up the caller chain. <lang lisp>(defun odd-word (s)

 (let ((stream (make-string-input-stream s)))
   (loop for forwardp = t then (not forwardp)
         while (if forwardp
                   (forward stream)
                   (funcall (backward stream)))) ))

(defun forward (stream)

 (let ((ch (read-char stream)))
   (write-char ch)
   (if (alpha-char-p ch)

(forward stream)

       (char/= ch #\.))))

(defun backward (stream)

 (let ((ch (read-char stream)))
   (if (alpha-char-p ch)
       (prog1 (backward stream) (write-char ch))
       #'(lambda () (write-char ch) (char/= ch #\.)))) )

</lang>

Examples:

<lang lisp>? (odd-word "what,is,the;meaning,of:life.") what,si,the;gninaem,of:efil. NIL ? (odd-word "we,are;not,in,kansas;any,more.") we,era;not,ni,kansas;yna,more. NIL</lang>

D

Translation of: C

<lang d>bool doChar(in bool odd, in void delegate() nothrow f=null) nothrow {

   import core.stdc.stdio, std.ascii;
   immutable int c = getchar;
   if (!odd)
       c.putchar;
   if (c.isAlpha)
       return doChar(odd, { c.putchar; if (f) f(); });
   if (odd) {
       if (f) f();
       c.putchar;
   }
   return c != '.';

}

void main() {

   bool i = true;
   while (doChar(i = !i)) {}

}</lang>

Output:
what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.

EchoLisp

No character input stream in EchoLisp, which runs in a browser window. We simultate it with a character stream, with the only function read-char, as specified in the task. <lang scheme> (lib 'sequences) (define input-stream null) (define output-stream "")

---------------------------
character I/O simulation
--------------------------

(define (read-char) (next input-stream)) ;; #f if EOF (define (write-char c) (when c (set! output-stream (string-append output-stream c))))

(define (init-streams sentence) (set! input-stream (procrastinator sentence)) (set! output-stream ""))

---------------------------------
task , using read-char/write-char
----------------------------------

(define (flop) ; reverses, and returns first non-alpha after word, or EOF (define c (read-char)) (if (string-alphabetic? c) (begin0 (flop) (write-char c)) c))

(define (flip)

   (define c (read-char))
   (if (string-alphabetic? c) (begin (write-char c)  (flip)) c))
   

(define (task sentence) (init-streams sentence) (while (and (write-char (flip)) (write-char (flop)))) output-stream )


</lang>

Output:

<lang scheme> (task "what,is,the;meaning,of:life.")

   → "what,si,the;gninaem,of:efil."
check diacritical

(task "Longtemps,je me suis couché,héhé,hôhô,de bonne heure.")

   → "Longtemps,ej me sius couché,éhéh,hôhô,ed bonne erueh."

</lang>

Elixir

Translation of: Erlang

<lang elixir>defmodule Odd_word do

 def handle(s, false, i, o) when ((s >= "a" and s <= "z") or (s >= "A" and s <= "Z")) do
   o.(s)
   handle(i.(), false, i, o)
 end
 def handle(s, t, i, o) when ((s >= "a" and s <= "z") or (s >= "A" and s <= "Z")) do
   d = handle(i.(), :rec, i, o)
   o.(s)
   if t == true, do: handle(d, t, i, o), else: d
 end
 def handle(s, :rec, _, _), do: s
 def handle(?., _, _, o), do: o.(?.); :done 
 def handle(:eof, _, _, _), do: :done
 def handle(s, t, i, o) do
   o.(s)
   handle(i.(), not t, i, o)
 end
 
 def main do
   i = fn() -> IO.getn("") end
   o = fn(s) -> IO.write(s) end
   handle(i.(), false, i, o)
 end

end

Odd_word.main</lang>

Output:
C:\Elixir>elixir Odd_word.exs
we,are;not,in,kansas;any,more.
we,era;not,ni,kansas;yna,more.

Erlang

<lang erlang> handle(S, false, I, O) when (((S >= $a) and (S =< $z)) or ((S >= $A) and (S =< $Z))) ->

   O(S),
   handle(I(), false, I, O);

handle(S, T, I, O) when (((S >= $a) and (S =< $z)) or ((S >= $A) and (S =< $Z))) ->

   D = handle(I(), rec, I, O),
   O(S),
   case T of true -> handle(D, T, I, O); _ -> D end;

handle(S, rec, _, _) -> S; handle($., _, _, O) -> O($.), done; handle(eof, _, _, _) -> done; handle(S, T, I, O) -> O(S), handle(I(), not T, I, O).

main([]) ->

   I = fun() -> hd(io:get_chars([], 1)) end,
   O = fun(S) -> io:put_chars([S]) end,
   handle(I(), false, I, O).

</lang>

Factor

This is a delicate program with arcane control flow. To reverse each odd word, this code uses continuations to jump-back into earlier iterations of a while loop. This trick reverses the letters by reversing the loop!

This code is difficult to follow, because it twists its control flow like spaghetti. These continuations form a singly-linked list, where each continuation contains a letter and a previous continuation. The program effectively reverses this linked list.

<lang factor>USING: continuations kernel io io.streams.string locals unicode.categories ; IN: rosetta.odd-word

<PRIVATE ! Save current continuation.

savecc ( -- continuation/f )
   [ ] callcc1 ; inline

! Jump back to continuation, where savecc will return f.

jump-back ( continuation -- )
   f swap continue-with ; inline

PRIVATE>

read-odd-word ( -- )
   f :> first-continuation!
   f :> last-continuation!
   f :> reverse!
   ! Read characters. Loop until end of stream.
   [ read1 dup ] [
       dup Letter? [
           ! This character is a letter.
           reverse [
               ! Odd word: Write letters in reverse order.
               last-continuation savecc dup [
                   last-continuation!
                   2drop       ! Drop letter and previous continuation.
               ] [
                   ! After jump: print letters in reverse.
                   drop                ! Drop f.
                   swap write1         ! Write letter.
                   jump-back           ! Follow chain of continuations.
               ] if
           ] [
               ! Even word: Write letters immediately.
               write1
           ] if
       ] [
           ! This character is punctuation.
           reverse [
               ! End odd word. Fix trampoline, follow chain of continuations
               ! (to print letters in reverse), then bounce off trampoline.
               savecc dup [
                   first-continuation!
                   last-continuation jump-back
               ] [ drop ] if
               write1                  ! Write punctuation.
               f reverse!              ! Begin even word.
           ] [
               write1                  ! Write punctuation.
               t reverse!              ! Begin odd word.
               ! Create trampoline to bounce to (future) first-continuation.
               savecc dup [
                   last-continuation!
               ] [ drop first-continuation jump-back ] if
           ] if
       ] if
   ] while
   ! Drop f from read1. Then print a cosmetic newline.
   drop nl ;
odd-word ( string -- )
   [ read-odd-word ] with-string-reader ;</lang>
USE: rosetta.odd-word
( scratchpad ) "what,is,the;meaning,of:life." odd-word
what,si,the;gninaem,of:efil.
( scratchpad ) "we,are;not,in,kansas;any,more." odd-word
we,era;not,ni,kansas;yna,more.

FALSE

This solution uses recursion to read the backwards words, to output the characters after having done the rest of that word. <lang false>[$$$$'.=\',=|\';=|\':=|~[^s;!\,]?]s: {recursive reading} [s;!$'.=~[,^f;!]?]r: {reverse words} [[$$$$'.=\',=|\';=|\':=|~][,^]#$'.=~[,^r;!]?]f: {forward words} ^f;!, {start}</lang>

Forth

<lang forth>: word? dup [char] . <> over bl <> and ;

?quit dup [char] . = if emit quit then ;
eatbl begin dup bl = while drop key repeat ?quit ;
even begin word? while emit key repeat ;
odd word? if key recurse swap emit then ;
main cr key eatbl begin even eatbl space odd eatbl space again ;</lang>

Go

<lang go>package main

import (

   "bytes"
   "fmt"
   "io"
   "os"
   "unicode"

)

func main() {

   owp(os.Stdout, bytes.NewBufferString("what,is,the;meaning,of:life."))
   fmt.Println()
   owp(os.Stdout, bytes.NewBufferString("we,are;not,in,kansas;any,more."))
   fmt.Println()

}

func owp(dst io.Writer, src io.Reader) {

   byte_in := func () byte {
       bs := make([]byte, 1)
       src.Read(bs)
       return bs[0]
   }
   byte_out := func (b byte) { dst.Write([]byte{b}) }    
   var odd func() byte
   odd = func() byte {
       s := byte_in()
       if unicode.IsPunct(rune(s)) {
           return s
       }
       b := odd()
       byte_out(s)
       return b
   }
   for {
       for {
           b := byte_in()
           byte_out(b)
           if b == '.' {
               return
           }
           if unicode.IsPunct(rune(b)) {
               break
           }
       }
       b := odd()
       byte_out(b)
       if b == '.' {
           return
       }
   }

}</lang> Output:

what,si,the;gninaem,of:efil.
we,era;not,ni,kansas;yna,more.

Using defer

<lang go>package main

import (

   "bytes"
   "fmt"
   "io"
   "os"
   "unicode"

)

func main() {

   owp(os.Stdout, bytes.NewBufferString("what,is,the;meaning,of:life."))
   fmt.Println()
   owp(os.Stdout, bytes.NewBufferString("we,are;not,in,kansas;any,more."))
   fmt.Println()

}

func owp(dst io.Writer, src io.Reader) {

   byte_in := func () byte {
       bs := make([]byte, 1)
       src.Read(bs)
       return bs[0]
   }
   byte_out := func (b byte) { dst.Write([]byte{b}) }    
   odd := func() byte {
       for {
           b := byte_in()
           if unicode.IsPunct(int(b)) {
               return b
           }
           defer byte_out(b)
       }
       panic("impossible")
   }
   for {
       for {
           b := byte_in()
           byte_out(b)
           if b == '.' {
               return
           }
           if unicode.IsPunct(rune(b)) {
               break
           }
       }
       b := odd()
       byte_out(b)
       if b == '.' {
           return
       }
   }

}</lang>

Using channels and goroutines

Translation of: Ruby
Translation of: Tcl

<lang go>package main

import (

   "bytes"
   "fmt"
   "io"
   "os"
   "unicode"

)

func main() {

   owp(os.Stdout, bytes.NewBufferString("what,is,the;meaning,of:life."))
   fmt.Println()
   owp(os.Stdout, bytes.NewBufferString("we,are;not,in,kansas;any,more."))
   fmt.Println()

}

type Coroutine struct {

   out <-chan Coroutine
   in chan<- byte

}

func owp(dst io.Writer, src io.Reader) {

   byte_in := func () (byte, error) {
       bs := make([]byte, 1)
       _, err := src.Read(bs)
       return bs[0], err
   }
   byte_out := func (b byte) { dst.Write([]byte{b}) }    
   var f, r Coroutine
   f = func () Coroutine {
       out := make(chan Coroutine)

in := make(chan byte)

       var fwd func (byte) byte
       fwd = func (c byte) (z byte) {
           if unicode.IsLetter(rune(c)) {
               byte_out(c)
               out <- f
               z = fwd(<- in)
           } else {
               z = c
           }
           return
       }
       go func () {
           for {
               x, ok := <- in
               if !ok { break }
               byte_out(fwd(x))
               out <- r
           }
       } ()
       return Coroutine{ out, in }
   } ()
   r = func () Coroutine {
       out := make(chan Coroutine)

in := make(chan byte)

       var rev func (byte) byte
       rev = func (c byte) (z byte) {
           if unicode.IsLetter(rune(c)) {
               out <- r
               z = rev(<- in)
               byte_out(c)
           } else {
               z = c
           }
           return
       }
       go func () {
           for {
               x, ok := <- in
               if !ok { break }
               byte_out(rev(x))
               out <- f
           }
       } ()
       return Coroutine{ out, in }
   } ()
   for coro := f; ; coro = <- coro.out {
       c, err := byte_in()
       if err != nil { break }
       coro.in <- c
   }
   close(f.in)
   close(r.in)

}</lang>

Haskell

While it seems like this solution would break the task's rules, Haskell is non-strict, therefore this yields the same behavior of reading and printing one character at a time, without excess storage into a "string". To prove it, run the program and manually enter the input string (Windows command prompt does not respect buffering settings, but urxvt on on Linux does). <lang Haskell>import System.IO

isAlpha :: Char -> Bool isAlpha = flip elem $ ['a'..'z'] ++ ['A'..'Z']

split :: String -> (String, String) split = break $ not . isAlpha

parse :: String -> String parse [] = [] parse l =

 let (a, w) = split l
     (b, x) = splitAt 1 w
     (c, y) = split x
     (d, z) = splitAt 1 y
 in a ++ b ++ reverse c ++ d ++ parse z

main :: IO () main = hSetBuffering stdin NoBuffering >> hSetBuffering stdout NoBuffering >>

      getContents >>= putStr . (takeWhile (/= '.')) . parse >> putStrLn "."</lang>

If the above is not acceptable, or if Haskell was implicitly strict, then this solution would satisfy the requirements: <lang Haskell>isAlpha :: Char -> Bool isAlpha = flip elem $ ['a'..'z'] ++ ['A'..'Z']

parse :: IO () parse = do

 x <- getChar
 putChar x
 case () of
  _ | x == '.'  -> return ()
    | isAlpha x -> parse
    | otherwise -> do
        c <- revParse
        putChar c
        if c == '.'
          then return ()
          else parse

revParse :: IO Char revParse = do

 x <- getChar
 case () of
  _ | x == '.'  -> return x
    | isAlpha x -> do
        c <- revParse
        putChar x
        return c
    | otherwise -> return x

main :: IO () main = hSetBuffering stdin NoBuffering >> hSetBuffering stdout NoBuffering >>

      parse >> putStrLn ""</lang>

Linux urxvt output:

$ ./OddWord
wwhhaatt,,is,si,tthhee;;meaning,gninaem,ooff::life.efil.
$ echo "what,is,the;meaning,of:life." | ./OddWord
what,si,the;gninaem,of:efil.
$ echo "we,are;not,in,kansas;any,more." | ./OddWord
we,era;not,ni,kansas;yna,more.

Windows command prompt output:

>OddWord.exe
what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.
>echo what,is,the;meaning,of:life. | OddWord.exe

what,si,the;gninaem,of;efil.
>echo we,are;not,in,kansas;any,more. | OddWord.exe

we,era;not,ni,kansas;yna,more.

Icon and Unicon

The following recursive version is based on the non-deferred GO version. A co-expression is used to turn the parameter to the wrapper into a character at a time stream.

<lang Icon>procedure main() every OddWord(!["what,is,the;meaning,of:life.",

               "we,are;not,in,kansas;any,more."])

end

procedure OddWord(stream) #: wrapper for demonstration

  write("Input stream: ",stream)
  writes("Output stream: ") & eWord(create !stream,'.,;:') & write()

end

procedure eWord(stream,marks) #: handle even words

  repeat {                               
     repeat 
        writes(@stream) ? if ="." then return else if any(marks) then break
     if writes(oWord(stream,marks)) == '.' then return
     }

end

procedure oWord(stream,marks) #: handle odd words (reverse)

  if any(marks,s := @stream) then return s
  return 1(oWord(stream,marks), writes(s))  

end</lang>

Output:

Input stream: what,is,the;meaning,of:life.
Output stream: what,si,the;gninaem,of:efil.
Input stream: we,are;not,in,kansas;any,more.
Output stream: we,era;not,ni,kansas;yna,more.

A slightly different solution which uses real I/O from stdin is: <lang Unicon>procedure main(A)

   repeat (while writes((any(&letters, c := reads(&input,1)),c))) |
          (writes(c) ~== "." ~== writes(rWord())) | break write()

end

procedure rWord(c)

   c1 := rWord((any(&letters, c1 := reads(&input,1)),c1))
   writes(\c)
   return c1

end</lang> And some sample runs:

->rw
what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.
->rw
we,are;not,in,kansas;any,more.
we,era;not,ni,kansas;yna,more.
->

J

This task's requirement to perform buffering implicitly rather than explicitly was perplexing from a J point of view (see talk page for some of that discussion). To avoid this issue, this implementation uses a coroutine-like utility.

J also lacks character stream support, so this implementation uses a stream-like implementation.

<lang j>putch=: 4 :0 NB. coroutine verb

 outch y
 return x

)

isletter=: toupper ~: tolower

do_char=: 3 :0 NB. coroutine verb

 ch=. getch
 if. isletter ch do.
   if. odd do.
     putch&ch yield do_char  return.
   end.
 else.
   odd=: -. odd
 end.
 return ch

)

evenodd=: 3 :0

 clear_outstream begin_instream y
 odd=: 0
 whilst. '.'~:char do.
   outch char=. do_char coroutine 
 end.

)</lang>

Note that in the couroutine-like support page we defined u yield v y such that it produces a result which, when returned to the coroutine helper verb, will cause the deferred execute u v y in a context where both u and v are expected to be coroutine verbs (they will produce a result either wrapped with yield or with return). Likewise return wraps the result with instructions for the coroutine helper, instructing it to use the returned result "as-is". (And, if return is used with an empty stack in the helper, that instance would be the result of the coroutine helper.)

Note that when we curry putch with ch (in putch&ch) we get a verb which needs only one argument. So in this case, x in putch (its left argument) will be the right argument of the derived verb. In other words, in this example, it will be the result of the do_char instance that uses return ch -- this will be the first non-letter character that is seen when dealing with the odd case.

With this implementation:

<lang j> evenodd 'what,is,the;meaning,of:life.' what,si,the;gninaem,of:efil.

  evenodd 'we,are;not,in,kansas;any,more.'

we,era;not,ni,kansas;yna,more.</lang>

That said, note that this implementation has significant overhead when compared to a more direct implementation of the algorithm.

Java

<lang java>public class OddWord {

   interface CharHandler {

CharHandler handle(char c) throws Exception;

   }
   final CharHandler fwd = new CharHandler() {

public CharHandler handle(char c) { System.out.print(c); return (Character.isLetter(c) ? fwd : rev); }

   };
   class Reverser extends Thread implements CharHandler {

Reverser() { setDaemon(true); start(); } private Character ch; // For inter-thread comms private char recur() throws Exception { notify(); while (ch == null) wait(); char c = ch, ret = c; ch = null; if (Character.isLetter(c)) { ret = recur(); System.out.print(c); } return ret; } public synchronized void run() { try { while (true) { System.out.print(recur()); notify(); } } catch (Exception e) {} } public synchronized CharHandler handle(char c) throws Exception { while (ch != null) wait(); ch = c; notify(); while (ch != null) wait(); return (Character.isLetter(c) ? rev : fwd); }

   }
   final CharHandler rev = new Reverser();
   public void loop() throws Exception {

CharHandler handler = fwd; int c; while ((c = System.in.read()) >= 0) { handler = handler.handle((char) c); }

   }
   public static void main(String[] args) throws Exception {

new OddWord().loop();

   }

}</lang> Output is equivalent to that of the Python solution.

Lasso

<lang Lasso>define odd_word_processor(str::string) => { local( isodd = false, pos = 1, invpos = 1, lastpos = 1 ) while(#str->get(#pos) != '.' && #pos <= #str->size) => { if(not #str->isAlpha(#pos)) => { not #isodd ? #isodd = true | #isodd = false } if(#isodd) => { #lastpos = 1 #invpos = 1 while(#str->isAlpha(#pos+#lastpos) && #pos+#lastpos <= #str->size) => { #lastpos++ } 'odd lastpos: '+#lastpos+'\r' local(maxpos = #pos+#lastpos-1) while(#invpos < (#lastpos+1)/2) => { local(i,o,ipos,opos) #ipos = #pos+#invpos #opos = #pos+(#lastpos-#invpos) #i = #str->get(#ipos) #o = #str->get(#opos)

//'switching '+#i+' and '+#o+'\r'

//'insert '+#o+' at '+(#ipos)+'\r' #str = string_insert(#str,-position=(#ipos),-text=#o)

//'remove redundant pos '+(#ipos+1)+'\r' #str->remove(#ipos+1,1)

//'insert '+#i+' at '+(#opos)+'\r' #str = string_insert(#str,-position=(#opos),-text=#i)

//'remove redundant pos '+(#opos+1)+'\r' #str->remove(#opos+1,1)

#invpos++ } #pos += #lastpos - 1 } //#str->get(#pos) + #isodd + '\r' #pos += 1 } return #str }

'orig:\rwhat,is,the;meaning,of:life.\r' 'new:\r' odd_word_processor('what,is,the;meaning,of:life.') '\rShould have:\rwhat,si,the;gninaem,of:efil.'</lang>

Output:
orig:
what,is,the;meaning,of:life.
new:
what,si,the;gninaem,of:efil.
Should have:
what,si,the;gninaem,of:efil.

Nim

Translation of: Python

<lang nim>import os, unicode, future

proc nothing(): bool{.closure.} = false

proc odd(prev = nothing): bool =

 let a = stdin.readChar()
 if not isAlpha(Rune(ord(a))):
   discard prev()
   stdout.write(a)
   return a != '.'
 # delay action until later, in the shape of a closure
 proc clos(): bool =
   stdout.write(a)
   prev()
 return odd(clos)

proc even(): bool =

 while true:
   let c = stdin.readChar()
   stdout.write(c)
   if not isAlpha(Rune(ord(c))):
     return c != '.'

var e = false while (if e: odd() else: even()):

 e = not e</lang>

Output:

$ echo "what,is,the;meaning,of:life." | ./oddword
what,si,the;gninaem,of:efil.
echo "we,are;not,in,kansas;any,more." | ./oddword
we,era;not,ni,kansas;yna,more.

OCaml

<lang ocaml>let is_alpha c =

 c >= 'a' && c <= 'z' ||
 c >= 'A' && c <= 'Z'

let rec odd () =

 let c = input_char stdin in
 if is_alpha c
 then (let e = odd () in print_char c; e)
 else (c)

let rec even () =

 let c = input_char stdin in
 if is_alpha c
 then (print_char c; even ())
 else print_char c

let rev_odd_words () =

 while true do
   even ();
   print_char (odd ())
 done

let () =

 try rev_odd_words ()
 with End_of_file -> ()</lang>

Executing:

$ echo "what,is,the;meaning,of:life." | ocaml odd_word_problem.ml
what,si,the;gninaem,of:efil.

Perl

All versions process text until EOF, not dot.

Input:

what,is,the;meaning,of:life.

Output:

what,si,the;gninaem,of:efil.

Closure version

<lang Perl>sub r { my ($f, $c) = @_; return sub { print $c; $f->(); }; }

$r = sub {};

while (read STDIN, $_, 1) { $w = /^[a-zA-Z]$/; $n++ if ($w && !$l); $l = $w; if ($n & 1 || !$w) { $r->(); $r = sub{}; print; } else { $r = r($r, $_); } } $r->();</lang>

Recursion version

<lang Perl>sub rev { my $c; read STDIN, $c, 1; if ($c =~ /^[a-zA-Z]$/) { my $r = rev(); print $c; return $r; } else { return $c; } }

while (read STDIN, $_, 1) { $w = /^[a-zA-Z]$/; $n++ if ($w && !$l); $l = $w; if ($n & 1) { print; } else { my $r = rev(); print $_; print $r; $n = 0; $l = 0; } }</lang>

Threads (processes) version

Perl still has weak threads support. Far more safe yet portable is to use processes (fork).

Here, fork is used instead of threads and pipe is used instead of conditional variable. <lang Perl>$|=1;

while (read STDIN, $_, 1) { $w = /^[a-zA-Z]$/; $n++ if ($w && !$l); $l = $w; if ($n & 1 || !$w) { close W; while(wait()!=-1){} print; } else { open W0, ">&", \*W; close W; pipe R,W; if (!fork()) { close W; <R>; print $_; close W0; exit; } close W0; close R; } }</lang>

Perl 6

A recursive solution, with the added feature that it treats each line separately. <lang perl6>my &in = { $*IN.getc // last }

loop {

   ew(in);
   ow(in).print;

}

multi ew ($_ where /\w/) { .print; ew(in); } multi ew ($_) { .print; next when "\n"; }

multi ow ($_ where /\w/) { ow(in) x .print; } multi ow ($_) { $_; }</lang>

Output:
$ ./oddword
we,are;not,in,kansas;any,more.
we,era;not,ni,kansas;yna,more.
what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.

Note how the even/oddness is reset on the line boundary; if not, the second line might have started out in an odd state and reversed "what" instead of "is". The call to next prevents that by sending the loop back to its initial state.

There is one clever trick here with the x operator; it evaluates both its arguments in order, but in this case only returns the left argument because the right one is always 1 (True). You can think of it as a reversed C-style comma operator.

PHP

Translation of: Python

<lang PHP>$odd = function ($prev) use ( &$odd ) { $a = fgetc(STDIN); if (!ctype_alpha($a)) { $prev(); fwrite(STDOUT, $a); return $a != '.'; } $clos = function () use ($a , $prev) { fwrite(STDOUT, $a); $prev(); }; return $odd($clos); }; $even = function () { while (true) { $c = fgetc(STDIN); fwrite(STDOUT, $c); if (!ctype_alpha($c)) { return $c != "."; } } }; $prev = function(){}; $e = false; while ($e ? $odd($prev) : $even()) { $e = !$e; }</lang>

PicoLisp

<lang PicoLisp>(de oddWords ()

  (use C
     (loop
        (until (sub? (prin (setq C (char))) "!,.:;?"))
        (T (= "." C))
        (setq C (char))
        (T
           (= "."
              (prin
                 (recur (C)
                    (if (sub? C "!,.:;?")
                       C
                       (prog1 (recurse (char)) (prin C)) ) ) ) ) ) )
  (prinl) ) )</lang>

Test: <lang PicoLisp>(in "txt1" (oddWords)) (in "txt2" (oddWords))</lang> Output:

what,si,the;gninaem,of:efil.
we,era;not,ni,kansas;yna,more.

PL/I

<lang PL/I>test: procedure options (main); /* 2 August 2014 */

  declare (ch, ech) character (1);
  declare odd file;

get_word: procedure recursive;

  declare ch character (1);
  get file (odd) edit (ch) (a(1));
  if index('abcdefghijklmnopqrstuvwxyz', ch) > 0 then call get_word;
  if index('abcdefghijklmnopqrstuvwxyz', ch) > 0 then
     put edit (ch) (a);
  else ech = ch;

end get_word;

  open file (odd) input title ('/ODDWORD.DAT,TYPE(text),recsize(100)');
  do forever;
     do  until (index('abcdefghijklmnopqrstuvwxyz', ch) = 0 );
        get file (odd) edit (ch) (a(1)); put edit (ch) (a);
     end;
     if ch = '.' then leave;
     call get_word;
     put edit (ech) (a);
     if ech = '.' then leave;
  end;

end test;</lang> file:

what,is,the;meaning,of:life.

output:

what,si,the;gninaem,of:efil.

file:

we,are;not,in,kansas;any,more.

output:

we,era;not,ni,kansas;yna,more.

Prolog

Works with SWI-Prolog. <lang Prolog>odd_word_problem :- read_line_to_codes(user_input, L), even_word(L, Out, []), string_to_list(Str, Out), writeln(Str).

even_word(".") --> ".".

even_word([H | T]) --> {char_type(H,alnum)}, [H], even_word(T).

even_word([H | T]) --> [H], odd_word(T, []).

odd_word(".", R) --> R, ".".

odd_word([H|T], R) --> {char_type(H,alnum)}, odd_word(T, [H | R]).

odd_word([H|T], R) --> R, [H], even_word(T). </lang> Output :

?- odd_word_problem.
|: what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.
true .

?- odd_word_problem.
|: we,are;not,in,kansas;any,more.
we,era;not,ni,kansas;yna,more.
true .

PureBasic

This example uses recursion. <lang PureBasic>#False = 0

  1. True = 1

Global *inputPtr.Character

Macro nextChar()

 *inputPtr + SizeOf(Character)

EndMacro

Procedure isPunctuation(c.s)

 If FindString("!?()[]{},.;:-'" + #DQUOTE$, c)
   ProcedureReturn #True
 EndIf
 ProcedureReturn #False

EndProcedure

Procedure oddWord()

 Protected c.c
 c = *inputPtr\c
 If isPunctuation(Chr(*inputPtr\c))
   ProcedureReturn
 Else
   nextChar()
   oddWord()
 EndIf 
 Print(Chr(c))

EndProcedure

Procedure oddWordProblem(inputStream.s)

 *inputPtr = @inputStream
 Define isOdd = #False
 While *inputPtr\c
   If isOdd
     oddWord()
   Else
     Repeat
       Print(Chr(*inputPtr\c))
       nextChar()
     Until isPunctuation(Chr(*inputPtr\c))
   EndIf
   Print(Chr(*inputPtr\c))
   isOdd ! 1 ;toggle word indicator
   nextChar()
 Wend 

EndProcedure

Define inputStream.s If OpenConsole()

 Repeat
   PrintN(#CRLF$ + #CRLF$ + "Enter a series of words consisting only of English letters (i.e. a-z, A-Z)")
   PrintN("and that are separated by a punctuation mark (i.e. !?()[]{},.;:-' or " + #DQUOTE$ + ").")
   inputStream = Input()
   oddWordProblem(inputStream) ;assume input is correct
 Until inputStream = ""
  
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
 CloseConsole()

EndIf</lang> Sample output:

Enter a series of words consisting only of English letters (i.e. a-z, A-Z)
and that are separated by a punctuation mark (i.e. !?()[]{},.;:-' or ").
what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.

Enter a series of words consisting only of English letters (i.e. a-z, A-Z)
and that are separated by a punctuation mark (i.e. !?()[]{},.;:-' or ").
we,are;not,in,kansas;any,more.
we,era;not,ni,kansas;yna,more.

Python

<lang python>from sys import stdin, stdout

def char_in(): return stdin.read(1) def char_out(c): stdout.write(c)

def odd(prev = lambda: None): a = char_in() if not a.isalpha(): prev() char_out(a) return a != '.'

# delay action until later, in the shape of a closure def clos(): char_out(a) prev()

return odd(clos)

def even(): while True: c = char_in() char_out(c) if not c.isalpha(): return c != '.'

e = False while odd() if e else even(): e = not e</lang> Running:<lang>$ echo "what,is,the;meaning,of:life." | python odd.py what,si,the;gninaem,of:efil. $ echo "we,are;not,in,kansas;any,more." | python odd.py we,era;not,ni,kansas;yna,more.</lang>

Translation of: Scheme

In this version, the action of printing the terminating punctuation is put in a closure and returned by odd(). <lang python>from sys import stdin, stdout

def char_in(): return stdin.read(1) def char_out(c): stdout.write(c)

def odd(): a = char_in() if a.isalpha(): r = odd() char_out(a) return r

# delay printing terminator until later, in the shape of a closure def clos(): char_out(a) return a != '.'

return clos

def even(): while True: c = char_in() char_out(c) if not c.isalpha(): return c != '.'

e = False while odd()() if e else even(): e = not e</lang>

Using coroutines and recursion

Translation of: Ruby
Translation of: Tcl
Works with: Python version 3.3+

<lang python>from sys import stdin, stdout

def fwd(c):

   if c.isalpha():
       return [stdout.write(c), (yield from fwd((yield f)))][1]
   else:
       return c

def rev(c):

   if c.isalpha():
       return [(yield from rev((yield r))), stdout.write(c)][0]
   else:
       return c

def fw():

   while True:
       stdout.write((yield from fwd((yield r))))

def re():

   while True:
       stdout.write((yield from rev((yield f))))

f = fw() r = re() next(f) next(r)

coro = f while True:

   c = stdin.read(1)
   if not c:
       break
   coro = coro.send(c)</lang>

Racket

Simple solution, using a continuation thunk for the reverse parts. <lang racket>

  1. !/bin/sh
  2. |

exec racket -tm- "$0" "$@" |#

  1. lang racket

(define (even k)

 (define c (read-char))
 (cond [(eq? c eof) (k)]
       [(not (char-alphabetic? c)) (k) (write-char c) (odd)]
       [else (even (λ() (write-char c) (k)))]))

(define (odd)

 (define c (read-char))
 (unless (eq? c eof)
   (write-char c)
   (if (char-alphabetic? c) (odd) (even void))))

(provide main) (define (main) (odd) (newline))

(with-input-from-string "what,is,the;meaning,of
life." main)
;; -> what,si,the;gninaem,of
efil.
(with-input-from-string "we,are;not,in,kansas;any,more." main)
;; -> we,era;not,ni,kansas;yna,more.

</lang>

REXX

The REXX program writes some header information to aid in visual fidelity when displaying the output to the
screen (also a blank line is written to make the screen display righteous;   it's assumed that writing titles and
blank lines doesn't break the spirit of the restrictions (single character I/O)   [the 8th line with the three says].

No recursion or the stack is used.   The program could've been written without subroutines. <lang rexx>/*REXX program solves the odd word problem by only using byte input/output.*/ iFID_ = 'ODDWORD.IN' /*Note: numeric suffix is added later.*/ oFID_ = 'ODDWORD.' /* " " " " " " */

    do case=1  for 2;   #=0           /*#:  is the number of characters read.*/
    iFID=iFID_ || case                /*read   ODDWORD.IN1  or  ODDWORD.IN2  */
    oFID=oFID_ || case                /*write  ODDWORD.1    o r ODDWORD.2    */
    say;   say;    say '════════ reading file: '        iFID        "════════"
             do  until x==.           /* [↓]   perform DO loop for odd words.*/
                do  until \isMix(x);  call readChar;   call writeChar;   end
             if x==.  then leave      /*is this end─of─sentence?  (full stop)*/
             call readLetters;             punctuation_location=#
                do j=#-1  by -1;           call readChar  j
                if \isMix(x)  then leave;  call writeChar
                end   /*j*/           /* [↑]    perform for the "even" words.*/
             call readLetters;       call writeChar;    #=punctuation_location
             end      /*until x ···*/
    end   /*case*/                    /* [↑]  process both of the input files*/

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────one─liner subroutines─────────────────────*/ isMix: return datatype(arg(1),'M') /*return 1 if arg is a letter.*/ readLetters: do until \isMix(x); call readChar; end; return writeChar: call charout ,x; call charout oFID,x; return /*──────────────────────────────────readChar subroutine───────────────────────*/ readChar: if arg(1)== then do; x=charin(iFID); #=#+1; end /*read next char*/

                        else     x=charin(iFID, arg(1))      /* "  specific "*/
         return</lang>

output when using two (default) input files which contain:

  •   input file   ODDWORD.IN1   ───►   what,is,the;meaning,of:life.
  •   input file   ODDWORD.IN2   ───►   we,are;not,in,kansas;any,more.


The output is written to the terminal screen as well as to a couple of unique files.   Only the screen output is
shown here, the output files mirror the display except for the headers   (reading file:   xxx)   and the writing
(SAYing) of blank lines which helps keep the screen righteous after using the REXX   charout   BIF   which
wrote to the terminal.

════════ reading file:  ODDWORD.IN1 ════════
what,si,the;gninaem,of:efil.

════════ reading file:  ODDWORD.IN2 ════════
we,era;not,ni,kansas;yna,more.

Ruby

These Ruby programs store each character in a single-character string.

Using fibers and recursion

Translation of: Tcl
Works with: Ruby version 1.9

<lang ruby>f, r = nil fwd = proc {|c|

 c =~ /alpha:/ ? [(print c), fwd[Fiber.yield f]][1] : c }

rev = proc {|c|

 c =~ /alpha:/ ? [rev[Fiber.yield r], (print c)][0] : c }

(f = Fiber.new { loop { print fwd[Fiber.yield r] }}).resume (r = Fiber.new { loop { print rev[Fiber.yield f] }}).resume

coro = f until $stdin.eof?

 coro = coro.resume($stdin.getc)

end</lang>

Using continuations

Translation of: Factor
Library: continuation

<lang ruby>require 'continuation' unless defined? Continuation require 'stringio'

  1. Save current continuation.

def savecc(*data)

 # With MRI 1.8 (but not 1.9), the array literal
 #   [callcc {|cc| cc}, *data]
 # used the wrong return value from callcc. The workaround is to
 # put callcc outside the array literal.
 continuation = callcc {|cc| cc}
 [continuation, *data]

end

  1. Jump back to continuation, where savecc will return [nil, *data].

def jump_back(continuation)

 continuation[nil]

end

def read_odd_word(input, output)

 first_continuation, last_continuation = nil
 reverse = false
 # Read characters. Loop until end of stream.
 while c = input.getc
   c = c.chr   # For Ruby 1.8, convert Integer to String.
   if c =~ /alpha:/
     # This character is a letter.
     if reverse
       # Odd word: Write letters in reverse order.
       saving, last_continuation, c = savecc(last_continuation, c)
       if saving
         last_continuation = saving
       else
         # After jump: print letters in reverse.
         output.print c
         jump_back last_continuation
       end
     else
       # Even word: Write letters immediately.
       output.print c
     end
   else
     # This character is punctuation.
     if reverse
       # End odd word. Fix trampoline, follow chain of continuations
       # (to print letters in reverse), then bounce off trampoline.
       first_continuation, c = savecc(c)
       if first_continuation
         jump_back last_continuation
       end
       output.print c      # Write punctuation.
       reverse = false     # Begin even word.
     else
       output.print c      # Write punctuation.
       reverse = true      # Begin odd word.
       # Create trampoline to bounce to (future) first_continuation.
       last_continuation, = savecc
       unless last_continuation
         jump_back first_continuation
       end
     end
   end
 end
 output.puts   # Print a cosmetic newline.

end

def odd_word(string)

 read_odd_word StringIO.new(string), $stdout

end

odd_word "what,is,the;meaning,of:life." odd_word "we,are;not,in,kansas;any,more."</lang>

Run BASIC

<lang runbasic>open "oddWord.txt" for input as #f ' read input stream while not(eof(#f)) line input #f, a$ oddW$ = "" ' begin the result oddW with blank px = 0 ' begin word search location with 0 count = 0 ' begin the word count to 0 while x < len(a$) ' look at each character x = instr(a$,",",px) ' search for comma (,) if x = 0 then x = len(a$) ' no more commas? x1 = instr(a$,";",px) ' search for (;) x2 = instr(a$,":",px) ' search for (:) if x1 <> 0 then x = min(x,x1) ' what came first the , ; or : if x2 <> 0 then x = min(x,x2)

w$ = mid$(a$,px,x - px) ' get the word seperated by , ; or :

if count and 1 then ' is it the odd word w1$ = "" for i = len(w$) to 1 step -1 w1$ = w1$ + mid$(w$,i,1) ' reverse odd words next i w$ = w1$ end if

       oddW$ = oddW$ + w$ + mid$(a$,x,1)        ' add the word to the end of oddW$

px = x + 1 ' bump word search location for next while count = count + 1 ' count the words wend print a$;" -> ";oddW$ ' print the original and result next ii wend close #f</lang>

what,is,the;meaning,of:life.   -> what,si,the;gninaem,of:efil.
we,are;not,in,kansas;any,more. -> we,era;not,ni,kansas;yna,more.

Scala

<lang Scala>import scala.io.Source import java.io.PrintStream

def process(s: Source, p: PrintStream, w: Int = 0): Unit = if (s.hasNext) s.next match {

 case '.' => p append '.'
 case c if !Character.isAlphabetic(c) => p append c; reverse(s, p, w + 1)
 case c => p append c; process(s, p, w)

}

def reverse(s: Source, p: PrintStream, w: Int = 0, x: Char = '.'): Char = s.next match {

 case c if !Character.isAlphabetic(c) => p append x; c
 case c => val n = reverse(s, p, w, c);
   if (x == '.') {p append n; process(s, p, w + 1)} else p append x; n

}

process(Source.fromString("what,is,the;meaning,of:life."), System.out); println process(Source.fromString("we,are;not,in,kansas;any,more."), System.out); println</lang>

Output:
what,si,the;gninaem,of:efil.
we,era;not,ni,kansas;yna,more.

Scheme

Output is identical to python. <lang lisp>(define (odd)

 (let ((c (read-char)))
   (if (char-alphabetic? c)
     (let ((r (odd)))

(write-char c) r)

     (lambda () (write-char c) (char=? c #\.)))))

(define (even)

 (let ((c (read-char)))
   (write-char c)
   (if (char-alphabetic? c)
     (even)
     (char=? c #\.))))

(let loop ((i #f))

 (if (if i ((odd)) (even))
   (exit)
   (loop (not i))))</lang>

Seed7

<lang seed7>$ include "seed7_05.s7i";

 include "chartype.s7i";

const func char: doChar (in boolean: doReverse) is func

 result
   var char: delimiter is ' ';
 local
   var char: ch is ' ';
 begin
   ch := getc(IN);
   if ch in letter_char then
     if doReverse then
       delimiter := doChar(doReverse);
       write(ch);
     else
       write(ch);
       delimiter := doChar(doReverse);
     end if;
   else
     delimiter := ch;
   end if;
 end func;

const proc: main is func

 local
   var char: delimiter is ' ';
   var boolean: doReverse is FALSE;
 begin
   repeat
     delimiter := doChar(doReverse);
     write(delimiter);
     doReverse := not doReverse;
   until delimiter = '.';
   writeln;
 end func;</lang>
Output:
> s7 oddWordProblem
SEED7 INTERPRETER Version 5.0.5203  Copyright (c) 1990-2014 Thomas Mertes
what,is,the;meaning,of:life.
what,si,the;gninaem,of:efil.

Tcl

Although the input is handled as strings, they're all as single-character strings.

Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6

proc fwd c {

   expr {[string is alpha $c] ? "[fwd [yield f][puts -nonewline $c]]" : $c}

} proc rev c {

   expr {[string is alpha $c] ? "[rev [yield r]][puts -nonewline $c]" : $c}

} coroutine f while 1 {puts -nonewline [fwd [yield r]]} coroutine r while 1 {puts -nonewline [rev [yield f]]} for {set coro f} {![eof stdin]} {} {

   set coro [$coro [read stdin 1]]

}</lang> Output is identical to Python and Scheme versions.

The only difference between the two coroutines (apart from the different names used when flipping back and forth) is the timing of the write of the character with respect to the recursive call.

TUSCRIPT

This example is incorrect. Please fix the code and remove this message.

Details: You are supposed to read characters one by one and not store them in arrays.

<lang tuscript> $$ MODE TUSCRIPT inputstring=* DATA what,is,the;meaning,of:life. DATA we,are;not,in,kansas;any,more.

BUILD C_GROUP >[pu]=".,;:-"

LOOP i=inputstring pu=STRINGS (i,"|>[pu]|") wo=STRINGS (i,"|<></|") outputstring=""

loop n,w=wo,p=pu
r=MOD(n,2)
IF (r==0) w=TURN (w)
outputstring=CONCAT(outputstring,w,p)

ENDLOOP PRINT outputstring ENDLOOP </lang> Output:

what,si,the;gninaem,of:efil.Brian:
we,era;not,ni,kansas;yna,more. 

zkl

Translation of: D

<lang zkl>var [const] delim=",:;/?!@#$%^&*()_+", stop="."; fcn oddly(inStream){

  inStream=inStream.walker(3);  // character iterator: string, file, etc
  doWord:=fcn(inStream,rev,f){  // print next word forewards or reverse
     c:=inStream.next();
     if(not rev) c.print();
     if(not (c==stop or delim.holds(c)))

return(self.fcn(inStream,rev,'{ c.print(); f(); }));

     if(rev){ f(); c.print(); }
     return(c!=stop);
  };
  tf:=Walker.cycle(False,True);  // every other word printed backwords
  while(doWord(inStream, tf.next(), Void)) {}
  println();

}</lang> Showing two different input streams: <lang zkl>oddly("what,is,the;meaning,of:life."); oddly(Data(0,String,"we,are;not,in,kansas;any,more."));</lang>

Output:
what,si,the;gninaem,of:efil.
we,era;not,ni,kansas;yna,more.