ASCII sanatı çizmek için RLE verilerini sıkıştırma


11

Bu soru, başka bir soruyu cevaplamak için bulduğum sorulara dayanıyor .

Bazen buradaki sorular bazı ASCII sanatlarını çizmeyi ister. Tekniğin verilerini depolamanın basit bir yolu RLE'dir (çalışma uzunluğu kodlaması) . Yani:

qqqwwwwweeerrrrrtttyyyy

dönüşür:

3q5w3e5r3t4y

Şimdi büyük bir ASCII sanatı çizmek için şu şekilde veri alıyor olabilirsiniz (yeni satır karakterlerini göz ardı ederek):

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 sanatı için kullanılan karakterler asla küçük veya büyük harf veya rakam olmayacak, sadece işaretler, işaretler ve semboller olacak, ancak her zaman yazdırılabilir ASCII karakter kümesinde bulunmayacaktır.

Bu dizede biraz yer kazanmak istersiniz, böylece sayıları büyük harf karakter kümesiyle değiştirirsiniz ('A' olmak 1'e eşittir, 'B' 'Z' 26'ya eşit olana kadar 2'ye eşittir), çünkü asla bir karakterin 26'dan fazla tekrarını almak. Yani şunu elde edersiniz:

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

(Character count: 34)

Ve son olarak bazı (harf + sembol) gruplarının tekrarlandığını fark edersiniz, bu nedenle dizede 3 kez veya daha fazla görünen grupları, dizedeki sırayla veya görünümde küçük harf karakter kümesiyle değiştirirsiniz, ancak sübstitüsyonlar (her bir sübstitüsyon için "grup + sübstitüe char" formatında) ve ipin geri kalanını olduğu gibi bırakır. Yani aşağıdaki gruplar:

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

sırasıyla 'a', 'b' ve 'c' ile ikame edilir, çünkü asla 26'dan fazla grup tekrarlanmaz. Sonunda şunu elde edersiniz:

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

(Character count: 9+24=33)

[Son adım yalnızca 1 bayt kazandırır çünkü değiştirildikten sonra karakterleri gerçekten kaydeden gruplar 4 kez veya daha fazla görünen gruplardır.]

Meydan okuma

Bir ASCII resmi çizmek için RLE verilerini içeren bir dize verildiğinde (önerilen kısıtlamalarla), açıklandığı gibi sıkıştırmak için yapabileceğiniz en kısa programı / işlevi / yöntemi yazın. Algoritma iki dizeyi yazdırmalı / döndürmelidir: ilki sıkıştırma için kullanılan sözlüğü içerir ve ikincisi sonuçta oluşan sıkıştırılmış dizedir. Dizeleri verilen sırayla bir Tuple, bir dizi, Liste veya herhangi bir şekilde döndürebilirsiniz.

Dizenin 2. adımda sıkıştırılamaması durumunda, algoritmanın boş bir dizeyi ilk dönüş değeri olarak ve 1. adımın sonucunu ikinci dönüş değeri olarak döndürmesi gerektiğini unutmayın.

1. adımın sonucunu çıktı değerlerine dahil etmenize gerek yoktur, sadece açıklama amacıyla bunları örneklere dahil ediyorum.

Bu , bu yüzden her dil için en kısa cevap kazanabilir!

Başka bir test örneği

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
çünkü asla bir Nope karakterinin 26 tekrarından fazlasını almayacaksınız . aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Okx

@Okx Asla durum böyle olamaz.
Outgolfer Erik

@ Tamamx evet, gerçek dünyada. Bununla birlikte, kurallar sınırlı bir ASCII sanatı seti için oluşturulmuştur.
Charlie

2
Gerçek bir uygulamada, S,aT bK@cmuhtemelen S,T K@önemsiz bir şekilde bundan çıkarılabilen ikame karakterlerini açıkça adlandırmadan saklanırdı .
Arnauld

@ Tamamen haklı olursanız, bunu kaçırdım, ancak herhangi bir kişinin cevabını yazmaya başlaması durumunda soruyu olduğu gibi bırakacağım.
Charlie

Yanıtlar:


3

JavaScript (ES6), 168 167 bayt

İki dizelerden oluşan bir dizi döndürür: [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``]

Test senaryoları


3

Python 2 , 269 280 268 266 bayt

Burada hiçbir şey fantezi değil. Bazı basit düzenli ifadeleri kullanmak için iyi bir fırsat.

İlk sürüm, normal ifade içinde yorumlanan özel karakterler içeren dizeler için başarısız oldu. İkinci sürüm (re.escape kullanarak) tüm test senaryoları ile çalışır. Bu düzeltmenin maliyeti 11 bayttır.

İkinci sürüm, sorun belirtiminde gerektiği gibi ve @CarlosAlejo tarafından işaret edildiği gibi ikame karakterlerini atamadı. Yani silbaştan.

Düzeltilmiş versiyon, daha fazla golf

  • İki satıra çıktı yazdırılmadan kaydedilen 6 bayt
  • +3 bayt: Zorluğun belirtildiği gibi yerine getirilmesine izin vermek için bir dize aracılığıyla kod değiştirmelere geçiş.
  • -4 bayt: Artık iki kez re.findall demediğim için yeniden adlandırmam gerekmiyor
  • -5 bayt: döngülerden döngülere geçiş.
  • @Comrade Sparkle Pony sayesinde -2 bayt
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

Çevrimiçi deneyin!


Neredeyse oradasınız, ikinci adımdaki grupların doğru sırada oluşturulmadığını unutmayın (örneğe bakın). Gruplar görünüm sırasına göre oluşturulmalıdır, bu yüzden ilk grup olmalıdır O,a.
Charlie

@CarlosAlejo Bir değişiklik olarak, ikamelerin keyfi olduğu için fonksiyonel bir bakış açısıyla dikkat çekmemiştim. Python'un bunu yapmanın doğal bir yolu olan varsayılan sözlükleri düzensizdir. Diğer olası veri yapılarını göz önünde bulundurmak zorundayız ....
CCB60

b=a=input()Ve kullanarak bazı baytları kaydedemediniz n,s,p=96,'',0mi?
SparklePony Yoldaş

\d+kullanmak için daha kısa bir normal ifade olurdu. Asla 26'nın üzerine çıkmayacaksınız, bu yüzden özellikle 1-2 basamak olmasını sağlamak için bir neden yok. Ayrıca, re.escapetemel bir dizenin replacebiraz daha kısa sona ereceği anlamına gelir : 253 bayt
Value Ink

0

Lua, 215 bayt

Sadece iyi bir desen eşleme.

Bence golf söz konusu olduğunda Lua'nın hafife alınması ... birlikte squish tüm bu ifadelere bak!

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 bayt

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

Sonunda aşağıdakiler için kullanım alanı bulmayı umuyordum 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. adımda sıkıştırılır

2. adımda sıkıştırılmamış


Python 2 , 246 bayt

Tüm ikinci adım re.sub repl lambda yapılır. Sadece eğlence için.

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

Çevrimiçi deneyin!


0

Perl 5 -pl , 81 bayt

s/\d+/chr$&+64/ge;$b=a;for$a(/([A-Z].)(?=.*\1.*\1)/g){s/\Q$a/$b/g&&($\.=$a.$b++)}

Çevrimiçi deneyin!

Kodlanmış dizeyi ilk satıra, üçe ikinci satıra yazdırır


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.