Unminify Pythlike String

13

Pyth, пожалуй, самый успешный универсальный язык для игры в гольф. Несмотря на то, что он несколько упал в результате появления новых языков, с 2014 по 2016 год лаконичный синтаксис Pyth, постоянные обновления, перегрузка и (для его эпохи) многие встроенные функции сделали его фаворитом для большинства вопросов.

Код Pyth часто трудно читать. Даже выходные данные режима отладки (переносимый Python) часто состоят из длинной строки, иногда с круглыми скобками, вложенными в десять. Однако правильно отформатированный Pyth очень читабелен.

Вот фрагмент кода Pyth, написанный @isaacg в разделе «Цепочка слов» .

.MlZfqhMtTeMPT+Lzs.pMyQ

Это гораздо более читабельно, как это.

.M                     Filter by gives-maximal-value of
   l Z                   lambda Z:length(Z) over
   f                     filter by (lambda T:
     q                     equal
       hM t T                head-map tail T
       eM P T                end-map Pop T)
     +L                    Append z to each element in
        z                        
        s .pM y Q            flattened permutations of each subset of Q

Для этой задачи мы исключаем классификации символов и фокусируемся на форматировании. Вместо того, чтобы быть кодом Pyth, ввод будет состоять из символов в 0123456789M. Цифра nпредставляет функцию арности n, иM представляет оператора. Например, приведенный выше код представляется как 210221M101M102M011M10. Вот шаги для унификации:

Разделите строку на токены.

Токен совпадает [0-9]M*.0Mне будет происходить при вводе.

Добавьте конечные 0.

Когда аргументов недостаточно, Pyth добавляет Qв код столько неявных переменных (лямбда-переменных или s), сколько необходимо для заполнения аргументов программы; они должны быть представлены 0с.

Сгруппируйте токены в строки.

Арентность токена - это значение его цифры.

  • Токен arity-0 (т. Е. 0) завершает строку.

  • Для токена arity-1 следующий токен должен идти в той же строке, разделенной пробелом.

  • Для токена arity> = 2 его аргументы идут в отдельных строках в порядке их появления в коде, за каждым следуют свои собственные подаргументы и так далее. Аргументы токена имеют отступ до конца этого токена плюс один пробел.

вход

Непустая строка (или массив char, массив строк длины 1 и т. Д., Как это разрешено стандартными методами ввода / вывода), состоящая из 0123456789M, который не будет содержать подстроку0M .

Выход

Строка отформатирована в соответствии с вышеуказанными правилами.

Контрольные примеры

210221M101M102M011M10

2
  1 0
  2
    2
      1M 1 0
      1M 1 0
    2M
       0
       1 1M 1 0


123M4M

1 2
    3M
       4M
          0
          0
          0
          0
       0
       0
    0


2MM

2MM
    0
    0


11011100

1 1 0
1 1 1 0
0


9000000

9
  0
  0
  0
  0
  0
  0
  0
  0
  0
lirtosiast
источник
Похожий вопрос: codegolf.stackexchange.com/questions/47798/…
lirtosiast
Могу ли я принять входные данные в виде массива цифр / строки? Примером 210221M101M102M011M10будет[2,1,0,2,2,1,'M',1,0,1,'M',1,0,2,'M',0,1,1,'M',1,0]
Луис Фелипе Де Иисус Муньос
@LuisfelipeDejesusMunoz Нет, если только стандартные правила ввода-вывода не требуют, чтобы вам было разрешено (что я не думаю, что они это делают). IMO немного изменило бы задачу, если бы Ms допускал, чтобы тип данных отличался от целых чисел.
lirtosiast
@lirtosiast Итак, массив символов / односимвольных строк - это нормально, просто не используются разные типы данных между цифрами и M?
Камил Дракари
1
@LeakyNun Пустая строка - теперь неопределенное поведение.
lirtosiast

Ответы:

1

JavaScript (ES8), 160 159 байт

f=(s,a=[d=0,p=[1]])=>s.replace(/(.)M*/g,(s,c)=>(g=_=>a[d]?s+(P=p[d]-=c--&&~s.length,c?`
`.padEnd(P):' '):g(d--))(a[d]--,a[++d]=+c,p[d]=p[d-1]))+(d?f('0',a):'')

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

комментарии

f = (                          // f = recursive function taking:
  s,                           //   s   = input string
  a = [                        //   a[] = array holding the number of expected arguments
    d = 0,                     //   d   = current depth, initialized to 0
    p = [1]                    //   p[] = array holding the padding values
  ]                            //
) =>                           //
  s.replace(                   // search in s all substrings
    RegExp('(.)M*', 'g'),      // consisting of a digit followed by 0 to N 'M' characters
    (s, c) =>                  // for each substring s beginning with the digit c:
      ( g = _ =>               //   g = recursive function
          a[d] ?               //     if we're still expecting at least one argument at
                               //     this depth:
            s + (              //       append s
              P = p[d] -=      //       update the padding value P = p[d] for this depth:
                c-- &&         //         decrement c; unless c was equal to 0,
                ~s.length,     //         add the length of s + 1 to p[d]
              c ?              //       if c is not equal to 0 (i.e. was not equal to 1):
                `\n`.padEnd(P) //         append a linefeed followed by P - 1 spaces
              :                //       else:
                ' '            //         append a single space
            )                  //
          :                    //     else (all arguments have been processed):
            g(d--)             //       decrement the depth and call g again
      )(                       //   before the initial call to g:
        a[d]--,                //     decrement the number of arguments at depth d
        a[++d] = +c,           //     set the number of arguments for the next depth
        p[d] = p[d - 1]        //     set the padding value for the next depth,
      )                        //     using a copy of the previous depth
  ) + (                        // end of replace()
    d ?                        // if we're not back at depth 0:
      f('0', a)                //   do a recursive call to f with an extra '0'
    :                          // else:
      ''                       //   stop recursion
  )                            //
Arnauld
источник
1

Haskell , 192 190 187 байт

unlines.snd.f
f(n:r)|(m,t)<-span(>'9')r,(s,l)<-n#t=(s,n?((n:m):map((' '<$(n:n:m))++)l))
f e=(e,["0"])
'1'?(a:b:r)=(a++drop(length a)b):r
_?s=s
'0'#s=(s,[])
n#s|(r,l)<-f s=(l++)<$>pred n#r

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

Должен быть лучший способ обработки случая arity-1, в настоящее время он занимает 45 байтов.

Редактирование:

  • -2 байта путем переключения на другой метод обработки 1, хотя предыдущий метод, вероятно, имеет больший потенциал оптимизации.
  • -3 байта, не преобразовывая цифры символов в числа и используя predвместо n-1.
unlines.snd.f
f(n:r)|(m,t)<-span(>'9')r,(s,l)<-read[n]#t,w<-map((' '<$(n:n:m))++)=(s,last$((n:m):w l):[(n:m++' ':h):w t|n<'2',h:t<-[l]])
f e=(e,["0"])
0#s=(s,[])
n#s|(r,l)<-f s=(l++)<$>(n-1)#r

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

Laikoni
источник
1

Древесный уголь , 75 байт

FS⊞υ⎇⁼ιM⁺⊟υιι≔⮌υυ≔⟦⟧θ≔⟦⟧ηW∨υη«≔⎇υ⊟υ0ιι¿⊖Σι↘→⊞θι⊞ηΣιW∧η¬§η±¹«⊟ηM⊕L⊟θ←¿η⊞η⊖⊟η

Попробуйте онлайн! Ссылка на подробную версию кода. Объяснение:

FS⊞υ⎇⁼ιM⁺⊟υιι

Зацикливайте вводимые символы и превращайте их в список цифр с необязательными Mсуффиксами.

≔⮌υυ

Переверните этот список, чтобы мы могли его использовать Pop.

≔⟦⟧θ

Эта переменная является стеком токенов, арность которых еще не выполнена.

≔⟦⟧η

Эта переменная является стеком остальной арности невыполненных токенов.

W∨υη«

Повторяйте, пока мы не сожмем все жетоны и не освободим стек.

     ≔⎇υ⊟υ0ι

Получить следующий токен или, 0если нет.

     ι¿⊖Σι↘→

Распечатайте маркер и затем переместите курсор по горизонтали, если он начинается с 1диагонали.

     ⊞θι⊞ηΣι

Добавьте токен и его арность в соответствующие переменные.

     W∧η¬§η±¹«

Повторите, пока стек арности не пуст, но верхняя арность равна нулю.

              ⊟η

Откажитесь от нулевой арности.

              M⊕L⊟θ←

Удалите его жетон и переместите столько символов, сколько осталось.

              ¿η⊞η⊖⊟η

Если остались какие-либо арности, уменьшите верхнюю арность.

Нил
источник