Сжатие данных RLE для рисования ASCII-графики


11

Этот вопрос основан на то , что я придумал , чтобы ответить на другой вопрос .

Иногда вопросы здесь просят нарисовать немного ASCII искусства. Одним простым способом хранения данных для искусства является RLE (кодирование по длине прогона) . Так:

qqqwwwwweeerrrrrtttyyyy

будет выглядеть так:

3q5w3e5r3t4y

Теперь, чтобы нарисовать большой ASCII-арт, вы можете получить такие данные (игнорируя символы новой строки):

19,20 3(4)11@1$20 11@19,15"4:20 4)19,4:20 11@
   ^^^
   Note that this is "20 whitespaces"

(Character count: 45)

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

Вы хотите сэкономить место в этой строке, поэтому вы заменяете числа набором символов в верхнем регистре (будучи «A» равно 1, «B» равно 2, пока «Z» не равно 26), потому что вы никогда не собираетесь получить более 26 повторений персонажа. Итак, вы получите:

S,T C(D)K@A$T K@S,O"D:T D)S,D:T K@

(Character count: 34)

И, наконец, вы замечаете, что некоторые группы (буква + символ) повторяются, поэтому вы заменяете группы, которые появляются в строке 3 раза или более, набором символов в нижнем регистре в порядке или появлении в строке, но сохраняя в буфере произведенные замены (в формате «группа + символ замены» для каждой замены) и оставшаяся часть строки как есть. Итак, следующие группы:

S, (3 times) 
T  (4 times)
K@ (3 times)

заменяется на 'a', 'b' и 'c' соответственно, потому что никогда не будет повторяться более 26 групп. Итак, наконец вы получите:

S,aT bK@c
abC(D)cA$bcaO"D:bD)aD:bc

(Character count: 9+24=33)

[Последний шаг сохраняет только 1 байт, потому что группы, которые фактически сохраняют символы после замены, - это группы, которые появляются 4 раза или более.]

Соревнование

Учитывая строку, содержащую данные RLE для рисования ASCII-графики (с предложенными ограничениями), напишите самую короткую программу / функцию / метод, которую вы можете, чтобы сжать ее, как описано. Алгоритм должен напечатать / вернуть две строки: первая содержит словарь, используемый для сжатия, а вторая - полученную сжатую строку. Вы можете вернуть строки в виде кортежа, массива, списка или чего-либо еще в указанном порядке.

Обратите внимание, что если строка не может быть сжата на шаге 2, алгоритм должен вернуть пустую строку в качестве первого возвращаемого значения и результат шага 1 в качестве второго возвращаемого значения.

Вам не нужно включать результат шага 1 в выходные значения, я просто включаю их в примеры для пояснения.

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

Еще один тест

Input:                   15,15/10$15,15/10"10$10"10$10"10$10"15,15/

Output of step 1:        O,O/J$O,O/J"J$J"J$J"J$J"O,O/

Final algorithm output:  O,aO/bJ$cJ"d
                         abcabdcdcdcdab

---

Input:                   15,15/10$15,15/10"

Output of step 1:        O,O/J$O,O/J"

Final algorithm output:  <empty string>
                         O,O/J$O,O/J"

1
потому что вы никогда не получите более 26 повторений персонажа Нету. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Okx

@Okx Этого не может быть.
Эрик Outgolfer

@ Да, в реальном мире. Правила составлены для ограниченного набора искусства ASCII.
Чарли

2
В реальной реализации, S,aT bK@cвероятно, будет храниться как просто S,T K@без явного присвоения имен символам замещения, которые могут быть тривиально выведены из этого.
Arnauld

@ Arnauld, ты совершенно прав, я пропустил это, но я оставлю вопрос как есть, на тот случай, если кто-нибудь начнет писать свой ответ.
Чарли

Ответы:


3

JavaScript (ES6), 168 167 байт

Возвращает массив из двух строк: [dictionary, compressed_string].

s=>[(a=(s=s.replace(/\d+/g,n=>C(n|64),C=String.fromCharCode)).match(/../g)).map(v=>s.split(v)[a[v]||3]>=''?D+=v+(a[v]=C(i++)):0,i=97,D='')&&D,a.map(v=>a[v]||v).join``]

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


3

Python 2 , 269 280 268 266 байт

Ничего необычного здесь не происходит. Хорошая возможность использовать несколько простых регулярных выражений.

Первая версия не удалась для строк, содержащих специальные символы, которые были интерпретированы в регулярном выражении. Вторая версия (с использованием re.escape) работает со всеми тестами. Это исправление стоило 11 байт.

Вторая версия не присваивала подстановочные символы по порядку, как требуется в спецификации проблемы и как указано @CarlosAlejo. Итак, вернемся к чертежной доске.

Исправленная версия, далее игра в гольф

  • -6 байт сохранено за счет отсутствия вывода на печать в две строки
  • +3 байта: переключение на подстановки кода через строку, чтобы разрешить вызов, как указано.
  • -4 байта: так как я больше не вызываю re.findall дважды, мне не нужно его переименовывать
  • -5 байт: переключение с циклов for на циклы while.
  • -2 байта благодаря @ Comrade Sparkle Pony
import re
S=re.sub
b=a=input()
for i in re.findall('\d{1,2}',a):
 b=S(i, chr(64+int(i)),b)
n,s,p=96,'',0
while p<len(b):
 c=b[p:p+2];f=b.count(c)
 if f>2and not c in s:n+=1;s+=c+chr(n)
 p+=2
p=0
while p<len(s):k=s[p:p+2];v=s[p+2];b=S(re.escape(k),v,b);p+=3
print s,b

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


Вы почти там, обратите внимание, что группы на втором этапе не созданы в правильном порядке (см. Пример). Группы должны быть созданы в порядке появления, поэтому первый должен быть O,a.
Чарли

@CarlosAlejo Я не заметил, что в качестве требования, поскольку замены являются произвольными, с функциональной точки зрения. Словари Python по умолчанию, естественный способ реализовать это, неупорядочены.
Придется

Не могли бы вы сохранить несколько байтов с помощью b=a=input()и n,s,p=96,'',0?
Товарищ SparklePony

\d+было бы более короткое регулярное выражение для использования. В любом случае вы никогда не пройдете более 26, так что нет никаких оснований гарантировать, что это конкретно 1-2 цифры. Кроме того, использование re.escapeозначает, что основная строка replaceзаканчивается немного короче: 253 байта
Value Ink

0

Луа, 215 байт

Просто хороший пример сопоставления с образцом.

Я думаю, что Луа недооценивают, когда дело доходит до игры в гольф ... посмотрите на все эти утверждения, сжатые вместе!

g,c=string.gsub,string.char
u=g(arg[1],"%d%d?",function(n)return c(n+64)end)l,d=97,""g(u,"..",function(m)n,e=0,g(m,".", "%%%0")g(u,e,function()n=n+1 end)if n>2 then
l,s=l+1,c(l)d,u=d..m..s,g(u,e,s)end
end)print(u,d)

0

Python 2 , 186 байт

from re import*
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
Q=[]
for p in findall('[A-Z].',S):
 if S.count(p)>2:a=chr(len(Q)+97);Q+=[p+a];S=sub(escape(p),a,S)
print''.join(Q),S

Я надеялся наконец найти применение для re.subn: C

# first step - convert all numbers to uppercase letters
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
# empty list to hold encoding of second step
Q=[]
# find every encoded pair (uppercase letter and some char)
for p in findall('[A-Z].',S):
 # if it occures 3 or move times
 if S.count(p)>2:
  # get lowercase letter to substitute with
  a=chr(len(Q)+97)
  # store encoding into list
  Q+=[p+a]
  # update string - substitute pair with lowercase letter
  S=sub(escape(p),a,S)
# output
# encodings of second step, space, result
# if nothing was compressed at step 2, space would prepend result (of step 1)
print''.join(Q),S

Сжатый на шаге 2

Не сжимается на шаге 2


Python 2 , 246 байт

Весь второй шаг сделан в repl lambda of re.sub. Просто для удовольствия.

from re import*
Q=[]
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
S=sub('[A-Z].',lambda m:(lambda m:S.count(m)>2and(m in Q or not Q.append(m))and chr(Q.index(m)+97)or m)(m.group(0)),S)
print''.join(Q[i]+chr(i+97)for i in range(len(Q))),S

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



Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.