A Scrambled Words Variant
October 11, 2019
Much of our solution is unchanged from the previous exercise; we use the same method to handle capitalization, and the main processing loop is a simple scan through the string from left to right. But the two middle cond
clauses are more complicated:
(define (scramble str) (let* ((cs (string->list str)) (upper (map char-upper-case? cs)) (cs (map char-downcase cs))) (let loop ((cs cs) (word (list)) (zs (list))) (cond ((null? cs) ; end of input (list->string (map (lambda (u? c) (if u? (char-upcase c) c)) upper (reverse zs)))) ((and ; collect letter into accumulator (pair? zs) (char-alphabetic? (car zs)) (char-alphabetic? (car cs)) (pair? (cdr cs)) (char-alphabetic? (cadr cs))) (loop (cdr cs) (cons (car cs) word) zs)) ((pair? word) ; end of word interior (loop (cddr cs) (list) (append (list (cadr cs)) (list (car cs)) (shuffle word) zs))) (else ; not in a word (loop (cdr cs) word (cons (car cs) zs)))))))
The hardest part was accumulating zs
in reverse; it took three tries to get the append
in the right order. Here’s an example:
> (scramble "Programming Praxis is fun!") "Parnmmrgiog Prixas is fun!"
You can run the program at https://ideone.com/9mJTqV. It is amazing that keeping the first and last letters of a word makes the whole word nearly readable.
Again I’ll perl this – it just needs a tweak to the regular expression.
[soucecode lang=”bash”]
echo ‘Programming Praxis is a FUN thing to do!’ |\
perl -pe ‘s{(?<=[a-z])([a-z]+)(?=[a-z])}{$1^uc$1|join””,map{$->[0]}sort{$a->[1]<=>$b->[1]}map{[$,rand]}split//,uc$1}ieg’
[/sourcecode]
Actually realised I didn’t need to do the split last time and so my previous answer can be shortened.
[soucecode lang=”bash”]
echo ‘Programming Praxis is a FUN thing to do!’ |\
perl -pe ‘s{([a-z]+)}{$1^uc$1|join””,map{$->[0]}sort{$a->[1]<=>$b->[1]}map{[$,rand]}split//,uc$1}ieg’
[/sourcecode]
The only difference between these is the regular expression needed to find interior words … In the former I’m using non-negative-lookbehind “(?<= )” and non-negative-lookahead “(?= )” to strip the first and last letters off the word strings….
Here’s a solution in Python.
Output:
C++ as before. This one uses a better RNG and reads input from std::cin.
A Haskell version. The change is the addition of interiorA and its helper function, surround.