Номер телефона в произнесенных словах

33

Цель

Напишите программу или функцию, которая переводит числовой номер телефона в текст, который позволяет легко сказать. Когда цифры повторяются, они должны читаться как «двойной n» или «тройной n».

Требования

вход

Строка цифр.

  • Предположим, что все символы представляют собой цифры от 0 до 9.
  • Предположим, строка содержит хотя бы один символ.

Выход

Слова, разделенные пробелами, о том, как эти цифры можно прочитать вслух.

  • Перевести цифры в слова:

    0 "ой"
    1 "один"
    2 "два"
    3 "три"
    4 "четыре"
    5 "пять"
    6 "шесть"
    7 "семь"
    8 "восемь"
    9 "девять"

  • Когда одна и та же цифра повторяется дважды подряд, напишите «двойное число ».

  • Когда одна и та же цифра повторяется трижды подряд, напишите «тройное число ».
  • Когда одна и та же цифра повторяется четыре или более раз, напишите «двойное число » для первых двух цифр и оцените оставшуюся часть строки.
  • Между каждым словом ровно один пробел. Допускается один пробел в начале или в конце.
  • Выходные данные не чувствительны к регистру.

счет

Исходный код с наименьшим количеством байтов.

Тестовые случаи

input        output
-------------------
0123         oh one two three
4554554      four double five four double five four
000          triple oh
00000        double oh triple oh
66667888     double six double six seven triple eight
19999999179  one double nine double nine triple nine one seven nine
Hand-E-Food
источник
38
Любой, кто интересуется «речевым гольфом», должен заметить, что «двойная шестерка» занимает больше времени, чем «шестерка». Из всех имеющихся здесь числовых возможностей только «тройная семерка» сохраняет слоги.
Фиолетовый Р
13
@Purple P: И, как я уверен, вы знаете, «двойной-двойной, двойной-двойной», «всемирная паутина» ..
Час Браун
11
Я голосую за то, чтобы поменять это письмо на «даб».
Hand-E-Food
8
Я знаю, что это только интеллектуальное упражнение, но передо мной стоит счет за газ с номером 0800 048 1000, и я бы прочитал его как «о, восемьсот, четыре, восемь, одна тысяча». Группировка цифр важна для читателей-людей, и некоторые шаблоны, такие как «0800», обрабатываются специально.
Майкл Кей
3
@PurpleP Любой, кто интересуется ясностью речи, тем не менее, особенно при разговоре по телефону, может захотеть использовать «двойную шестерку», поскольку более ясно, что говорящий означает две шестерки и случайно не повторяет цифру 6. Люди не роботы: P
извиниться и восстановить Монику

Ответы:

10

05AB1E , 53 52 51 50 49 байтов

γε€T2äθ¬MÊi¨₃1ǝR]˜“Šç€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š‹¶½¿“#s踻

Попробуйте онлайн!

Объяснение:

γ                      # split input in groups of consecutive equal digits
 ε              ]      # for each group
  €T                   #  add a 10 before each digit (66 -> [10, 6, 10, 6])
    2äθ                #  keep only the second half of that list
       ¬MÊi     ]      #  if the first element is not the maximum
           ¨           #   drop the last element
            ₃1ǝ        #   replace the second element with 95
               R       #   reverse the list
˜                      # flatten
 “...“                 # compressed string: "oh one two ... nine double triple"
      #                # split on spaces
       sè              # index (wraps around, so 95 yields "triple")
         ¸»            # join with spaces
Grimmy
источник
1
О, Mтакже заглядывает в списки при определении максимального целого числа в стеке? Не знал этого. Похоже, что-то вспомнить. :)
Кевин Круйссен
16

8088 Assembly, IBM PC DOS, 164 159 156 155 байт

Binary:

00000000: d1ee 8a0c 03f1 53fd ac3a d075 0343 e2f7  ......S..:.u.C..
00000010: 85db 741c 5f8a d043 f6c3 0174 0a57 bd64  ..t._..C...t.W.d
00000020: 0155 83eb 0374 0957 bd5d 0155 4b4b 75f7  .U...t.W.].UKKu.
00000030: 8ad0 2c2f 7213 518a f0b0 24b1 31bf 6a01  ..,/r.Q...$.1.j.
00000040: fcf2 aefe ce75 fa59 57e2 bc5a 85d2 740c  .....u.YW..Z..t.
00000050: b409 cd21 b220 b402 cd21 ebef c364 6f75  ...!. ...!...dou
00000060: 626c 6524 7472 6970 6c65 246f 6824 6f6e  ble$triple$oh$on
00000070: 6524 7477 6f24 7468 7265 6524 666f 7572  e$two$three$four
00000080: 2466 6976 6524 7369 7824 7365 7665 6e24  $five$six$seven$
00000090: 6569 6768 7424 6e69 6e65 24              eight$nine$

Создайте и протестируйте исполняемый файл, используя xxd -rвыше, или загрузите PHONE.COM .

Несобранный список:

D1 EE       SHR  SI, 1              ; point SI to DOS PSP (80H) for input string
8A 0C       MOV  CL, BYTE PTR[SI]   ; load input string length into CX
03 F1       ADD  SI, CX             ; move SI to end of input 
53          PUSH BX                 ; push a 0 to signal end of output stack 
        CHAR_LOOP:
FD          STD                     ; set LODS direction to reverse 
AC          LODSB                   ; load next char from [SI] into AL, advance SI 
3A D0       CMP  DL, AL             ; is it same as previous char? 
75 03       JNZ  NEW_CHAR           ; if not, it's a different char 
43          INC  BX                 ; otherwise it's a run, so increment run length
E2 F7       LOOP CHAR_LOOP          ; move on to next char 
        NEW_CHAR: 
85 DB       TEST BX, BX             ; is there a run greater than 0? 
74 1C       JZ   GET_WORD           ; if not, look up digit name 
5F          POP  DI                 ; get name for the current digit 
8A D0       MOV  DL, AL             ; save current char in DL 
43          INC  BX                 ; adjust run count (BX=1 means run of 2, etc)
F6 C3 01    TEST BL, 1              ; is odd? if so, it's a triple
74 0A       JZ   IS_DBL             ; is even, so is a double 
57          PUSH DI                 ; push number string ("one", etc) to stack
BD 0164     MOV  BP, OFFSET T       ; load "triple" string 
55          PUSH BP                 ; push to stack 
83 EB 03    SUB  BX, 3              ; decrement run count by 3 
74 09       JZ   GET_WORD           ; if end of run, move to next input char 
        IS_DBL: 
57          PUSH DI                 ; push number string to stack
BD 015D     MOV  BP, OFFSET D       ; load "double" string 
55          PUSH BP                 ; push to stack 
4B          DEC  BX                 ; decrement by 2
4B          DEC  BX
75 F7       JNZ  IS_DBL             ; if not end of run, loop double again 
        GET_WORD: 
8A D0       MOV  DL, AL             ; save current char into DL
2C 2F       SUB  AL, '0'-1          ; convert ASCII char to 1-based index 
72 13       JB   NOT_FOUND          ; if not a valid char, move to next
51          PUSH CX                 ; save outer loop counter 
8A F0       MOV  DH, AL             ; DH is the index to find, use as scan loop counter
B0 24       MOV  AL, '$'            ; word string is $ delimited
B1 31       MOV  CL, 031H           ; search through length of word data (49 bytes)
BF 016A     MOV  DI, OFFSET W       ; reset word data pointer to beginning
FC          CLD                     ; set DF to scan forward for SCAS 
        SCAN_LOOP: 
F2/ AE      REPNZ SCASB             ; search until delimiter '$' is found in [DI]
FE CE       DEC  DH                 ; delimiter found, decrement counter 
75 FA       JNZ  SCAN_LOOP          ; if counter reached 0, index has been found 
59          POP  CX                 ; restore outer loop position
57          PUSH DI                 ; push string on stack 
        NOT_FOUND:
E2 BC       LOOP CHAR_LOOP          ; move to next char in input 
        OUTPUT_STACK: 
5A          POP  DX                 ; get string from top of stack 
85 D2       TEST DX, DX             ; it is the last? 
74 0C       JZ   EXIT               ; if so, exit 
B4 09       MOV  AH, 09H            ; DOS display string function 
CD 21       INT  21H                ; write string to console 
B2 20       MOV  DL, ' '            ; load space delimiter 
B4 02       MOV  AH, 02H            ; DOS display char function 
CD 21       INT  21H                ; write char to console 
EB EF       JMP  OUTPUT_STACK       ; continue looping 
        EXIT: 
C3          RET                     ; return to DOS 

D   DB "double$" 
T   DB "triple"
W   DB "$oh$","one$","two$","three$","four$","five$","six$","seven$","eight$","nine$" 

TL; DR:

Строка ввода читается справа налево, чтобы упростить поиск тройки. Выходные данные помещаются в стек x86, чтобы упростить изменение порядка отображения, а также упростить перестановку «двойных» и «тройных» слов, чтобы предшествовать имени цифры.

Если следующая цифра отличается от последней, имя ищется в списке слов и помещается в стек. Поскольку в машинном коде отсутствует формальная концепция «индексированного массива строк переменной длины», список слов сканируется i(индекс слова) несколько раз, чтобы разделитель строк ( $) находил соответствующее слово. Полезно, что в x86 есть пара коротких инструкций ( REPNZ SCASBчто аналогично memchr()C), что упрощает это (спасибо CISC !).

Если цифра такая же, как и предыдущая, счетчик длины «прогона» увеличивается и продолжает цикл на входе влево. По окончании цикла имя цифры берется из стека, поскольку его нужно будет ставить после «двойного» или «тройного» для каждой группировки. Если длина цикла нечетна (а длина цикла > 1), то имя цифры, за которым следует строка «тройка», помещается в стек, а длина цикла уменьшается на 3. Поскольку длина цикла теперь будет четной, шаг повторяется для «double», пока длина пробега не станет равной 0.

Когда входная строка достигла конца, стек выгружается, и каждая сохраненная строка записывается на экран в обратном порядке.

I / O:

Автономный исполняемый файл для ПК с DOS, ввод из командной строки в консоль.

введите описание изображения здесь

Загрузите и протестируйте PHONE.COM .

640 КБ
источник
repne scasbесть memchr(или strchrесли вы знаете, что будет хит), нет strstr.
Питер Кордес
CH = 0 при входе в процесс гарантируется стандартом, или это то, что делает какая-то версия DOS? Я заметил, вы предполагаете, что mov cl, byte[si] это эквивалентно movzx cx, byte [si]. Интересно, если бы использование другого reg, например AH, для счетчика dec ah / jnzвместо вместо loop, спасло бы что-нибудь от того, что нет необходимости нажимать / вставлять CX. Вероятно, нет, и у вас не осталось 16-битных регистров, которые бы допускали 1 байт dec.
Питер Кордес
1
@PeterCordes, для того, чтобы CH=0я пошел по fysnet.net/yourhelp.htm , который для любого разумного выпуска DOS всегда нулевой, как и в BX. Хорошая мысль о нулевом расширении mov, хотя технически я не думаю, что movzxдоступно на 808x (сохраняя целевую платформу IBM PC 5150 и все). Я возился со всеми регистрами, как мог, чтобы спасти байты, но если вы видите что-то, что я, вероятно, пропустил, пожалуйста, дайте мне знать!
640KB
1
Точнее назвать это memchrИМО. Именование «строковой инструкции» вводит людей в заблуждение, заставляя их думать, что они работают со строками C неявной длины, но в действительности они работают со строками явной длины, такими как std::stringили буферы. Например memcpy, memset(movs / stos), memchr/ memrchr(repne scas с DF = 0 или 1) и memcmp(repeat cmps). Единственный эквивалент C для repe scas- strspnпотому что я не думаю, что для этого есть memфункция. Можно даже описать stoswили stosdкак wmemsetнапример.
Питер Кордес
1
movzxстоит дополнительный байт кода операции, и да, он был введен только с 386. Было проще набрать текст, чтобы описать тот факт, что вы выполняете слияние с младшим байтом и предполагаете, что он правильно расширен на ноль. Если вы знаете CX или хотя бы CH = 0, тогда да, для игры в гольф всегда переходите movк CL. Но вне игры в гольф, идти в байтах нагрузку х86 являются movzxи movsx: они избегают каких - либо ложных зависимостей или другой парциального регистра проделки. На современных процессорах с назначением dword они работают так же быстро, как и dword mov .
Питер Кордес
9

05AB1E , 61 56 53 52 51 байт

γvyDg;LàäRv… ‹¶½¿#yg蓊瀵‚•„í†ìˆÈŒšï¿Ÿ¯¥Š“#yè])áðý

-9 байт благодаря @Grimy .

Попробуйте онлайн или проверьте все контрольные примеры .

Объяснение:

γ               # Split the (implicit) input into substrings of equal adjacent characters
                #  i.e. "199999991779" → ["1","9999999","1","77","9"]
 v              # Loop over each substring `y`:
   Dg           #  Get the length of a copy of the substring
     ;          #  Halve it
      L         #  Create a list in the range [1, length/2], where odd lengths are
                #  automatically truncated/floored
                #   i.e. "1" (length=1) → 0.5 → [1,0]
                #   i.e. "9999999" (length=7) → 3.5 → [1,2,3]
       à        #  Pop and push the maximum of this list
  y     ä       #  Divide the string into that many parts
                #   → ["1"]
                #   → ["999","99","99"]
         R      #  Reverse the list
                #   → ["99","99","999"]
  v             # Inner loop over each item `y`:
    ‹¶½¿       #  Push dictionary word: "  double triple"
         #      #  Split it on spaces: ["","","double","triple"]
          yg    #  Get the length of the current item `y`
            è   #  And use it to (0-based) index into the list
   “Šç€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š“
                #  Push dictionary string "oh two three four five six seven eight nine"
     #          #  Split it on spaces: ["oh","two","three",...,"nine"]
      yè        #  Use `y` to index into the string-list (with automatic wrap-around,
                #  so since there are 10 words, it basically indexes with a single digit
                #  due to an implicit modulo-10)
                #   i.e. "77" → "seven"
 ]              # Close both loops
  )             # Wrap all values on the stack into a list
   á            # Only keep letters, which removes the empty strings from the list
    ðý          # And join the list on spaces
                # (after which the result is output implicitly)

Посмотрите эту подсказку 05AB1E (раздел Как пользоваться словарем? ), Чтобы понять, почему … ‹¶½¿есть " double triple"и “Šç€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š“есть "oh two three four five six seven eight nine".

Кевин Круйссен
источник
1
@Grimy Ах, конечно .. Я добавил, if(length>=4)прежде чем добавить остальные, но, конечно, это не обязательно для целых чисел 1,2,3, потому что ;Å2¨3ª£они оставят строки нетронутыми (просто в любом случае просто обернуты в список, который мы сглаживаем после карты). Спасибо, что заметили! И с нетерпением жду вашего ответа с Åγ. У меня действительно было чувство, что первая часть может быть сделана как-то короче.
Кевин Круйссен
1
Dg;LàäRпо-прежнему на один байт короче āɨšJõK, и гораздо более похож на то, что у вас было изначально.
Grimmy
1
@ Грими А, это действительно закрыто от того, что у меня изначально было, мне это нравится. :) Еще раз спасибо!
Кевин Круйссен
1
@ Грими смог найти себе еще один гольф, о котором я забыл ... áа õKне в конце. :)
Кевин Круйссен
1
Приятно найти с á! Вот 51 и еще один . 50 кажется возможным.
Grimmy
7

QuadR , 137 байтов SBCS

Заголовок дела с пробелом.

∊¯2↑¨@(∊∘⎕A)⍵
(.)\1*
{⍺←(,¨⎕D)⎕R('OhOneTwoThreeFourFiveSixSevenEightNine'(∊⊂⊣)⎕A)⋄' 'w←⍺,⊃⍵:⍬⋄1=≢⍵:⍺⍵⋄3=≢⍵:'Triple',w'Double',w,∇2↓⍵}⍵M

Попробуйте онлайн!

ε NLIST (Flatten)
¯2↑¨ взять последние два символа (набивка на левую сторону с пробелом) каждые символы
@ в позициях , где
(∊∘⎕A) символы являются членами верхнего регистра A lphabet
 в результате операции ниже PCRE Replace ...

(.) любой символ,
\1 за которым следует
* ноль или более раз, заменяется результатом следующего…

{…}⍵M "DFN"; это М ATCH вышеуказанного узора

('OhOneTwoThreeFourFiveSixSevenEightNine'()⎕A) Применить следующую анонимную молчаливую функцию с длинной строкой и заглавной буквой A в качестве аргументов слева:

 членство (из букв в длинной строке в верхнем алфавите)

 разделы (с новым разделом, начинающимся всякий раз, когда является членом

 левый аргумент (то есть длинная строка)

()⎕R PCRE R заменить следующие шаблоны этими словами:

⎕D цифры от 0 до 9

 относиться к каждому как к отдельному образцу

⍺← назначить эту функцию для замены в (для в lphabetise)

тогда,

⊃⍵ первый персонаж матча

, как строка

 применить к этому

w← назначить это w(для слова )

' '∊: Если пробел является его членом (т.е. если совпадение было пустым):

 ничего не возвращать (становится пустой строкой)

 иначе,

1=≢⍵: если один равен количеству символов в совпадении (то есть его длине):

⍺⍵ алфавит этой цифры

 иначе,

3=≢⍵: если три равно количеству символов в совпадении (то есть его длине):

'Triple',w перед именем «Triple» в ш Орд

 иначе,

2↓⍵ перейти к цифрам из матча

 отреагировать на это

w, добавить слово

'Double', prepend "Double"

Адам
источник
6

JavaScript (ES6),  161 160 152  144 байта

Вывод включает в себя один ведущий пробел.

s=>[n=>' '+'oh/one/two/three/four/five/six/seven/eight/nine'.split`/`[n],'$1 double$2','triple$2'].map(r=>s=s.replace(/(\S*)( \S+)\2|\d/g,r))&&s

Попробуйте онлайн!

или см. отформатированный исходный код

Как?

Преобразование выполняется в три этапа:

  1. замените каждую цифру соответствующим английским словом, которому предшествует пробел
  2. заменить каждый шаблон "X X"на"double X"
  3. заменить каждый шаблон "double X X"на"triple X"

Чтобы сохранить байты, мы используем одно и то же регулярное выражение для всех шагов:

/(\S*)( \S+)\2|\d/g

который работает следующим образом:

(\S*)  -> 1st capturing group: any word, or nothing at all
( \S+) -> 2nd capturing group: a space, followed by a word
\2     -> a copy of the 2nd capturing group
|\d    -> or try to capture a digit instead (for step 1)

На шаге 1 мы используем функцию обратного вызова, которая выбирает правильное слово из таблицы поиска:

  • "799999"" seven nine nine nine nine nine"

На шаге 2 мы заменим на "$1 double$2":

  • " (seven)( nine)( nine)"" seven double nine"
  • "( nine)( nine) nine"" double nine nine"

На шаге 3 мы заменим на "triple$2":

  • " (double)( nine)( nine)"" triple nine"
Arnauld
источник
3

Python 2 , 171 169 168 байт

s=input()
while s:c=s[0];n=(s[1:2]==c)+(s[:3]==c*3!=s[1:4]);print'   eellpbiurotd'[-n:0:-2]+'oh one two three four five six seven eight nine'.split()[int(c)],;s=s[1+n:]

Попробуйте онлайн!

-1 байт, спасибо Jitse

TFeld
источник
Ударь меня снова! Сохранить 1 байт, как это так
Jitse
@ Jitse, это не работает 1312;)
TFeld
Ах, ты прав!
Джитс
Как насчет этого тогда: ['','double ','triple '][n]до ' eellpbiurotd'[-n:0:-2]168 байт: Попробуйте его в Интернете!
Джитс
Кроме того, также 168 байтов
Jitse
3

Perl 5 -p , 111 байт

s/(\d)\1/ double$1/g;s/\w+(\d)\1/triple$1/g;s/\d/' '.qw(oh one two three four five six seven eigth nine)[$&]/ge

Попробуйте онлайн!

Объяснение:

s/(\d)\1/ double$1/g; # Replace non-overlapping double digits with " double<digit>"
s/\w+(\d)\1/triple$1/g; # Replace remaining double digits preceded by "double" with "triple<digit>"
s/\d/' '.qw(oh one two three four five six seven eigth nine)[$&]/ge # Replace digits with " <word>"
Wastl
источник
1
Побрил несколько байтов: 106
Xcali
3

Scala , 213 байтов

Понял. Каким-то образом рекурсивная версия, которую я пытался создать, была гораздо более многословной, чем эта (хотя все еще рекурсивной, но только в одном случае). Функция fпринимает в качестве входной строки номер телефона и выводит его фонетику с пробелом в конце.

var u="oh one two three four five six seven eight nine" split " "
"(.)\\1*".r.replaceAllIn(s,x=>{var o=x.matched
var k=u(o(0)-48)+" "
o.length match{case 3=>"triple "+k
case 1=>k
case _=>"double "+k+f(o drop 2)}})

Попробуйте онлайн!
Изменить : -8b благодаря DrY Wit!

Scala , 215 байт

И вот идет ведущая версия пробелов, по некоторым причинам длиннее на два байта (даже при масштабном рефакторинге).

var u="oh one two three four five six seven eight nine" split " "
"(.)\\1*".r.replaceAllIn(s,x=>{var o=x.matched
var k=u(o(0)-48)
" , double , triple ".split(",")(if(o.length>3){k+=f(o drop 2);1}else o.length-1)+k})

Попробуйте онлайн!

В. Куртуа
источник
2
Вы можете сохранить 8 байтов, заменив (o(0)+"").toIntна o(0)-48.
Доктор У Вит
Отлично, @DrYWit спасибо!
В. Куртуа
3

PHP , 174 169 166 159 байт

for(;$s=strspn($argn,$d=$argn[$i],$i++);$s==3?($i+=2)+print'triple ':$s<2?:++$i+print'double ',print[oh,one,two,three,four,five,six,seven,eight,nine][$d].' ');

Попробуйте онлайн!

Для каждой цифры в индексе, $iначиная с 0:

  • Если диапазон той же цифры, начиная с местоположения, $iравен 3, печатает 'triple 'и добавляет 2 к $iтак, чтобы на следующей итерации было перепрыгнуто 2 цифры.
  • Если диапазон той же цифры, начиная с местоположения, $iравен или больше 2, но не равен 3, печатает 'double 'и добавляет 1, $iтак что на следующей итерации будет перепрыгивать 1 цифра.
  • Печатает слово для цифры и пробела.
  • $i++,
night2
источник
2

Сетчатка 0.8.2 , 105 байт

+`(.)\1
=$1
.
 $&
= =
triple
=
double
9
nine
8
eight
7
seven
6
six
5
five
4
four
3
three
2
two
1
one
0
oh

Попробуйте онлайн! Выводит пробел. Объяснение: Первоначально я попробовал регулярное выражение, которое автоматически соответствует 2 или 3 цифрам, но подход @ Арнаулда оказался более удачным. Объяснение:

+`(.)\1
=$1

Подберите пары одинаковых цифр и замените первую на =. Затем повторите, чтобы для нечетного числа вторая последняя цифра также была заменена на =.

.
 $&

Поместите цифры (и =).

= =
triple

Обрабатывать регистр из трех одинаковых цифр.

=
double
9
nine
8
eight
7
seven
6
six
5
five
4
four
3
three
2
two
1
one
0
oh

Замените все оставшиеся символы словами.

Нил
источник
2

Желе , 59 байт

⁵;`,0;$Ɗ€Ẏ;`Ø0ṭ;-œṣjƭƒV€‘$ị“¡ıc⁴Ṛ⁽]@ɱ2¦Ż©Ẉḷ$Æ!)ɗ[ı8ɱḃ%ċ»Ḳ¤K

Попробуйте онлайн!

Монадическая ссылка, которая принимает в качестве аргумента строку цифр и возвращает строку Jelly из слов, разделенных пробелами. Когда вызывается как полная программа, выводит неявно.

Ник Кеннеди
источник
2

T-SQL 2017, 238 байт

Добавлены некоторые разрывы строк, чтобы сделать его читабельным

WHILE''<left(@,1)SELECT @=stuff(@,1,iif(p<4,p,2),'')+
iif(p=1,' ',iif(p=3,' triple ',' double '))
+trim(substring('oh  one  two  threefour five six  seveneightnine',left(@,1)*5,5))
FROM(SELECT~-patindex('%[^'+left(@,1)+']%'+'^',@)p)z
PRINT @

Попробуйте онлайн

t-clausen.dk
источник
2

C ++, 382 байта

Это не суперсловер, но кто-то должен был написать версию C ++. Рекурсивная функция R проходит по входной строке и считает повторные значения. Если есть более 3 повторов, он делает вид, что было 2 повторения, затем перематывает и пытается снова.

Еще несколько исходных символов могли бы быть вытеснены с помощью #defineMajor, но я уверен, что лучший алгоритм мог бы выжать больше.

#include <iostream>
#include <sstream>
using namespace std;
char*n[]={"oh","one","two","three","four","five","six","seven","eight","nine"};
void R(ostream& s,const char*r,char p='x',int c=0){if(*r==p)R(s,r+1,p,c+1);else
{if(c>1){if(c>= 4){s<<"double ";r-=(c-2);}else if(c==3)s<< "triple ";else if(c==2)s<< "double ";
}if(c >0)s<<n[p-'0']<<" ";if(!*r)return;R(s,r+1,*r,1);}}

void check(const char* in, const char* out)
{
    std::stringstream ss;
    R(ss,in);
    if (out == ss.str()) std::cout << "PASS: "; else std::cout << "FAIL! ";
    std::cout << in << "\n< " << out << "\n> " << ss.str() << std::endl;
}

int main(int c,char**argv)
{
    if (argv[1] == std::string("test"))
    {
        check("0123"         ,"oh one two three ");
        check("4554554"      ,"four double five four double five four ");
        check("000"          ,"triple oh ");
        check("00000"        ,"double oh triple oh ");
        check("66667888"     ,"double six double six seven triple eight ");
        check("19999999179"  ,"one double nine double nine triple nine one seven nine ");
    }
    else
    {
        char* v = argv[1];
        R(std::cout,v);
        std::cout << std::endl;
    }
}

и проверка контрольных примеров:

pa-dev01$ ./a.out test
PASS: 0123
< oh one two three
> oh one two three
PASS: 4554554
< four double five four double five four
> four double five four double five four
PASS: 000
< triple oh
> triple oh
PASS: 00000
< double oh triple oh
> double oh triple oh
PASS: 66667888
< double six double six seven triple eight
> double six double six seven triple eight
PASS: 19999999179
< one double nine double nine triple nine one seven nine
> one double nine double nine triple nine one seven nine
Марк Лаката
источник
1
Нужна ли часть гольфа #include <sstream>? Или вы могли бы сдвинуть это после гольфовой части для тестовой функции? Я думаю, что печатать std::ostream&sзаняло бы меньше места, чем using namespace std;, если нет других мест, где вам нужно std::.
Питер Кордес
253 байта
floorcat
2

Perl 6 , 96 93 байта

{S:g/(.)$0?[$0{}<!$0>]?/{(<triple double>X$)[3-$/.comb]}{+$/??uniname(~$0).words[1]!!'oh'} /}

Попробуйте онлайн!

Это блок анонимного кода, который принимает число и возвращает строку с цифрами в верхнем регистре, например, 0123 => oh ONE TWO THREEс одним завершающим пробелом.

Это было удалено на некоторое время, пока я не узнал, как использовать перехваты в запросе, но это должно быть исправлено сейчас.

Джо Кинг
источник
1

Красный , 242 байта

func[s][b:[copy t skip t]parse s[any[change[b t ahead not t](rejoin["triple "t])|
change b(rejoin["double "t])| skip]]foreach c s[prin either i:
find"0123456789"c[rejoin[pick[:oh:one:two:three:four:five:six:seven:eight:nine]index? i" "]][c]]]

Попробуйте онлайн!

Гален Иванов
источник
1

Scala , 253 байта

def g(s:String):String={val t="oh one two three four five six seven eight nine".split(" ")(s(0)-48)
s.length match{case 3=>"triple "+t;case 2=>"double "+t;case 1=>t;case _=>"double "+t+" "+g(s drop 2)}}
s=>"(.)\\1*".r.findAllIn(s).map(g(_)) mkString " "

Попробуйте онлайн!

Доктор У Вит
источник
1

Oracle SQL, 578 байт (в отформатированном виде)

Решение не является кратким, поэтому публикуйте его в формате.

with r(s) as
(select x from t
  union all
 select case
           when length(regexp_substr(s, '(.)(\1)+')) = 3 
           then regexp_replace(s, '^...')
           else regexp_replace(s, '^(.)\1|^.')
        end
   from r
  where s is not null)
select listagg(decode(length(r),  2, 'double ',  3, 'triple ') ||
               decode(substr(r, 1, 1), 0, 'oh', to_char(to_date(substr(r, 1, 1), 'j'), 'jsp')), ' ')
               within group (order by rownum)
  from (select regexp_replace(s, lag(s) over (order by length(s)) || '$') r
          from r order by length(s) desc);

Тест в SQL * Plus

SQL> create table t(x) as select /*'45547777777774'*/ '1999999910079' from dual;

Table created.

SQL> set pages 0
SQL> with r(s) as
  2  (select x from t
  3    union all
  4   select case
  5             when length(regexp_substr(s, '(.)(\1)+')) = 3
  6             then regexp_replace(s, '^...')
  7             else regexp_replace(s, '^(.)\1|^.')
  8          end
  9     from r
 10    where s is not null)
 11  select listagg(decode(length(r),  2, 'double ',  3, 'triple ') ||
 12                 decode(substr(r, 1, 1), 0, 'oh', to_char(to_date(substr(r, 1, 1), 'j'), 'jsp')), ' ')
 13                 within group (order by rownum)
 14    from (select regexp_replace(s, lag(s) over (order by length(s)) || '$') r
 15            from r order by length(s) desc);
one double nine double nine triple nine one double oh seven nine

Основная хитрость заключается в том, что цифры преобразуются в слова с использованием моделей формата Oracle вместо жестко закодированных литералов «один» ... «девять».

Доктор У Вит
источник
есть ли шанс, что это станет гольфом? кажется, вы можете удалить кучу пробелов. Я также думаю, что вы можете переписать ГДЕ s не является нулем ГДЕ s> ''
t-clausen.dk
1
Вы можете сохранить несколько символов, заменяя то , что после того, как union allс select regexp_replace(s,case when length(regexp_substr(s, '(.)(\1)+')) = 3 then '^...' else '^(.)\1|^.' end) from r.
Стив Касс
1

(Roblox) Lua 5.1 , 166 байт

for I,N in('111 triple 11 double 1 '):gmatch'(%d+)(%D+)'do for i,n in('0oh1one2two3three4four5five6six7seven8eight9nine'):gmatch'(.)(%l+)'do s=s:gsub(i*I,N..n)end end

Убедитесь, sчто это предопределенное строковое значение, заполненное только цифрами; это будет переменная, которая будет изменена. Результат будет включать ведущий символ пробела [\u20] .

VisualPlugin Rōblox
источник
Добро пожаловать на сайт! Поскольку Lua может принимать ввод с помощью стандартных методов , это противоречит правилам, требующим, sчтобы ввод уже был. Кроме того, у вас есть хороший первый пост! Я бы порекомендовал вам включить ссылку на сайт онлайн-тестирования, например, tio.run/#lua, чтобы другие могли проверить ваше решение
caird coinheringaahing
Здравствуй. Вариант Lua, на котором я тестировал (Rbx.Lua), не содержит методов ввода, хотя в песочнице есть методы вывода print, warn и error.
VisualPlugin Rōblox