楼梯写作


35

编写一个程序或函数,该程序或函数将以阶梯形式输出给定的字符串,并将以元音开头的单词的每个部分写在上一个部分的下一行。

例如:

Input: Programming Puzzles and Code Golf


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

输入值

一个仅包含字母和空格的字符串。

可以通过STDIN或函数参数或任何等效参数传递字符串。

字母可以是小写或大写。

始终假定输入遵循这些规则,您无需检查输入是否不正确。

输出量

元音(即,每一次aeiouy)在遇到这个词,你必须输出到下一行(包括遇到元音)字的其余部分,在正确的水平位置。该规则是递归的,这意味着如果单词中有n个元音,它将被写在n + 1行上。

  • 元音应该写在下一行的开头,而不是在遇到前一行的末尾。

  • 每个单词都从第一行开始,因此应独立于其他单词设置格式。两个词用空格隔开。

  • 如果单词以元音开头,则必须从第二行开始写出来。

测试用例

  • 输入: Programming Puzzles and Code Golf

输出:

Pr          P           C    G
  ogr        uzzl   and  od   olf
     amm         es        e
        ing
  • 输入: The quick brown fox jumps over the lazy dog

输出:

Th  q     br    f   j          th  l    d
  e  u      own  ox  umps ov     e  az   og
      ick                   er        y
  • 输入: aeiouy

输出:

 
a
 e
  i
   o
    u
     y
  • 输入: YEAh UppErcAsE VOwEls

输出:

               V
Y    Upp        Ow
 E      Erc       Els
  Ah       As  
             E
  • 输入: If you only knew the power of the Dark Side

输出:

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

计分

这是,因此最短的代码获胜。


第三个输出示例似乎与以下规则不一致:“如果单词以元音开头,则必须从第二行开始编写它”。
JohnE

1
Y是Y是元音吗?
Optimizer

1
@JohnE确实是,我已修复它。谢谢。
致命

2
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.经过一番思考,我了解到这意味着移至下一行应该在元音打印之前进行,而不是在之后进行,但是值得以一种可以立即理解的方式来措辞,这花了我一段时间。
trichoplax

3
是否允许尾随换行符/空格?
Loovjo

Answers:


18

视网膜50 44 34 (+10) 32 30字节

感谢Dennis通过使用实际控制字符节省了14个字节。

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

基于此答案,我正在使用ANSI转义码垂直移动终端光标。在<ESC>应与控制字符0x1B替换,并且<VT>与垂直制表0x0B。对于比较简单的测试,你也可以替换<ESC>\e<VT>\v,并通过饲料输出printf

为了进行计数,每一行都放在一个单独的文件中。但是,为方便起见,只需将代码粘贴到单个文件中,然后使用-s选项调用Retina更为简单。

第一个替换环绕着中的每个元音\v...#,其中\v将光标向下移动,并且#是第二步的标记。该i`是视网膜的符号来区分大小写的匹配。

然后,第二步重复(+`#从单词中删除a 并将a e\[A放在单词的末尾,从而使光标向上移动。一旦字符串停止更改,即当字符串中不再有#标记时,此操作将停止。


您不需要printf。只需替换\e为ESC字节(0x1b)。
丹尼斯

@丹尼斯哦,这要好得多,谢谢。
Martin Ender

1
太棒了!!!
kirbyfan64sos

这个答案就是为什么没人会认真对待视网膜;)
Christopher Wirt

@ChristopherWirt请详细说明一下:)(虽然如果有人我真的胆寒视网膜严重。)
马丁安德

8

CJam,39 36字节

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}/

上面是可逆的xxd转储,因为源代码包含不可打印字符VT(代码点0x0b)和ESC(代码点0x1b)。

这个答案一样,它使用垂直制表符和ANSI转义序列

这需要支持的视频文本终端,其中包括大多数非Windows终端模拟器。

测试运行

在执行实际代码之前,我们将禁用提示并清除屏幕。

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

这样可以确保输出正确显示。

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

要恢复提示,请执行以下操作:

PS1="$PS1save"

怎么运行的

我们在每个元音之前插入一个垂直制表符以向下移动光标,并在每个空格之后插入足够的字节序列1b 5b 41"\e[A")的副本以将光标移回到第一行。

l           e# Read a line from STDIN.
{           e# For each character C:
  _el       e#   Push lowercase(C).
  "aeiouy"& e#   Intersect with "aeiouy".
  {         e#   If the intersection is non-empty:
    ".[A"   e#     Push "\e[A" (will be printed later).
    '.o     e#     Print "\v".
    \       e#     Swap "\e[A" with C.
  }&        e#
  _S&       e#   Intersect C with " ".
  {         e#   If the intersection is non-empty:
    ]       e#     Wrap the entire stack in an array.
  }&
  o         e#   Print C or the entire stack.
}/          e#

不要忘记unset PS1save以后。
usandfriends

5

Java,428个字节

void s(String s){int l=s.length(),m=0;char[][]c=new char[l][];for(int i=0;i<c.length;java.util.Arrays.fill(c[i++],' '))c[i]=new char[l];String v="aeiouyAEIOUY";String[]a=s.split(" ");for(int r=0,p=0;r<a.length;r++){String u=a[r]+" ";int o=v.indexOf(u.charAt(0))>=0?1:0,x=p;for(;x<u.length()-1+p;o+=v.indexOf(u.charAt(x++-~-p))>=0?1:0)c[o][x]=u.charAt(x-p);p+=u.length();m=m<o?o:m;}for(int i=0;i<=m;i++)System.out.println(c[i]);}

我知道,这太可怕了。可能有一些字符可以刮掉,但是我懒得这么做。


你也许可以宣告你的很多的int变量(即irpo,和x),您初始化lm,因为他们会在稍后给出的值。您也可以String v="...",a[]=...;针对进行与上述相同的操作String u。那会大大降低你的分数。
TNT

我喜欢x++-~-p
Ypnypn

4

Perl,31个字节

0000000: 24 5c 3d 22 1b 5b 41 22 78 20 73 2f 5b 61  $\=".[A"x s/[a
000000e: 65 69 6f 75 79 5d 2f 0b 24 26 2f 67 69     eiouy]/.$&/gi

上面是可逆的xxd转储,因为源代码包含不可打印字符VT(代码点0x0b)和ESC(代码点0x1b)。

该代码长27个字节,需要切换040p(4个字节)。

该程序需要一个视频文本终端,该终端支持垂直制表符和 ANSI转义序列,其中包括大多数非Windows终端模拟器。

测试运行

在执行实际代码之前,我们将禁用提示并清除屏幕。

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

这样可以确保输出正确显示。

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

要恢复提示,请执行以下操作:

PS1="$PS1save"

怎么运行的

  • perl -040p自动将输入作为空格分隔的标记(-040)读取,将每个标记保存在$_-p)中并执行程序。

  • s/[aeiouy]/.$&/gi$_对元音执行全局,不区分大小写的搜索,并将每个元音替换为控制字符VT(向下移动光标),然后替换为元音本身。

  • s返回其进行的替换次数,因此$\=".[A"x s...将字节序列1b 5b 41的多个副本(将光标向上移动)保存在中$\,每个元音一个。

  • 在程序结束时"$_$\",由于-p切换,Perl自动打印。


4

C,200个 190字节

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);}

取消高尔夫:

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);
}

它分配一个矩形缓冲区(实际上是正方形),用空格和换行符填充它,然后遍历给定的字符串。最后,它添加一个空字符以防止尾随换行符。

从技术上讲,它不是函数,因为它包含全局变量。事实上,它不能被称为超过一次(jl必须在开始时为0)。为了遵守,i,j,k,l,M;可以int i,j=0,k,l=0,M;在功能开始时移至。


char*t=malloc(M*M);-> char t[M*M];for(i=0;i<M*M;++i)->for(;i<M*M;++i)
Spikatrix

好收获,编辑。
jcai

这不是C99唯一的原因char t[M*M]吗?
扎卡里

4

CJam,47岁

是的,它有点长,但不是用ANSI代码“欺骗” :)

q_{_S&!\el"aeiouy"-!U+*:U}%_0|$])\zff{~@-S@?}N*

在线尝试

这个想法是计算每个字符的行号(从0开始,以元音递增,然后在空格处跳回0),然后对于每一行,重复该字符串,但用空格替换具有不同行号的字符。


3

K,81 72 70 66字节

好吧,这是一个开始:

`0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/{+\{12>"aeiouyAEIOUY"?x}'x}'(0,&~{"  "?x}'x)_ x}

用法示例:

  `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       

编辑1:

更好。做了一些表面平整的改进:

`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}

值得注意的是,我颠倒了?执行元音搜索时的参数,从而消除了对lambda的需要,_对在空格上分割单词的操作也进行了反演,并且我意识到这~{" "?x}'x是一种非常愚蠢且过于复杂的说法" "=x

编辑2:

s在将其应用到lambda之前,需要对另一个表面级别进行调整,从而将内部的对象保存在内部:

`0:{+{(-z)!y,x#" "}[|/s].'x,'s:,/(+\12>?["aeiouyAEIOUY"]')'_[0,&" "=x]x}
`0:{+{z!y,x#" "}[|/s].'x,'-s:,/(+\12>?["aeiouyAEIOUY"]')'_[0,&" "=x]x}

编辑3:

好的,让我们采用另一种方法来计算每个字符的偏移量。无需在空格处分割序列并计算+\元音位置的运行总和(),我们可以对整个输入字符串进行一次操作,每遇到一个空格,就将运行总和乘以0。我需要否定此序列,因此在我计算垂直填充量时,我可以在进行扫描时减去减法而不是加法,并使用距离数(#?)而不是最大值(|/)。

`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}

这样可以节省另外4个字符。!


2

红宝石:135个 131 124 115 112字符

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

样品运行:

bash-4.3$ ruby staircase.rb <<< 'Programming Puzzles and Code Golf'
Pr          P           C    G
  ogr        uzzl   and  od   olf
     amm         es        e
        ing

如果我没记错的话,可以将regex缩短为/(?=[aeiouy ])/i
Alex A.

啊,你说得对@AlexA。空格作为单独的单词仅对较早的理论很重要。谢谢。
manatwork

2

C,192字节

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);}}

这遍历字符串,在打印字符时将其空白。重复直到没有剩余的非空格字符可打印为止。它是可移植的C,无需假设字符编码。

可读版本

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 */
    }
}

' '-> 32f(char*s){int l=0,r=1,v,c;->l,r=1,v,c;f(char*s){
Spikatrix

@Cool- ' ' 可能32,但是取决于字符编码,正如我说的,我制作了这个便携式C。但是,删除显式int的确很棒-不知道为什么我忘记了!
Toby Speight 2015年

2

Python 3中,265个 207 202 185 177字符

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))

这太糟糕了,我不感到骄傲。我知道可以将其缩短,但我还是想发布。

受C版本启发,它创建一个列表,然后在遍历输入字符串时将其填充。


2

GNU Sed,151 + 1

(+1,因为它需要-r标记)

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

我以为sed将是完成这项工作的工具,但发现它出奇的困难。

可读版本:

#!/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

恐怕应该是128个字符。单行版本缺少p,因此没有输出。一个小问题是输出以额外的空间开头。一个巨大的问题是,以元音开头的第一段文本消失了。
manatwork

我敢肯定它早点工作了。我看一下,看看我坏了什么。感谢您的单挑,@ manatwork!
Toby Speight 2015年

c由于前一行,我跳入循环是错误的tx。我已经恢复了具有类似循环的早期版本,稍后将再次尝试。
Toby Speight 2015年

2

Python 2中,145个 142字节

可能没有其他方法那么有竞争力,但是我认为这是使用正则表达式的一种很酷的方法。

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

正则表达式(?!([^aeiouy ]*[aeiouy]){N}[^aeiouy]* ).匹配任何单个字符从一个字的结束字母第N组内。由于它从世界末日开始计数,因此我在前后前后颠倒了字符串,而且我还必须在末尾添加一个空格,但是在那之后,使用re.sub这些空格替换这些字符的每个实例就变得很简单。它对N的每个值执行此操作,直到字符串为空。


使用起来不错,而且可读性强re.I,可以通过替换适当的标志值(即)来节省3个字节2
Sp3000

1
@ Sp3000只有在代码高尔夫球中,才具有与“漂亮且可读”的负关联
KSab 2015年

1

八度,132129个字符

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)

测试

输入: "YEAh UppErcAsE VOwEls"

输出:

               V     
Y Upp Ow   
 埃尔斯·埃尔斯
  阿        
             Ë       

1

Gema53个48个字符

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

请注意^[(x1b)和^K(x0b)是单个字符。(在下面的示例运行中,如果您想尝试一下,我将使用它们的复制粘贴友好功能\e\v等效功能。)

样品运行:

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 

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.