Стиснення даних 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 повторень персонажа Нопе. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Okx

@Okx Це ніколи не може бути.
Ерік Аутгольфер

@Okx так, у реальному світі. Однак правила складаються для обмеженого набору мистецтва ASCII.
Чарлі

2
У реальній реалізації вона, S,aT bK@cймовірно, зберігається як просто S,T K@без явного іменування символів підстановки, які можна тривіально вивести з цього.
Арнольд

@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 байт: перехід від циклів до циклів.
  • -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, природний спосіб їх здійснення, не мають порядку. Доведеться розглянути інші можливі структури даних ....
CCB60

Не вдалося зберегти кілька байт за допомогою b=a=input()і n,s,p=96,'',0?
Товариш SparklePony

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

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

Пітон 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 байт

Весь другий крок, виконаний у відповіді лямбда від 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.