Staircase writing

Write a program or a function that will output a given string in a staircase fashion, writing each part of a word that starts with a vowel one line below the previous part.

For example:

Input: Programming Puzzles and Code Golf

Output: Pr          P           C    G
ogr        uzzl   and  od   olf
amm         es        e
ing


Input

A string containing nothing but letters and spaces.

The string can be passed via STDIN or function arguments or anything equivalent.

Letters can be lowercase or uppercase.

Inputs are always assumed to follow those rules, you don't need to check for incorrect inputs.

Output

Each time a vowel (that is, a, e, i, o, u or y) is encountered in a word, you must output the rest of the word on the next line (the encountered vowel included), at the correct horizontal position. This rule is recursive, which means that if there are n vowels in the word, it will be written on n+1 lines.

• The vowel should be written at the beginning of the next line, and not at the end of the previous line when one is encountered.

• Each word starts on the first line, and should thus be formatted independently from other words. Two words are separated by a space.

• If a word starts with a vowel, you have to write it starting on the second line.

Test cases

• Input: Programming Puzzles and Code Golf

Output:

Pr          P           C    G
ogr        uzzl   and  od   olf
amm         es        e
ing

• Input: The quick brown fox jumps over the lazy dog

Output:

Th  q     br    f   j          th  l    d
e  u      own  ox  umps ov     e  az   og
ick                   er        y

• Input: aeiouy

Output:


a
e
i
o
u
y

• Input: YEAh UppErcAsE VOwEls

Output:

               V
Y    Upp        Ow
E      Erc       Els
Ah       As
E

• Input: If you only knew the power of the Dark Side

Output:

            kn   th  p        th  D    S
If y   onl    ew   e  ow   of   e  ark  id
o     y             er                e
u


Scoring

This is , so the shortest code wins.

• The third output example seems inconsistent with the rule "If a word starts with a vowel, you have to write it starting on the second line." Jul 1 '15 at 15:01
• Y is Y a vowel ? Jul 1 '15 at 15:02
• @JohnE indeed it was, I fixed it. Thanks. Jul 1 '15 at 15:03
• The vowel should be written at the beginning of the next line, and not at the end of the previous line when one is encountered. After some thought, I understand that this means that the move to the next line should happen before the vowel is printed, not after, but it might be worth wording this in a way that is instantly understandable - it took me a while. Jul 1 '15 at 15:09
• Is trailing newlines / spaces allowed? Jul 1 '15 at 15:31

Retina, 504434(+10)32 30 bytes

Thanks to Dennis for saving 14 bytes by using actual control characters.

i[aeiouy]
<VT>$0# +#(\S*)$1<ESC>[A


Based on this answer, I'm using ANSI escape codes to move the terminal cursor vertically. The <ESC> should be replaced with the control character 0x1B, and <VT> with the vertical tab 0x0B. For simpler testing, you can also replace <ESC> with \e, <VT> with \v and feed the output through printf.

For counting purposes, each line goes in a separate file. However, for convenience it's simpler to just paste the code into a single file and invoke Retina with the -s option.

The first replacement surrounds each vowel in \v...#, where the \v shifts the cursor downward and the # is a marker for the second step. The i is Retina's notation for case-insensitive matching.

The second step then repeatedly (+) removes a # from a word and puts a e\[A at the end of the word which shifts the cursor upward. This stops once the string stops changing, i.e. when there are no more # markers in the string.

• You don't need printf. Just replace \e with the ESC byte (0x1b). Jul 1 '15 at 15:41
• @Dennis Oh, that's much better, thank you. Jul 1 '15 at 15:45
• This is so awesome!!! Jul 1 '15 at 17:03
• This answer is why no one takes Retina seriously ;) Jul 2 '15 at 18:24
• @ChristopherWirt Please elaborate :) (Although I would actually be terrified if anyone took Retina seriously.) Jul 2 '15 at 20:42

CJam, 39 36 bytes

0000000: 6c 7b 5f 65 6c 22 61 65 69 6f 75 79 22  l{_el"aeiouy"
000000d: 26 7b 22 1b 5b 41 22 27 0b 6f 5c 7d 26  &{".[A"'.o\}&
000001a: 5f 53 26 7b 5d 7d 26 6f 7d 2f           _S&{]}&o}/


The above is a reversible xxd dump, since the source code contains the unprintable character VT (code point 0x0b) and ESC (code point 0x1b).

Like this answer, it uses vertical tabs and ANSI escape sequences.

This requires a supporting video text terminal, which includes most non-Windows terminal emulators.

Test run

Before executing the actual code, we'll disable the prompt and clear the screen.

$PS1save="$PS1"
$unset PS1$ clear


This makes sure the output is shown properly.

echo -n Programming Puzzles and Code Golf | cjam <(xxd -ps -r <<< 6c7b5f656c226165696f757922267b221b5b4122270b6f5c7d265f53267b5d7d266f7d2f)
Pr          P           C    G
ogr        uzzl   and  od   olf
amm         es        e
ing


To restore the prompt, execute this:

000000e: 65 69 6f 75 79 5d 2f 0b 24 26 2f 67 69     eiouy]/.$&/gi  The above is a reversible xxd dump, since the source code contains the unprintable character VT (code point 0x0b) and ESC (code point 0x1b). The code is 27 bytes long and requires the switches 040p (4 bytes). The program requires a video text terminal that supports vertical tabs and ANSI escape sequences, which includes most non-Windows terminal emulators. Test run Before executing the actual code, we'll disable the prompt and clear the screen. $ PS1save="$PS1"$ unset PS1
$clear  This makes sure the output is shown properly. echo -n Programming Puzzles and Code Golf | perl -040pe "$(xxd -ps -r <<< 245c3d221b5b41227820732f5b6165696f75795d2f0b24262f6769)"
Pr          P           C    G
ogr        uzzl   and  od   olf
amm         es        e
ing


To restore the prompt, execute this:

PS1="$PS1save"  How it works • perl -040p automatically reads the input as space-separated tokens (-040), saves each token in $_ (-p) and executes the program.

• s/[aeiouy]/.$&/gi performs a global, case-insensitive search in $_ for vowels and replaces each vowel by the control character VT (moves the cursor down), followed by the vowel itself.

• s returns the number of replacements it made, so $\=".[A"x s... saves multiple copies of the byte sequence 1b 5b 41 (moves the cursor up) in $\, one for each vowel.

• At the end of the program, Perl automatically prints "$_$\", because of the -p switch.

C, 200 190 bytes

i,j,k,l,M;f(char*s){M=strlen(s)+1;char t[M*M];for(;i<M*M;++i)t[i]=(i+1)%M?32:10;for(i=0;i<M-1;++i)k=(strspn(s+i,"aeiouyAEIOUY")?++j:s[i]==32?j=0:j)*M+i,l<k?l=k:0,t[k]=s[i];t[l+1]=0;puts(t);}


Ungolfed:

i,j,k,l,M;
f(char *s){
M = strlen(s)+1;
char t[M*M];
for(; i<M*M; ++i) t[i] = (i+1)%M ? 32 : 10;
for(i=0; i<M-1; ++i)
k = (strspn(s+i,"aeiouyAEIOUY") ? ++j : s[i]==32 ? j=0 : j) * M + i,
l<k ? l=k : 0,
t[k] = s[i];
t[l+1]=0;
puts(t);
}


It allocates a rectangular buffer (actually square), fills it with spaces and newlines, then traverses the given string. At the end it adds a null character to prevent trailing newlines.

Technically it's not a function since it contains globals; in fact it can't be called more than once (j and l must be 0 at the start). To comply, i,j,k,l,M; could be moved to int i,j=0,k,l=0,M; at the start of the function.

• char*t=malloc(M*M); --> char t[M*M]; and for(i=0;i<M*M;++i) --> for(;i<M*M;++i) Jul 2 '15 at 10:00
• Good catches, edited.
– jcai
Jul 2 '15 at 13:36
• Isn't this C99 only due to char t[M*M]? Jul 31 '17 at 13:42

CJam, 47

Yeah, it's a bit long, but it's not "cheating" with ANSI codes :)

q_{_S&!\el"aeiouy"-!U+*:U}%_0|$])\zff{~@-S@?}N*  Try it online The idea is to calculate a line number for each character (starting at 0, incrementing at vowels and jumping back to 0 at space), and then for each line, repeat the string but replace the characters that have a different line number with a space. K, 817270 66 bytes Well, it's a start: 0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/{+\{12>"aeiouyAEIOUY"?x}'x}'(0,&~{" "?x}'x)_ x}  Usage Examples:  0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/{+\{12>"aeiouyAEIOUY"?x}'x}'(0,&~{" "?x}'x)_ x} "Programming Puzzles and Code Golf" Pr P C G ogr uzzl and od olf amm es e ing 0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/{+\{12>"aeiouyAEIOUY"?x}'x}'(0,&~{" "?x}'x)_ x} "YEAh UppErcAsE VOwEls" V Y Upp Ow E Erc Els Ah As E  Edit 1: Better. Made some surface level improvements: 0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/{+\{12>"aeiouyAEIOUY"?x}'x}'(0,&~{" "?x}'x)_ x} 0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/(+\12>?["aeiouyAEIOUY"]')'_[0,&" "=x]x}  Notably, I inverted the arguments for ? when I perform the vowel search and thus eliminated the need for a lambda, did the same inversion with _ where I split words on whitespace, and I realized that ~{" "?x}'x is a really silly, overcomplicated way of saying " "=x. Edit 2: Another surface level tweak- negate s before applying it to the lambda, saving parens inside: 0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/(+\12>?["aeiouyAEIOUY"]')'_[0,&" "=x]x} 0:{+{z!y,x#" "}[|/s].'x,'-s:,/(+\12>?["aeiouyAEIOUY"]')'_[0,&" "=x]x}  Edit 3: OK, let's take a different approach to calculating the offset for each character. Instead of splitting the sequence at spaces and calculating a running sum (+\) of the positions of vowels, we can operate on the whole input string in one pass, multiplying the running sum by 0 whenever we encounter a space. I need the negation of this sequence, so I can subtract instead of adding as I scan and use number-of-distinct (#?) instead of max (|/) when I calculate the amount of vertical padding. 0:{+{z!y,x#" "}[|/s].'x,'-s:,/(+\12>?["aeiouyAEIOUY"]')'_[0,&" "=x]x} 0:{+{z!y,x#" "}[#?s].'x,'s:1_0{(~" "=y)*x-12>"aeiouyAEIOUY"?y}\x}  That saves another 4 characters. Phew! Ruby: 135131124115 112 characters a=[] y=l=0 gets.split(r=/(?=[aeiouy ])/i).map{|w|w=~r&&y+=1 w<?A&&y=0 a[y]='%*s%s'%[-l,a[y],w] l+=w.size} puts a  Sample run: bash-4.3$ ruby staircase.rb <<< 'Programming Puzzles and Code Golf'
Pr          P           C    G
ogr        uzzl   and  od   olf
amm         es        e
ing

• If I'm not mistaken, you can shorten your regex to /(?=[aeiouy ])/i. Jul 1 '15 at 15:49
• Ah, you are right @AlexA. The space as separate word was only important for an earlier theory. Thanks. Jul 1 '15 at 16:06

C, 192 bytes

f(char*s){int l=0,r=1,v,c;for(;r;l=1){v=l;r=0;char*p;for(p=s;*p;++p){c=*p;if(c==' ')v=l,putchar(c);else if((strchr("aoeuiyAOEUIY",c)?--v:v)<0)r=1,putchar(' ');else*p=' ',putchar(c);}puts(p);}}


This iterates through the string, blanking characters as it prints them. It repeats until there are no non-space characters left to print. It's portable C, making no assumptions about character encoding.

f(char *s) {
int l=0,       /* true if we've done the first line (no vowels) */
r=1,       /* true if characters remain in buffer */
v,         /* how many vowels to print from current word */
c;         /* current character value */
for (l=0; r; l=1) {
v = l;
r = 0;
char *p;
for (p=s;*p;++p) {
c=*p;
if (c==' ') {       /* a space - reset vowel counter */
v=l;
putchar(c);
} else if ((strchr("aoeuiyAOEUIY",c)?--v:v)<0) {
/* vowel conter exceeded - print a space */
putchar(' ');
r=1;
} else {
/* print it, and obliterate it from next line of output */
putchar(c);
*p=' ';
}
}
puts(p); /* p points at the NUL, so this just prints a newline */
}
}

• ' ' --> 32 and f(char*s){int l=0,r=1,v,c; --> l,r=1,v,c;f(char*s){ Jul 2 '15 at 10:03
• @Cool - ' ' may be 32, but it depends on the character encoding, and as I said, I made this portable C. Dropping the explicit int is great, though - not sure why I forgot that! Jul 2 '15 at 10:08

Python 3, 265207202185 177 characters

i=input()
w,e=i.split(" "),lambda:[[" "]*len(i)]
o,x=e(),0
for p in w:
y=0
for c in p:
if c in"AEIOUYaeiouy":o+=e();y+=1
o[y][x],x=c,x+1
x+=1
for l in o:print("".join(l))


This is terrible and I'm not proud. I know this can be made shorter, but I thought I'd post anyway.

Inspired by the C version, it creates a list which is then filled while traversing the input string.

GNU Sed, 151 + 1

(+1 as it needs the -r flag)

s/^/ /;h;s/[aoeuiy]/_/ig;:a;s/_[^ _]/__/;ta;y/_/ /;g;:x;:b;s/ [^ aoeuiy]/  /i;tb;h;s/([^ ])[aoeuiy]/\1_/ig;:c;s/_[^ _]/__/;tc;y/_/ /;g;s/ [^ ]/  /ig;tx


I thought that sed would be the tool for this job, but found it surprisingly hard.

#!/bin/sed -rf

# make sure the string starts with a space
s/^/ /
h

# print leading consonants, if any
s/[aoeuiy]/_/ig
:a
s/_[^ _]/__/
ta
y/_/ /
p
g

:x
# strip the consonants just printed
:b
s/ [^ aoeuiy]/  /i
tb
h

s/([^ ])[aoeuiy]/\1_/ig
:c
s/_[^ _]/__/
tc
y/_/ /
p
g
# remove leading vowel of each word
s/ [^ ]/  /ig
tx

• I'm afraid, that should be 128 characters. The one-line version is missing a p, so it outputs nothing. A small issue is that outputs starts with an extra space. A huge issue is that first piece of text starting with vowel disappears. Jul 2 '15 at 8:27
• I'm sure it was working earlier. I'll have a look and see what I've broken. Thanks for the heads-up, @manatwork! Jul 2 '15 at 9:48
• I was wrong to jump into loop c, due to the line just before tx. I've reinstated an earlier version with its similar loop, and I'll have another attempt later. Jul 2 '15 at 10:16

Python 2, 145 142 Bytes

Probably isn't as competitive as some other methods, but I thought this was a cool way of using regex.

import re;s=I=input()[::-1]+" ";i=0
while s.strip()or i<2:s=re.sub("(?!([^aeiouy ]*[aeiouy]){%s}[^aeiouy]* )."%i," ",I,0,2)[::-1];print s;i+=1


The regex (?!([^aeiouy ]*[aeiouy]){N}[^aeiouy]* ). matches any single character not within the N-th group of letters from the end of a word. Since it counts from the end of the world I reverse the string before and afterward, and I also have to add a space at the end, but after that it becomes a simple matter of using re.sub to replace every instance of these characters with a space. It does this for every value of N until the string is empty.

• As nice and readable it is to use re.I, you can save 3 bytes by substituting the appropriate flag value, i.e. 2. Jul 4 '15 at 7:09
• @Sp3000 Only in code-golf do have negative associations with "nice and readable"
– KSab
Jul 4 '15 at 7:16

Octave, 132 129 characters

p=1;x=[];y=input(0);for j=1:numel(y);if regexpi(y(j),'[aeiouy]');p+=1;elseif y(j)==" ";p=1;end;x(p,j)=y(j);end;x(x==0)=32;char(x)


Test

Input: "YEAh UppErcAsE VOwEls"

Output:

               V
Y    Upp        Ow
E      Erc       Els
Ah       As
E


Gema: 53 48 characters

/[aeiouyAEIOUY]/=@append{u;^[[A}^K$1 =$u@set{u;}


Note that ^[ (x1b) and ^K (x0b) are single characters. (In the below sample run I use their copy-paste friendly \e and \v equivalents, in case you want to try it out.)

Sample run:

bash-4.3$gema '/[aeiouyAEIOUY]/=@append{u;\e[A}\v$1; = $u@set{u;}' <<< 'Programming Puzzles and Code Golf' Pr P C G ogr uzzl and od olf amm es e ing  Jelly, 42 bytes (non-competing?) Ḳµe€Øyœṗ⁸⁶ṁ$;¥\z⁶Zµ€µḷ/⁶ṁW⁸;ḣ®µ€L€Ṁ©\$¡ZK€Y
`

Try it online!

Why Jelly, why? :-(

• Longer than CJam seems weird Jul 31 '17 at 17:08
• @Fatalize It's because Jelly just doesn't go with strings...usually. Also you can't really compare different programming paradigms (cjam is stack-based, jelly is tacit). Jul 31 '17 at 17:34