Provide here your solution(s) to the OddWordProblem. Failure to do so will color how seriously comments are taken concerning how trivial the problem is.
In CeeLanguage:
#include <stdio.h> #include <ctype.h> int peek() { int c = getchar(); ungetc(c, stdin); return c; } int pop() { return getchar(); } int alpha() { return isalpha(peek()); } int space() { return isspace(peek()); } void chkend() { if(peek() == '.') { printf(".\n"); exit(0); } } void spaces(int f) { while(space()) pop(); chkend(); if(f) putchar(' '); } void even() { while(alpha()) putchar(pop()); } void odd() { if(alpha()) { int c = pop(); odd(); putchar(c); } } int main() { spaces(0); for(;;) { even(); spaces(1); odd(); spaces(1); } }Beware when testing this that your buffering does not interfere with very long input.
Beautiful.
Another in CeeLanguage:
The function f(char *cur) takes a pointer to the input text and prints output text to stdin as specified by the problem. It returns a non-zero value upon failure (which only happens if the string does not have the terminating point or if printf fails).
int f(char *cur) {
char buffer[20], *out; int STATE, i; while(isspace(*cur)) cur++; for(STATE = 1, i = 0; *cur; i = 0, putchar(' ')) { while(isalpha(*cur)) buffer[++i] = *cur++; out = buffer + (STATE == 1 ? 0 : i + 1); while(i--) putchar(*(out += STATE)); STATE *= -1; while(isspace(*cur)) cur++; if(*cur == '.') return !printf(".\n"); } return 1;}
In SchemeLanguage:
(define (spaces starting continuation) (case (peek-char) ((#\.) (display #\.) (newline)) ((#\space) (read-char) (spaces starting continuation)) (else (if (not starting) (display #\space)) (continuation)))) (define (even) (case (peek-char) ((#\. #\space) (spaces #f odd)) (else (display (read-char)) (even)))) (define (odd) (define (magic) (case (peek-char) ((#\. #\space) #f) (else (let ((c (read-char))) (magic) (display c))))) (magic) (spaces #f even)) (spaces #t even)
Another in SchemeLanguage:
(define spacemap '((startspaces . startspaces) (evenword . oddspaces) (oddspaces . oddspaces) (oddword . evenspaces) (evenspaces . evenspaces))) (define (oddmagic) (case (peek-char) ((#\space #\.) #f) (else (let ((c (read-char))) (oddmagic) (display c))))) (define (oddwords) (let loop ((state 'startspaces)) (case (peek-char) ((#\space) (read-char) (loop (cdr (assv state spacemap)))) ((#\.) (display (read-char)) (newline)) (else (case state ((startspaces) (loop 'evenword)) ((evenword) (display (read-char)) (loop 'evenword)) ((oddspaces) (display #\space) (loop 'oddword)) ((oddword) (oddmagic) (loop 'evenspaces)) ((evenspaces) (display #\space) (loop 'evenword)))))))
In PerlLanguage (ignoring the character-at-a-time requirement and doing it with strings and regular expressions):
do { $line .= getc(); } until($line =~ /\.$/); $line =~ s/^ *//; $line =~ s/ *\././; $line =~ s/ +/ /g; $line =~ s/([^ .]+) ([^ .]+)/ "$1 " . reverse($2) /eg; print "$line\n";Oh, please. If you're going to ignore one of the specifications for the problem, you could at least give a good answer. That's the sort of thing that makes Perl look bad. There's a reverse function for a reason, you know. Here, try this.
my @words = split " ", "whats the matter with kansas."; my $odd; for (0..$#words) { if ($odd) { $words[$_] = join "", reverse split "", $words[$_]; undef $odd; next; } $odd = 1; } print join " ", @words;
This does look pretty straightforward, with a couple of bookkeeping details in the spec. Here is a CommonLisp version. I haven't tried this, and only had a couple of minutes for it, but I think it is correct w.r.t the given spec. It uses as 20 character buffer, there are probably much more elegant ways to do this. -- ska
(defun oddword (input-stream output-stream) (let ((word-count 0) (buffer (make-array 20 :element-type 'base-char :fill-pointer 0 :adjustable t))) (flet ((eat-spaces () (loop for s = (read-char input-stream nil input-stream) until (or (eq s input-stream) (not (eq s #\space))) finally (unread-char s input-stream))) (print-word () (if (oddp word-count) (loop for n from (1- (length buffer)) downto 0 do (write-char (aref buffer n) output-stream)) (loop for n below (length buffer) do (write-char (aref buffer n) output-stream))) (incf word-count) (setf (fill-pointer buffer) 0))) (loop for s = (read-char input-stream nil input-stream) until (eq s input-stream) do (case s (#\space (eat-spaces) (print-word) (unless (eq #\. (peek-char t input-stream)) (write-char #\space output-stream))) (#\. (print-word) (write-char #\. output-stream)) (t (vector-push-extend s buffer)))))))
I took the above CL solution and improved (my opinion :-) it:
(defun oddword (&key (input *query-io*) (output *query-io*)) (let ((word-count 0) (buffer nil)) (flet ((eat-spaces () (loop for c = (read-char input) while (eql c #\Space) finally (unread-char c input))) (print-word () (mapc 'write-char (if (oddp word-count) buffer (reverse buffer))) (incf word-count) (setf buffer nil))) (handler-case (loop for c = (read-char input) do (case c (#\Space (print-word) (eat-spaces) (unless (eql #\. (peek-char t input)) (write-char #\Space output))) (#\. (print-word) (write-char #\. output)) (t (push c buffer)))) (end-of-file () (print-word))))))
A Modula-2 implementation of a similar specification (word length 70, handle '\r') is at http://www.modulaware.com/mdlt53.htm. It uses CoRoutines.
A JavaLanguage solution:
package com.ebh; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; /** * Consider a character set consisting of letters, a space, * and a point. Words consist of one or more, but at most * 20 letters. An input text consists of one or more words * separated from each other by one or more spaces and * terminated by 0 or more spaces followed by a point. * Input should be read from, and including, the first * letter of the first word, up to and including the * terminating point. The output text is to be produced * such that successive words are separated by a single * space with the last word being terminated by a single * point. Odd words are copied in reverse order while even * words are merely echoed. For example, the input string * whats the matter with kansas. * becomes * whats eht matter htiw kansas. * The problem is further restricted in that the characters * must be read and printed one at a time. */ public class OddWordProblem { static ArrayList<Character> word = new ArrayList<Character>(); static Character separator; static boolean forward=true; static boolean wordEnded = false; static final char SPACE = ' '; static final char PERIOD = '.'; public static void main(String[] args) throws IOException { BufferedReader input = new BufferedReader(new FileReader(args[0])); BufferedWriter output = new BufferedWriter(new FileWriter(args[1])); solve(input, output); output.flush(); } private static void solve(BufferedReader input, BufferedWriter output) throws IOException { int nextCharAsInt; while ((nextCharAsInt = input.read())!=-1) { char nextChar = (char)nextCharAsInt; if (nextChar == SPACE || nextChar == PERIOD) { endOfWord(output, nextChar); } else { middleOfWord(output, nextChar); } } if (separator!=null) { output.write(separator.charValue()); } } private static void middleOfWord(BufferedWriter output, char nextChar) throws IOException { if (wordEnded) { wordEnded = false; forward = !forward; output.write(separator.charValue()); } word.add(nextChar); } private static void endOfWord(BufferedWriter output, char nextChar) throws IOException { if (!forward) { Collections.reverse(word); } writeCurrentWord(output); separator = nextChar; word.clear(); wordEnded = true; } private static void writeCurrentWord(BufferedWriter output) throws IOException { for (char c : word) { output.write(c); } } }What's so hard about that? -- EricHodges
See OddWordProblemSolutionArgument
A ForthLanguage solution (should work in any ANS Forth):
variable wordLen create word 20 chars allot : addLetter ( [a-z] -- ) wordLen @ 20 < 0= abort" word too long!" word wordLen @ chars + c! 1 wordLen +! ; : emitWord word wordLen @ chars + word do I c@ emit loop ; : droWtime word 1 chars - dup wordLen @ chars + do I c@ emit -1 chars +loop ; : eatSpaces ( bl -- [a-z.] ) begin drop key dup bl <> until ; : getWord ( [a-z] -- [a-z.] ) begin addLetter key dup [char] . = if exit then dup bl = until eatSpaces ; variable parity : wordOut wordlen @ 0= abort" word parsing broken" parity @ if droWtime false else emitWord true then parity ! 0 wordLen ! ; : main false parity ! 0 wordLen ! bl eatSpaces ( c ) dup [char] . = if emit exit then begin getWord wordOut dup [char] . <> while space repeat emit ;This problem is also a good test for coming up with good test cases for the spec. For instance, I had to redo the design once when I realized "word ." needed to output "word." And then I had to handle the minimal input of "." and " ." differently. -- IanOsgood
That's actually above and beyond the call of duty. Here is the initial spec, which disallows the minimal input you list:
Another ForthLanguage solution, in the style of the elegant CeeLanguage entry. The 'ungetc' character is kept on top of the stack.
: 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 ;
The same in FalseLanguage:
[[$' =][%^]#]b: [$$'.=\' =|~]w: [$'.=~[' ,]?]s: [w;![^o;!\,]?]o: ^b;![$'.=~][w;[,^]#b;!s;!o;!b;!s;!]#,
#include <iostream> #include <fstream> #include <algorithm> using namespace std; const char WORD_SEPARATOR = ' '; const char END_OF_STREAM = '.'; const unsigned MAX_WORD_LENGTH = 20; //----------------------------------------------------------------------------- template <typename TYPE> class auto_close { public: TYPE& resource; auto_close(TYPE& r) : resource(r) { }; ~auto_close() { if (resource.is_open()) resource.close(); }; }; //----------------------------------------------------------------------------- void extractWord(istream& in, string& word) { while (in.good() && in.peek() != END_OF_STREAM && in.peek() == WORD_SEPARATOR) in.ignore(); word.clear(); while (in.good() && in.peek() != END_OF_STREAM && in.peek() != WORD_SEPARATOR) { word += in.get(); if (word.length() > MAX_WORD_LENGTH) throw length_error("Invalid input. Character/Word length exceeded."); } } //***************************************************************************** int main(int argc, char* argv[]) { try { if (argc != 3) throw invalid_argument("Invalid arguments."); ifstream infile(argv[1]); ofstream outfile(argv[2]); auto_close<ifstream> infile_close(infile); auto_close<ofstream> outfile_close(outfile); string word; unsigned long wordCount = 0; while (infile.good() && infile.peek() != END_OF_STREAM) { extractWord(infile, word); if (wordCount++ & 1) reverse(word.begin(), word.end()); for (string::const_iterator p = word.begin(); p != word.end(); ++p) outfile << *p; outfile << WORD_SEPARATOR; } outfile.seekp(outfile.tellp() - fpos<int>(wordCount ? 1 : 0)); outfile << END_OF_STREAM; } catch (exception& e) { cerr << "Error: " << e.what() << endl; return -1; } return 0; }-- KyleWakefield
Erics solution translated to CeeSharp and refactored a bit
using System; using System.IO; using System.Collections; public class OddWordProblem { [STAThread] static void Main(string[] args) { StreamWriter output = new StreamWriter(args[1]); new OddWordProblem().Solve(new StreamReader(args[0]), output); output.Flush(); } ArrayList currentWord = new ArrayList(); char aSeparator; bool isForward=true; bool isWordEnded=false; void Solve(StreamReader theInput, StreamWriter theOutput) { int nextChar; while ((nextChar = theInput.Read())!=-1) { char aChar = (char)nextChar; if(aChar==' '||aChar=='.')EndOfWord(theOutput, aChar); else MiddleOfWord(theOutput, aChar); } theOutput.Write(aSeparator); } void MiddleOfWord(StreamWriter theOutput, char aChar) { if(isWordEnded) { isWordEnded = false; isForward = !isForward; theOutput.Write(aSeparator); } currentWord.Add(aChar); } void EndOfWord(StreamWriter output, char nextChar) { if(!isForward)currentWord.Reverse(); foreach(char aChar in currentWord) output.Write(aChar); aSeparator = nextChar; currentWord = new ArrayList(); isWordEnded = true; } }
A modest proposal. To make OddWordProblemSolution? in JavaLanguage a worthwhile challenge, I spoke to myself: "Self! let's do it in a single procedure, with fixed size memory, like we used to do it PascalLanguage and other worthwhile languages". Java syntax kind of stayed in my way, but then I figure out that _ can be an identifier, and is kind of unobtrusive to read. Therefore the fake _. operator will give access to your friendly VAR section of the outer procedure. Wile the fake ._() becomes an acceptable way to call a procedure. It's kind of prematurely optimized, but people who lived to program for Kbytes of memory have nothing to be ashamed of.
/** * You can write PASCAL in JAVA * With thanks to Dr. Wirth for showing the way * and also to Dr. Gries for this invaluable piece of wisdom * DO NOT PROGRAM IN A LANGUAGE PROGRAM INTO A LANGUAGE */ public class OddWordsProgram? { interface Procedure { public void _() throws Exception; } static final int MAX_SIZE=20; public static void main(String args[]) { // Like I told you, this is your friendly VAR section // mayeb we can lobby James Gosling to consider it for Java 1.6 class VAR { int c; boolean readEvenFlag= true; boolean firstTimeSkipSpace=true; // for lack of real forward declarations some inner procedure // are declared as variables in the local scope } final VAR _ = new VAR(); class ReadNextChar? {public void _() throws Exception {_.c= System.in.read(); }} final ReadNextChar? readNextChar= new ReadNextChar?(); class EatSpace? implements Procedure { public final void _() throws Exception { do { readNextChar._(); } while (_.c != -1 && _.c== ' ' ); }} EatSpace? eatSpace= new EatSpace?(); class ReadEvenWord? implements Procedure { public final void _() throws Exception { if (! _.firstTimeSkipSpace) { System.out.write(' '); } else _.firstTimeSkipSpace=false; do { System.out.write(_.c); readNextChar._(); } while (_.c != -1 && _.c!=' ' && _.c!= '.'); _.readEvenFlag= false; }} ReadEvenWord? readEvenWord= new ReadEvenWord?(); final byte [] buffer= new byte[MAX_SIZE]; class ReadOddWord? implements Procedure { public final void _() throws Exception { int index=MAX_SIZE; System.out.write(' '); do { buffer[--index] = (byte) _.c; readNextChar._(); } while (_.c != -1 && _.c!= ' ' && _.c!= '.' ); System.out.write(buffer,index, MAX_SIZE - index); _.readEvenFlag= true; }} ReadOddWord? readOddWord= new ReadOddWord?(); try { readNextChar._(); while (true){ if (_.c==' ') eatSpace._(); else if (_.c== -1) { System.err.println("Error: unexpected end of file, waiting for '.' "); System.exit(-1);} else if (_.c == '.') { System.out.write('.'); break;} else { if (_.readEvenFlag ) readEvenWord._(); else readOddWord._(); }} System.out.flush(); } catch (ArrayIndexOutOfBoundsException? ex) { System.err.println("I caught an odd input word longer than MAX_SIZE="+MAX_SIZE); System.exit(-1); } catch(Exception ex) { System.err.println(ex); ex.printStackTrace(System.err); System.exit(-1); } }}
As an example of how trivial this problem is without the restriction that characters be "READ AND WRITTEN" (oppose "READ and WRITTEN") one at a time, here is the HaskellLanguage solution:
import Char main = (printOneAtATime . oddword) "whats the matter with kansas." printOneAtATime [] = putChar '\n' printOneAtATime (c:cs) = putChar c >> printOneAtATime cs oddword [] = [] oddword ('.':cs) = ['.'] oddword (c:cs) | isSpace c && test cs = [c] ++ (oddword' (dropWhile isSpace cs) []) | isSpace c= [c] ++ "." | otherwise= [c] ++ (oddword cs) oddword' [] acc = acc oddword' ('.':cs) acc = acc ++ "." oddword' (c:cs) acc | isSpace c && test cs = acc ++ [c] ++ (oddword (dropWhile isSpace cs)) | isSpace c= acc ++ "." | otherwise= oddword' cs (c:acc) test cs = (head (dropWhile isSpace cs)) /= '.'Since the length of the words are bounded in the problem, "acc" will never grow beyond 20 characters. This is why you should challenge yourself with the Turing-tape style formulation of the problem. As an aside, this demonstrates how industry-standard languages can certainly be the wrong tool for the job.
Note -- Reimplementing Haskell's output function is busywork. Modern systems use buffered I/O, so technically this solution might not satisfy "written one at a time" out of the box, but the spirit of the problem is maintained, assuming you allow for a "word" buffer at all. The standard Haskell function dropWhile reads one element at time by definition, as do my functions.
Note also the Lisp version above is pretty clean, even following the original spec (supporting your comment about industry-standard languages).
I read the question and daydreamed at work about writing a C++ version based on a general finite state machine and polymorphism, but when I sat down to work on it at home I found myself more and more attracted to terser CeeLanguage version, and so I wrote this:
#include <stdio.h> char copy_word(char** in, char** out, int direction) {// copies word in direction specified, leaves dots and spaces. char c = **in; if (c != ' ' && c != '.') {// dont touch specail chars ++*in; if (direction == 1) {
char oddword(char* in, char* out) { int dir = 1;// first word backwards while (1) { if( *in == '.') break;// dot means end while( *in == ' ') in++;// eat space
if( *in == '.') break;// dot means end copy_word(&in, &out, dir*=-1);// negating alternates direction
if( *in == '.') break;// dot means end
char oddword0(char* in, char* out) {// test main while(*out++ = *in++); }
int main(int argc, char* argv[]) { char buf[1024],*ptr = buf;// this is just me revising pointers while (--argc || (ptr[-1] = 0)) for (char* wrd = *++argv; (*ptr++ = *wrd++) || !(ptr[-1] = ' '););
oddword(buf, buf);
}Please forgive the main() function that I wrote first, not so much in the spirit of true XP but in order to practice pointer arithmetic!
main() throws space-separated command line arguments into a fixed size array. You can test multiple spaces by quoting them in the command line. This array size limit is not a constraint of my solution, merely of the test code. Similarly the fact that you may see junk after the dot if you reuse the test buffer, as I do here. I think it is good to reuse the testbuffer for in and out despite the junk because it helps test that the algorithm is reading and writing one character at a time.
The algorithm calls a recursive function to copy each word letter by letter but it does tail recursion to copy normally, and recurse, then copy to copy reversed. -- BillWeston
hang on though, I just realised it doesn't fulfil the conditions... to do that I must always have a ++ when I have a *. I will try again -- BillWeston
What? No RubyLanguage solutions? We'll have to fix that:
class OddWord? def initialize(input) @input = input end def go c = read_word(reverse = false) c = read_word(reverse = !reverse, find_word) until c == '.' puts c end private def read return [@input.getc].pack('c') end def read_word(reverse, c = read) return c if [' ', '.'].include?(c) print c unless reverse v = read_word(reverse) print c if reverse return v end def find_word(c = read) return find_word if c == ' ' print ' ' unless c == '.' return c end end-- JasonArhart
def oddwords(put,get): def output(stack, goForward=True): if goForward: for storedChar in stack: put(storedChar) else: while len(stack)>0: put(stack.pop()) goForward=True stack=[] while 1: c=get() if c in " .": output(stack,goForward) goForward ^= True while c==" ": c=get() if c!=".": put(" ") stack=[] if c==".": put(".") break stack.append(c)Solutions to this puzzle should probably be divided into several categories. In one category, the main restriction would be character-at-a-time I/O without the ability to push-back onto the input stream or pull-back from the output stream. In other words, a solution would be a function which took arbitrary "char get(void)" and "void put(char)" functions, and reproduced the correct behavior. In another category, I/O pushback (in the style of a Turing tape) would be permitted, but the program would not be permitted to store data "off the tape" in stacks or recursive function calls -- solutions would presumably be submitted in BrainfuckLanguage or a similar Turing-tape emulator.
Ya shouldn'ta mentioned BrainfuckLanguage, 'cause I had to make a solution on the SnuspLanguage page. Amazingly, it is not longer than other solutions on this page.
Alternate PythonLanguage solution:
from sys import stdin, stdout def even(char) : stdout.write(char); return select(even, 0, ""); def odd(char) : q = select(odd, 0, ""); stdout.write(char); return q def select(fn, skipspace, prefix) : char = stdin.read(1) if char.isspace() and skipspace : return select(fn, 1, prefix) elif char.isspace() : return 0 elif char.isalpha() : stdout.write(prefix); return fn(char) elif char == "." : return 1 else : raise "Invalid input" if not select(even, 1, "") : while not select(odd, 1, " ") and not select(even, 1, " ") : pass stdout.write(".")
program oddwords(input,output); function dospaces(starting: boolean) : boolean; begin while input^ = ' ' do get(input); case input^ of '.': begin dospaces := false; writeln('.'); end; else begin dospaces := true; if not starting then write(' '); end end end; procedure oddmagic; var c: char; begin case input^ of '.', ' ': ; { do nothing } else begin c := input^; get(input); oddmagic; write(c); end end end; var parity: (odd, even); var starting: boolean; begin starting := true; parity := even; while dospaces(starting) do begin starting := false; if parity = even then begin while (input^ <> '.') and (input^ <> ' ') do begin write(input^); get(input); end; parity := odd end else begin oddmagic; parity := even end end end.
In CommonLisp
(defvar *finished* nil) (defun chomp () (cond ((char= (peek-char) #\Space) (read-char) (chomp)))) (defun getc () (let ((c (read-char))) (case c (#\. (setf *finished* t)) (#\ (chomp))) c)) (defun even (s) (if (char/= (write-char (getc) s) #\Space #\.) (even s))) (defun odd () (let ((str (reverse (with-output-to-string (s) (even s))))) (loop for c across (subseq str 1) do (write-char c)) (write-char (elt str 0)))) (defun main () (let ((foo #'(lambda () (even *standard-output*))) (bar #'odd)) (loop do (progn (funcall foo) (if *finished* (return)) (rotatef foo bar))))) (main)
The JavaLanguage versions above all seem unnecessarily verbose. The CeeLanguage version at the top seems straightforward enough, and it can easily be adapted to Java with some helper methods and type casting:
public class OddWordProblem { static final int EOF = -1;//returned by in.read() static final int NIL = -2;//to be distinct from EOF int buffer = NIL; void putchar( char ch ) { System.out.print( ch ); } int getchar() { //hack to avoid having "throws IOException" on *EVERY* other method try { return System.in.read(); } catch ( java.io.IOException e ) { throw new RuntimeException( e ); } } int peek() { if ( buffer == NIL ) buffer = getchar(); return buffer; } char pop() { int result = peek(); buffer = NIL; return (char) result; } boolean alpha() { return peek() >= 0 && Character.isLetter( (char) peek() ); } boolean space() { return peek() >= 0 && Character.isWhitespace( (char) peek() ); } void chkend() { if(peek() == '.') { System.out.println(".\n"); System.exit(0); } } void spaces() { spaces(true); } void spaces(boolean f) { while(space()) pop(); chkend(); if(f) putchar(' '); } void even() { while(alpha()) putchar(pop()); } void odd() { if(alpha()) { int c = pop(); odd(); putchar((char)c); } } int main() { spaces(false); for(;;) { even(); spaces(); odd(); spaces(); } } public static void main( String[] args ) { new OddWordProblem().main(); } }
"""OddWordProblem solution in PythonLanguage using GeneratorsInPython. >>> def test_oddword(instr): ... import sys, StringIO, oddword ... infile = StringIO.StringIO(instr) ... def getchar(): return infile.read(1) ... def putchar(c): sys.stdout.write(c) ... oddword.oddword(getchar, putchar) ... >>> test_oddword('whats the matter with kansas.') whats eht matter htiw kansas. """ class Error(StandardError): pass WB, END = '!', '.' def getletter(getc): c = getc() if not c.isalpha(): raise Error("First symbol must be a letter: `%s'" % c) space = False while True: if c.isspace(): space = True elif c == END: break # exit generator elif c.isalpha(): if space: space = False yield WB # word boundary yield c else: raise Error("Invalid symbol: `%s'" % c) # EOF here too c = getc() def oddword(getc,putc): def printword(word, reverse, ws = ' '): if reverse: word.reverse() for c in word: putc(c) putc(ws) word = []; reverse = False for char in getletter(getc): if char == WB: # word boundary printword(word, reverse) # print previous word word = []; reverse = not reverse # begin new word else: if len(word) == 20: raise Error('Max word length exceeded') word.append(char) printword(word,reverse, '.') # print last word def testdoc(): import doctest return doctest.testmod() if __name__=='__main__': if testdoc()[0] == 0: print 'OK'I'm a newbie in PythonLanguage, so the above code may be not a Pythonic one.
Here is a PascalLanguage translation of the solution that EwDijkstra published in his essay "Notes on Structured Programming" in the book Structured Programming. It is interesting to note that:
program oddword(input, output); var forward : boolean; x : char; c : array [ 1 .. 20 ] of char; l, k, inc, term : integer; begin forward := true; read(x); repeat l := 0; repeat l := l + 1; c[l] := x; read(x) until (x = ' ') or ( x = '.'); while x = ' ' do read(x); if forward then begin k := 0; inc := +1; term := l end else begin k := l + 1; inc := -1; term := 1 end; repeat k := k + inc; write(c[k]) until k = term; if x = '.' then write('.') else write(' '); forward := not forward until x = '.'; writeln end.
Here's one in DelphiLanguage by JosephStyons:
function ReverseOddWords?(s : string): string; function StrReverse?(s : string) : string; var i : integer; begin Result := ''; for i := Length(s) downto 1 do Result := Result + s[i]; end; var i : integer; oddword : boolean; lastCharWasASpace : boolean; currentWord : string; begin oddword := True; //first word is odd lastCharWasASpace := False; currentWord := ''; for i := 1 to Length(s) do begin //for each letter... if ((s[i] = ' ') and not(lastCharWasASpace)) or (s[i]='.') then begin if oddword then Result := Result + StrReverse?(currentWord) + s[i] else Result := Result + currentWord + s[i]; currentWord := ''; oddword := not(oddword) end else if s[i] <> ' ' then currentWord := currentWord + s[i]; lastCharWasASpace := ' '=s[i]; //use this since we can't look forward or back end; end;
Another solution in common lisp... but it's not very functional programming
(defun kill-spaces () "Eliminates spaces from input and returns the next caracter to be read." (peek-char t)) ;nice feature of peek-char... removes every whitespace it finds (defun print-word (word) "Prints a list of characters." (dolist (c word) (write-char c)) (defun odd-word () "Reads a word and prints it reversed" (do ((c (peek-char) (peek-char)); each iteration pushes a char in the list (word nil)) ((or (char= c #\.) (char= c #\Space)) (print-word word)) (push (read-char) word))) (defun even-word () "Reads a word and prints it to output" (do ((c (peek-char) (peek-char))) ((or (char= c #\.) (char= c #\Space))) (write-char (read-char)))) (defun odd-word-magic () (do ((next-c (kill-spaces) (kill-spaces)) ; next-c is always the first char of a word or a "." (word-count 0 (1+ word-count))) ((char= next-c #\.) (write-char (read-char))) (if (not (zerop word-count)) ; if its the first word, no space (write-char #\Space)) (if (oddp word-count) (odd-word) (even-word))))
Better Haskell version (ignoring the character-at-a-time requirement):
import Data.List enumerate = zip $ cycle [0,1] oddwords x = foldl' add "" (enumerate ws) ++ "." where add "" (_,t) = t add s (0, t) = s ++ " " ++ t add s (1, t) = s ++ " " ++ reverse t ws = words $ takeWhile (/= '.') x
Somewhat obfuscated C++ version:
#include<iostream> #include<stack> #define _ cout<< #define ___ cin int main( ){using namespace std;char _l,l_; bool __=1,l=0;stack<char>_l_ ;while(!l){_l= ___.get(); switch( _l){case'.':l=1;case' ': __=!__;while(!_l_.empty()){_ _l_.top();_l_. pop();}_ _l;while(___.peek()==' ') {l_=___. get();_' ';}break; default:if(__) {_l_.push (_l);}else{_ _l;}}}_ endl;}
Scala version in the style of the "Better Haskell version" (ignoring the character-at-a-time requirement):
def cycle[T](seq: Seq[T]) = Stream.continually(seq).flatten // define cycle as per Haskell as Scala does not define it def enumerate[T](words: Seq[T]) = cycle (List(0,1)) zip words def oddwords(input : String) = { def add(stringSoFar : String, wordAndOddIndicator : (Int,String)) = (stringSoFar, wordAndOddIndicator) match { case ("", (_, t)) => t case (s, (0, t)) => s + " " + t case (s, (1, t)) => s + " " + t.reverse } def ws(words : Seq[String]) = words takeWhile ("." !=) // split the string into words up to the first ".", first making sure that "kansas." becomes "kansas ." val words = input.replaceFirst("""\.""", " .").split(" +").toList enumerate(ws(words)).foldLeft("")(add) + "." }
Simple Scala version (ignoring the character-at-a-time requirement):
def oddwords(input : String) = { def reverseOddWords(is: List[String]) : List[String] = { is match { case a :: b :: xs => a :: b.reverse :: reverseOddWords(xs) case a :: xs => a :: reverseOddWords(xs) case xs => xs } } // split the string into words, first making sure that "kansas." always becomes "kansas ." val words = input.replaceFirst("""\.""", " .").split(" +").toList takeWhile("."!=) reverseOddWords(words).mkString(" ") + "." }
Implementation in BrainfuckLanguage (follows character at a time requirement):
+>+<[
>>>+[,[>+>+<<-]>>[<<+>>-] ++++[<-------->-] +<[>-<[-]]> [-<<[<] +<[>->[.>]<[[-]<]<-] >[>[>]<-[[<]>+[>]<-]<[.[-]<]+>]< >>>] <<[>+>+<<-]>>[<<+>>-] ++[<----------------------->-] +<[>-<[-]]> [-<<[<] +<[>->[.>]<[[-]<]<-] >[>[>]<-[[<]>+[>]<-]<[.[-]<]>] <<-->]<+]]