Reverse Vowels
June 4, 2019
Our definition of vowel is simplistic:
(define (vowel? c) (member (char-downcase c) '(#\a #\e #\i #\o #\u)))
We make two passes over the input, collecting vowels on the first pass (in filter
and rewriting on the second pass (in loop
):
(define (reverse-vowels str) (let* ((cs (string->list str)) (vs (reverse (filter vowel? cs)))) (let loop ((cs cs) (vs vs) (zs (list))) (cond ((null? cs) (list->string (reverse zs))) ((vowel? (car cs)) (let ((f (if (char-upper-case? (car cs)) char-upcase char-downcase))) (loop (cdr cs) (cdr vs) (cons (f (car vs)) zs)))) (else (loop (cdr cs) vs (cons (car cs) zs)))))))
Here are our two examples:
> (reverse-vowels "HELLO world") "HOLLO werld" > (reverse-vowels "Programming PRAXIS") "Prigramming PRAXOS"
The student who asked the question was trying to solve the problem in a single pass using two pointers, one traversing the string left-to-right and the other traversing the string right-to-left, but got confused. I think the two-pass approach is simpler and leads to code that is more obviously correct. Here is my version of the student’s algorithm, which demonstrates a different way to handle the case-correction part of the task:
(define (reverse-vowels str) (define (fix-case x y) (if (char-upper-case? x) (char-upcase y) (char-downcase y))) (let loop ((lo 0) (hi (- (string-length str) 1))) (cond ((< hi lo) str) ((and (vowel? (string-ref str lo)) (vowel? (string-ref str hi))) (let ((temp (string-ref str lo))) (string-set! str lo (fix-case temp (string-ref str hi))) (string-set! str hi (fix-case (string-ref str hi) temp))) (loop (+ lo 1) (- hi 1))) ((not (vowel? (string-ref str lo))) (loop (+ lo 1) hi)) ((not (vowel? (string-ref str hi))) (loop lo (- hi 1))) (else (loop (+ lo 1) (- hi 1))))))
And here again are our two examples:
> (reverse-vowels "HELLO world") "HOLLO werld" > (reverse-vowels "Programming PRAXIS") "Prigramming PRAXOS"
You can run the program at https://ideone.com/12nlr2.
I decided to use a functional style instead of the perhaps more
obvious in-place replacement of characters in an array. My program
(written without peeking at the solution) ended up being almost the
same as the first one by programmingpraxis, except for the slight
optimization of avoiding a couple of reverses. Here it is for
completeness sake.
Mumps version
A Haskell version.
Klong version
Rust version:
Playground link https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=60f83463ee1eca11e929173b886da670
Rust version:
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=60f83463ee1eca11e929173b886da670
Rust version without custom iterator
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=54bac1b236904a178f7eb8ba8e5714e8
Here’s a solution in Python.
Output:
LOCOMOTIVE BASIC
10 REM Reverse Vowels by SRS 05.03.2020
20 MODE 2
30 PRINT “Please enter a string; this program will then reverse the vowels in that string,”:PRINT “maintaining the original capitalisation of the vowels.”
40 PRINT
50 INPUT”Your String:”,s$
60 FOR i=LEN(s$) TO 1 STEP -1:c$=MID$(s$,i,1):IF INSTR(“aeiouAEIOU”,c$) THEN rv$=rv$+c$
70 NEXT
80 FOR i=1 TO LEN(s$):c$=MID$(s$,i,1):IF INSTR(“aeiou”,c$) THEN rs$=rs$+LOWER$(LEFT$(rv$,1)):rv$=RIGHT$(rv$,LEN(rv$)-1):GOTO 110
90 IF INSTR(“AEIOU”,c$) THEN rs$=rs$+UPPER$((LEFT$(rv$,1))):rv$=RIGHT$(rv$,LEN(rv$)-1):GOTO 110
100 rs$=rs$+c$
110 NEXT
120 PRINT “My Output: “;rs$