未折叠数字


72

任务

给定一串英文数字名称,它们“一起折叠”,如下所示:

zeronineoneoneeighttwoseventhreesixfourtwofive

将字符串拆分回数字:

zero nine one one eight two seven three six four two five

规则

  • 输入始终是字符串。它始终由一个或多个小写的英文数字名称组成,折叠在一起,仅此而已。

    • 英文数字名称为zero one two three four five six seven eight nine
  • 输出可以是字符串列表,也可以是新字符串,其中的数字由非字母,非空字符串分隔。(您的输出也可以选择在开头或结尾处包含这样的字符串,并且分隔符不必保持一致。因此,即使这样,{{ zero0one$$two );也是有效的答案(如果很荒谬)zeroonetwo。)

  • 以字节为单位的最短答案将获胜。

测试用例

three -> three
eightsix -> eight six
fivefourseven -> five four seven
ninethreesixthree -> nine three six three
foursixeighttwofive -> four six eight two five
fivethreefivesixthreenineonesevenoneeight -> five three five six three nine one seven one eight
threesevensevensixninenineninefiveeighttwofiveeightsixthreeeight -> three seven seven six nine nine nine five eight two five eight six three eight
zeroonetwothreefourfivesixseveneightnine -> zero one two three four five six seven eight nine

28
这是一个巨大的挑战!这项任务非常容易理解和验证,但是正确的使用方法并不是很明显。选择正确的方法可能会在得分上产生巨大差异。+1 :)
DJMcMayhem

1
在考虑了这一点之后,我想起了无政府状态高尔夫方面的一个类似但更简单的挑战:!它引发了一些惊人的C答案。我希望很快能看到其中之一:)
Lynn

我认为我的C答案不符合这样的条件,但是希望这是其他比我更幽默的人的起点。
Michael Dorgan

我很确定我也遇到过同样的挑战,但是您应该在其中打印实际数字。我几乎可以肯定,您Lynn也发布了该消息。但我丢失了链接,将其连接起来了吗?
魔术章鱼缸

3
@MichaelDorgan(或任何其他C编码器),您可能想看看我在Befunge答案中使用的算法。将其直接转换为C可以得到104字节的解决方案,我认为它胜过所有现有的C答案。我敢打赌,具有更高C高尔夫技能的人可以改善这一点。
James Holderness

Answers:



17

C(gcc)89 80 76 75 72 71 70 69字节

f(char*s){*s&&f(s+printf(" %.*s",""[(*s^s[2])%12],s)-1);}

在线尝试!

(89)归功于gastropner进行XOR哈希处理。
(76)感谢Toby Speight提出的使用第一和第三的想法。
(75)感谢迈克尔·多根'0'48
(72)感谢Michael DorganLynn提供带有控制字符的文字。
(69)感谢林恩x?y:0x&&y

f (char *s) {        /* K&R style implicit return type. s is the input. */
    *s&&f(           /* Recurse while there is input. */
        s+printf(    /* printf returns the number of characters emitted. */
            " %.*s", /* Prefix each digit string with a space. Limit
                      * how many bytes from the string to print out. */
            ""
                     /* Magic hash table, where the value represents
                      * the length of the digit string. The string
                      * is logically equivalent to
                      * "\04\01\05\03\04\05\05\04\04\01\03\03" */
            [(*s^s[2])%12],
                     /* The XOR hash (mod 12) */
            s)       /* The current digit. */
            -1);}    /* Subtract 1 for the space. */

11

Python 2,50个字节

import re
re.compile('..[eox]|[tse]?....').findall

在线尝试!

-3感谢Lynn
-4感谢Uriel答案的正则表达式。


3
真好!import re;re.compile('…').findall应该节省几个字节。我确实希望这会变成正则表达式高尔夫球:)
Lynn

@Lynn等等,等我完成!:-P编辑:实际上是3个字节。
暴民埃里克(Erik the Outgolfer)'17年

@Lynn另外,您应该将其转为代码高尔夫 正则表达式。;)
Erik the Outgolfer

我正在寻找C答案,这将非常有趣!
林恩

9

Befunge,87 85 81 76字节

<*"h"%*:"h"$_02g-v1$,*<v%*93,:_@#`0:~
"@{&ruX;\"00^ !: _>_48^>+:"yp!"*+%02p0

在线尝试!

Befunge没有任何字符串操作指令,因此我们在处理它们时会在遇到的最后三个字符中创建一种哈希。

此哈希本质上是一个三位数字(以104为基数)。每次读取新字符时,我们用104 2修改哈希值以摆脱最旧的字符,将其乘以104以便为新字符腾出空间,然后添加新字符mod 27的ASCII值(以确保它不会溢出)。

为了进行比较,我们将这个值mod 3817写入内存(因此将其截断为8位),从而得到较小的数字,Befunge会更容易处理。然后,我们需要比较的散列为0、38、59、64、88、92、114、117和123。如果它与任何散列都匹配,我们知道我们遇到了一个标记a结束的字符序列。数字,因此我们输出了额外的空间,并将哈希值重置为零。

如果您想知道为什么使用基数104或为什么使用mod 3817,那么这些值是经过精心选择的,因此我们需要比较的哈希列表可以用尽可能少的字节表示。


老实说,在我看来,这就像烤面包。哇。虽然算法描述很好,但我会加以考虑。
Michael Dorgan's

^,我记得看到这个词是mojibake(もじばけ)。您如何找到@JamesHolderness这些数字(基础104,模块3187)?
扎卡里

@Zacharý我写了一个Python脚本,测试了不同的基础和Mod组合,以找到针对所有预期输入运行时可以产生正确结果的组合。一旦知道了哪种组合有效,我便通过Befunge数生成器运行所得的哈希输出,以找出产生最短代码的代码。
James Holderness

6

Java(OpenJDK 8)55 46 43字节

使用Forty3 / FrownyFrog可节省9个字节

多亏了Titus节省了3个字节

s->s.replaceAll("one|tw|th|f|z|s|.i"," $0")

在线尝试!

编辑:感谢您对lambda的欢迎和解释!


3
嗨,欢迎来到PPCG!很好的第一个答案,而且确实有效。这是它的TIO链接。Lambda可以通过多种方式创建。这是另一个TIO,其中包含一些lambda和添加的注释,因此您可以了解如何自己创建它们。(我建议将其拷贝到Eclipse的,所以你可以看到代码的高亮显示。)另外,提示在Java中的高尔夫球场各种语言技巧高尔夫可能是有趣的阅读。入住愉快!:)
Kevin Cruijssen '17

@KevinCruijssen谢谢!老实说,我很惊讶Java比JavaScript短。通常,当我阅读挑战时,JS会短很多。
卡H

JavaScript应该短2个字节(用gregex后缀代替All)。
尼尔

@Neil在这里更长,因为它正在使用f=(s)=>而不是s->,它短了4个字节。
卡H

1
@LucaH-根据FrownyFrog的建议,您可以将几个两个字母的字符串减少为单个字符:z | f | s而不是ze | fo | fi | si | se /
Forty3

6

C(GCC) 179 159 146 139 137 116 107 103 102字节

编辑1 :( 添加了Xcoder先生的建议 -谢谢!-我的宏版本与您的宏大小相同,但我更喜欢您的宏。)

编辑2: 已更改的char个人将与对的调用进行比较strchr()

编辑3: K&R的var声明(Eww!)

编辑4: 当1宏不够时...

编辑5: 使用上述建议的新算法重做。感谢James Holderness提出了这个好主意!

编辑6: 删除了0设置,因为它似乎会自动去那里-所使用的大师级代码高尔夫技术(逗号,printf技巧等)-感谢gastropner

编辑7: 使用memchr并修复了James Holderness指出的错误。

编辑7: 用于&&最终检查以替换?-感谢jxh

c,h;f(char*s){while(c=*s++)putchar(c),h=h%10816*104+c%27,memchr("&;@X\\ru{",h%3817,9)&&putchar(h=32);}

在线尝试!

不打高尔夫球(老实说这还是很打高尔夫球的...)


int c;
int h;
void f(char*s)
{
    while(c=*s++)
        putchar(c),
        h=h%10816*104+c%27,
        memchr("&;@X\\ru{",h%3817,9)?putchar(h=32):1;
}

旧的,直接的grep-esqe解决方案:

#define p putchar
#define q c=*s++
c,x;f(char*s){while(q){p(c);x=strchr("tse",c);p(q);p(q);if(!strchr("eox",c)){p(q);if(x)p(q);}p(' ');}}

旧的,更干净的版本。

// Above code makes a macro of putchar() call.

void f(char *s)
{
    char c;
    while(c = *s++)
    {
        putchar(c);
        int x = strchr("tse", c);

        putchar(*s++);
        putchar(c=*s++);

        if(!strchr("eox", c))
        {
            putchar(*s++);
            if(x)
            {
                putchar(*s++);
            }
        }       
        putchar(' ');
    }
}

在线尝试!


我们可以将putchar等宏化几个字节,但总的来说,如果可能,仍在考虑一种更好的算法。
Michael Dorgan

通过删除一对不必要的括号#defineputchar删除159个字节
Xcoder先生17年

2
有点难看,但136个字节通过使用#define p putchar(代替(注意开括号)。
汤姆·卡彭特

1
109个字节c,h=0;f(char*s){while(c=*s++)putchar(c),h=h%10816*104+c%27,c=h%3817,printf(" "+!(c&&strchr("&;@X\\ru{",c)));}
gastropner

啊,我在下面看到的printf技巧加上一对括号和花括号的删除。启用了大师级代码高尔夫:)
Michael Dorgan

5

JavaScript,66 57 52 44 41字节

s=>s.replace(/one|t[wh]|.i|[fsz]/g," $&")

相当幼稚,但是可以。

FrownyFrog很好地抓住了使用2个字符的可能性..“ 1”除外,其中纯2个字符的校验可能会弄乱零值。编辑:单打fsFrownyFrog的好收获,我忽略了我的前两场高尔夫。

感谢Neil,建议使用未命名的lambda,并且能够将单个char用作z52。

Titus提供了一个较小的RegEx。我觉得我们最终将走向Uriel的正则表达式。


如果您使用两个字符并按“ on”到底,是否会中断?
FrownyFrog

我在想z|tw|th|f|s|ei|ni|on
FrownyFrog

1
@FrownyFrog o首先出现,因此被首先认可。
Uriel's

1
on|t[wh]|.i|[fsz](-4个字节)
Titus

2
@Titus-不幸的是,on|将匹配zeronine渲染zer onine
Forty3


5

C,103 99字节

char*r="f.tzuonresn.xgv";f(char*s){*s&&f(s+printf("%.*s ",(strrchr(r,s[2])-strchr(r,*s))%10,s)-1);}

这适用于任何字符编码(包括笨拙的EBCDIC等),因为它不使用输入字符的数值。而是在魔术字符串中定位第一个和第三个字母。它们之间的距离表示每次打印要前进多少个字母。

测试程序

#include <stdio.h>
int main(int argc, char **argv)
{
    for (int i = 1;  i < argc;  ++i) {
        f(argv[i]);
        puts("");
    }
}

1
可以使用递归保存一些字节:tio.run
##






3

果冻 23  21 字节

ḣ3OP%953%7%3+3ɓḣṄȧṫḊÇ

完整程序打印的换行分隔输出。注意:一旦完成,它会重复“永远”打印空行(直到较大的递归限制或段错误)

在线尝试!(TIO输出是累积的,本地实现将逐行打印)

怎么样?

从字符列表开始,程序反复:

  1. 使用一些序数数学来找到字符列表中第一个单词的长度;
  2. 打印单词加上换行符;和
  3. 从字符列表的开头删除单词

通过检查当前字符列表的前三个字符(必要时是第一个单词的一部分)来确定第一个单词的长度。程序将这些转换为普通数,将它们相乘,将结果乘以953,对结果乘以7,对结果乘以3,再加上三个:

word   head3  ordinals       product  %953  %7  %3  +3 (=len(word))
zero   zer    [122,101,114]  1404708   939   1   1   4
two    two    [111,110,101]  1233210    28   0   0   3
one    one    [116,119,111]  1532244   773   3   0   3
three  thr    [116,104,114]  1375296   117   5   2   5
four   fou    [102,111,117]  1324674     4   4   1   4
five   fiv    [102,105,118]  1263780   102   4   1   4
six    six    [115,105,120]  1449000   440   6   0   3
seven  sev    [115,101,118]  1370570   156   2   2   5
eight  eig    [101,105,103]  1092315   177   2   2   5
nine   nin    [110,105,110]  1270500   151   4   1   4

ḣ3OP%953%7%3+3ɓḣṄȧṫḊÇ - Main link, list of characters           e.g. "fiveeight..."
ḣ3              - head to index three                                "fiv"
  O             - ordinals                                           [102,105,118]
   P            - product                                            1263780
    %953        - modulo by 953                                      102
        %7      - modulo by seven                                    4
          %3    - modulo by three                                    1
            +3  - add three                                          4

              ɓ - dyadic chain separation swapping arguments...
... ḣṄȧṫḊÇ ...
    ḣ         - head to index                                        "five"
     Ṅ        - print the result plus a line-feed and yield the result
       ṫ      - tail from index                                      "eeight..."
      ȧ       - and (non-vectorising)                                "eeight..."
        Ḋ     - dequeue                                               "eight..."
         Ç    - call the last link (Main*) as a monad with this as input
              -       * since it's the only link and link indexing is modular.

1
我不确定是否允许这样做。(严重的是,当两个大大提高评价的元答案彼此相反时,您会怎么做?)
ØrjanJohansen

OP明确声明“您的输出也可以选择在开头或结尾处包含此类字符串”,并且该程序实际上随其进行打印,因此无论如何都必须在强制终止之前生成输出。
乔纳森·艾伦

可以,但是我不认为OP被​​认为是无限的结尾字符串。元问题明确地涉及首先打印输出的情况。
与Orjan约翰森

我认为它符合要求的精神(例如,如果打印出无限的空字符串,然后我可能会争辩说没有的话)
Jonathan Allan

因此,我想这使我进入了马丁的阵营“如果它是一个程序并且可以证明……” :)
乔纳森·艾伦

3

C 168145144,141字节

编辑:尝试将init'i'设为1,如下所示

a,b; main(i)

摆脱领先的空格,
但它会在以三,七或八开始的输入时中断

141

#define s|a%1000==
a,i;main(b){for(;~scanf("%c",&b);printf(" %c"+!!i,b),a|=b%32<<5*i++)if(i>4|a%100==83 s 138 s 116 s 814 s 662 s 478)a=i=0;}

在线尝试

144

a,i;main(b){for(;~(b=getchar());printf(" %c"+!!i,b),a=a*21+b-100,++i)if(i>4|a==204488|a==5062|a==7466|a==23744|a==21106|a==6740|a==95026)a=i=0;}

在线尝试

168

i,a;main(b){for(;~scanf("%c",&b);printf(" %c"+!!i,b),a|=b<<8*i++)if(i>4|a==1869768058|a==6647407|a==7305076|a==1920298854|a==1702259046|a==7891315|a==1701734766)a=i=0;}

在线尝试!

不打高尔夫球

i,a;main(b){
for(;~scanf("%c",&b); // for every char of input
printf(" %c"+!!i,b), // print whitespace if i==0 , + char
a|=b<<8*i++ // add char to a for test
)
if(
i>4| // three seven eight
a==1869768058|      // zero
a==6647407|        // one
a==7305076|       // two
a==1920298854|   //four
a==1702259046|  //five
a==7891315|    //six
a==1701734766 //nine
) a=i=0; //reset i and a
}

通过移动a << 8
可以使int常量变得不必要的大,但如果可以以某种方式与字符串进行比较,则它应该是最自然的

146使用字符串比较

#define s|a==*(int*)
a,b;main(i){for(;~(b=getchar());printf(" %c"+!!i,b),a|=b<<8*i++)if(i>4 s"zero"s"one"s"two"s"four"s"five"s"six"s"nine")a=i=0;}

使用字符串比较

迷惑

#define F(x)if(scanf(#x+B,&A)>0){printf(#x,&A);continue;}
B;A;main(i){for(;i;){B=1;F(\40e%4s)F(\40th%3s)F(\40se%3s)F(\40o%2s)B=2;F(\40tw%1s)F(\40si%1s)B=1;F(\40%4s)i=0;}}


2

相当长的一个。欢迎您将它打下来。

R,109位元组

function(x)for(i in utf8ToInt(x)){F=F+i;cat(intToUtf8(i),if(F%in%c(322,340,346,426,444,448,529,536,545))F=0)}

在线尝试!


有什么办法使用unicode字符而不是数字?
Michael Dorgan's

不错的应用intToUtf8!通过使用正则表达式的另一种方法,可以使用90个字节:function(x,p=paste,z=p("(",p(c("zero",broman::numbers),collapse="|"),")"))gsub(z,"\\1 ",x)
Michael M

2

Haskell,81个字节

f[c]=[c]
f(h:t)=[' '|s<-words"z one tw th f s ei ni",and$zipWith(==)s$h:t]++h:f t

在线尝试!

说明:

f(h:t)=                      h:f t -- recurse over input string
   [' '|s<-               ]++      -- and add a space for each string s
      words"z one tw th f s ei ni" -- from the list ["z","one","tw","th","f","s","ei","ni"]
      ,and$zipWith(==)s$h:t        -- which is a prefix of the current string

2

Python 3(无正则表达式),85字节

i=3
while i<len(s):
	if s[i-3:i]in'ineiveroneghtwoureesixven':s=s[:i]+' '+s[i:]
	i+=1

在线尝试!


2
欢迎来到PPCG!
Laikoni '17

很好,但是完整的程序必须包含接受输入的代码。
乔纳森·艾伦

因此,作为一个完整的程序104个字节。但是,您可以通过使用保存4 while s[i:],然后通过提交递归将其减少到93个字节lambda(函数只需要返回输出,而不是自己打印输出)。
乔纳森·艾伦,

2

Excel,181字节

=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"z"," z"),"on"," on"),"tw"," tw"),"th"," th"),"f"," f"),"s"," s"),"ei"," ei"),"ni"," ni")

在前面放置一个空格:zontwthfseini


2

Z80汇编,46 45字节

; HL is the address of a zero-terminated input string
; DE is the address of the output buffer

Match5: ldi                                 ; copy remaining characters
Match4: ldi
Match3: ld a,32 : ld (de),a : inc de        ; and add space after a matched word.

Uncollapse:

        ld a,(hl) : ldi : or a : ret z      ; copy first byte (finish if it was zero)
        ex af,af'                           ; and save its value for later.

        ldi : ld a,(hl) : ldi               ; copy second and third bytes

        cp 'e' : jr z,Match3                ; is the third letter 'e' or 'o' or 'x'?
        cp 'o' : jr z,Match3
        cp 'x' : jr z,Match3

        ex af,af'                           ; now look at the first letter

        cp 'e' : jr z,Match5                ; is it 't' or 's' or 'e'?
        sub 's' : jr z,Match5
        dec a : jr z,Match5
        jr Match4

(将Uriel的酷正则表达式适应不符合正则表达式的环境很有趣)。


1

果冻40 39字节

“¢¤Ƙƒ⁺6j¹;Ċ-ḶṃżṃgɼṘƑUẏ{»Ḳe€€@ŒṖẠ€TḢịŒṖK

在线尝试!

这个怎么运作

“¢¤Ƙƒ⁺6j¹;Ċ-ḶṃżṃgɼṘƑUẏ{»Ḳe€€@ŒṖẠ€TḢịŒṖK
“¢¤Ƙƒ⁺6j¹;Ċ-ḶṃżṃgɼṘƑUẏ{»                 = the compressed string of the digit names
                        Ḳ                = split at spaces
                         e€€@ŒṖ          = check whether each member of each partition of the argument is a digit.
                               Ạ€        = A function that checks whether all values of an array are true, applied to each element.
                                 T       = Finds the index of each truthy element 
                                  Ḣ      = Grab the first element, since we have a singleton array
                                    ịŒṖ  = The previous command gives us the index, partition that splits the input into digits. This undoes it and gives us the partition.
                                       K = Join the array of digits with spaces                



1

Python 3,无正则表达式, 83 68 65  63字节

-15感谢Lynn(将其重构为单个函数),
-3感谢Lynn(避免使用更多算术索引到列表中)
...导致另外节省2个字节(避免使用负模数的括号):)

def f(s):h=ord(s[0])*ord(s[1])%83%-7%-3+5;print(s[:h]);f(s[h:])

一个函数,该函数打印用换行符分隔的单词,然后引发IndexError

在线尝试!(禁止例外,以允许测试套件内多次运行)


我稍后会再讨论这个问题,并且意识到这可能是68个字节:def f(s):h=[4,5,3][ord(s[0])*ord(s[1])%83%7%3];print(s[:h]);f(s[h:])
Lynn

哇哦,h(s)h(s)我怎么会没有注意到?谢谢琳!
乔纳森·艾伦,

我不确定如何继续回到这个问题并注意到新事物,但是它h=(ord(s[0])*ord(s[1])%83%7+1)%3+3是65字节!:)
林恩

嘿,谢谢林恩,那也允许再打两个字节!
乔纳森·艾伦,

0

果冻,36个字节

œṣj⁶;$}
W;“€ɗİẒmṫṃ¦¦ạỊɦ⁼Fḷeṭḷa»s2¤ç/

在线尝试!

算法:

for x in ['ze', 'ni', 'on', 'tw', 'th', ...]:
    replace x in input by space+x

我敢打赌,我们可以做得更好。


0

Mathematica,125个字节

(s=#;While[StringLength@s>2,t=1;a="";While[FreeQ[IntegerName/@0~Range~9,a],a=s~StringTake~t++];Print@a;s=StringDrop[s,t-1]])&


在线尝试!

TIO输出有关“ CountryData”(???)的错误消息,
我不知道为什么会这样,但是在Mathematica上进行一切工作都很好



0

q / kdb +,59个 51字节

解:

{asc[raze x ss/:string`z`one`tw`th`f`s`ei`ni]cut x}

例:

q){asc[raze x ss/:string`z`one`tw`th`f`s`ei`ni]cut x}"threesevensevensixninenineninefiveeighttwofiveeightsixthreeeight"
"three"
"seven"
"seven"
"six"
"nine"
"nine"
"nine"
"five"
"eight"
"two"
"five"
"eight"
"six"
"three"
"eight"

说明:

快速解决方案,可能是更好,更可行的方法。

{asc[raze x ss/:string`z`one`tw`th`f`s`ei`ni]cut x} / ungolfed solution
{                                                 } / lambda with implicit x as input
                                             cut x  / cut x at indices given by left
 asc[                                       ]       / sort ascending
                string`z`one`tw`th`f`s`ei`ni        / string list ("z","one",...)
          x ss/:                                    / string-search left with each right
     raze                                           / reduce down list

笔记:

46个字节,进行一些简单的打高尔夫球,用k个电话代替q个电话,但仍然是一个沉重的解决方案。

asc[(,/)x ss/:($)`z`one`tw`th`f`s`ei`ni]cut x:

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.