Persingkat teks dengan Run Encoding Panjang

8

Mempersingkat (atau tidak) teks menggunakan pengkodean run run

Memasukkan:

heeeello
woooorld

Keluaran:

1h4e2l1o
1w4o1r1l1d
  • Baca baris dari stdin.
  • Cetak ke stdout.
  • Stderr tentu saja dibuang.
  • Asumsikan ada testcases tersembunyi (tidak ada embedding dari output)
  • Input / Output sebagai ASCII
  • Bahasa apa pun diterima
mroman
sumber
3
Anda dapat (biasanya) menyimpan sedikit jika Anda mengabaikan semua yang ada, misalnya w4orldalih-alih 1w4o1r1l1d(Anda harus keluar dari angka, mis. `F111 -> f3 \ 1´). Tapi kemudian itu akan menjadi duplikat dekat dari ini: codegolf.stackexchange.com/questions/6774
primo
1
Karena itu cukup dekat untuk Run-Length Encoding yang saya pilih untuk ditutup sebagai dupe. Itu tidak akan memberikan tantangan baru atau tempat menarik.
Peter Taylor
Poin bonus untuk siapa pun yang mengelola untuk menemukan fixpoint.
FUZxxl
4
@ FuZxxl, 22adalah titik perbaikan sepele.
Peter Taylor
2
@PeterTaylor Dan satu-satunya yang tidak kosong. Kita tahu itu harus dimulai dengan angka. 11tidak mungkin. 22harus berakhir di sana atau diikuti oleh titik tetap lain yang tidak dimulai dengan 2. 333nnnadalah pola yang mustahil, karena Anda tidak akan pernah menemukan karakter yang sama pada indeks ganjil berturut-turut. 4444dan gagal karena alasan yang sama.
Khuldraeseth na'Barya

Jawaban:

2

Perl: 46 → 36 atau 27 karakter

perl -pe's|((.)\2*)|@x=split//,$1;@x.$x[0]|eg'

Semua salam @ardnew untuk memunculkan ide menggunakan tr///coperator untuk menghitung jumlah karakter dalam string yang cocok alih-alih membelah:

perl -pe's|((.)\2*)|$1=~y///c.$2|eg'

Degolfed:

while(defined($_ = <>)) {
  $_ =~ s{((.)\2*)}           # match 1 or more consecutive identical non-newlines
         {
           ($1 =~ y///c )     # count the number of characters in $1
           .                  # and concatenate it
           $2                 # with the first matched character
         }eg;                 # execute substitution, match "global"
  print $_;                   # print the modified line
}

Pemakaian:

$ perl -pe's|((.)\2*)|$1=~y///c.$2|eg' infile

atau melalui STDIN

$ perl -pe's|((.)\2*)|$1=~y///c.$2|eg'
heeeello

cetakan

1h4e2l1o
amon
sumber
Anda mengubah diri Anda pada jumlah karakter Anda - saya menghitung 37 karakter termasuk 1 untuk popsi.
Gareth
Anda dapat menyimpan 10 karakter dengan menggunakan s|((.)\2*)|$1=~y///c.$2|eg, yang berjumlah 27 karakter total (menggunakan aturan penghitungan karakter yang sama dengan @Gareth)
ardnew
1
Lebih pendek lagi menjadi 25 byte (termasuk -p) dengan menghilangkan paren luar: Coba online!
Xcali
2

Stax , 7 byte

ûèB☼å°╤

Jalankan dan debug st stlanglang.xyz!

Dibongkar (8 byte) dan penjelasan:

m|RFNppz
m           For each line of input:
 |R           Run-length encode: "heeeello" -> [[104,1],[101,4],[108,2],[111,1]]
   F          For each pair:
    N           Uncons-left: [104,1] -> push [104]; push 1
     ppz        Pop and print. Pop and print. Push "".
              Implicit print (always an empty string) with a newline

5 byte, hanya berfungsi pada satu baris:

∩l↨me
|RmEp]    Unpacked
|R        Run-length encode: "heeeello" -> [[104,1],[101,4],[108,2],[111,1]]
  m       Map block over input:
   E        Explode array: [104,1] -> push 104, push 1
    p       Pop and print with no newline
     ]      Make a one-element list: 104 -> [104] (which is "h")
            Implicit print with newline

Jalankan dan debug di staxlang.xyz!

Mungkin tidak legal. Program ini mencetak setiap pasangan pada garisnya sendiri. Agak samar.

Jika format output itu ilegal, saya beri Anda 6 byte :

╡δôZ→╬
|RFEp]p    Unpacked
  F        For each item in array, execute block:
      p      Pop and print with no newline
             No implicit print in for-each block, so no extra newlines

Jalankan dan debug di staxlang.xyz!

Pencipta bahasa menunjukkan secara rekursif bahwa uncons-right ( N) dapat mempersingkat ini menjadi enam byte yang dibongkar, karena menangani Edan ]dengan sendirinya. Program sesingkat ini, sering kali tidak menjadi lebih pendek saat dikemas, dan ini adalah contohnya. Masih enam byte: |RFNppEdit: Harus memperbarui jawaban utama saya; bentuk ini yang saya gunakan.

Khuldraeseth na'Barya
sumber
1
Belum selesai. |RFNppdapat memberikan output yang ditentukan dalam 6 byte dibongkar, tetapi sayangnya, tidak dikemas.
rekursif
1
@KevinCruijssen Yap. Aduh.
Khuldraeseth na'Barya
1

J, 35 31 karakter

,(](":@#,{.);.1~1,2~:/\])1!:1[1

Pemakaian:

   ,(](":@#,{.);.1~1,2~:/\])1!:1[1
heeeello
1h4e2l1o
   ,(](":@#,{.);.1~1,2~:/\])1!:1[1
woooorld
1w4o1r1l1d
Gareth
sumber
Menggunakan aturan dan fungsi situs modern, [:,(#,&":{.)/.~untuk 15: Cobalah online!
Jonah
1

Brachylog , 11 byte

ḅ⟨{lṫ}ch⟩ᵐc

Cobalah online!

(Jika output benar-benar harus di stdout, tambahkan satu byte wdi akhir.)

          c    The output is the concatenation of
 ⟨    c ⟩ᵐ     the concatenated pairs of
  {lṫ}         length converted to a string
       h       and first element
ḅ        ᵐ     for every run in the input.
String yang tidak terkait
sumber
1

Python 3 berulang, 115 99 97 byte

while 1:
 a=b='';k=0
 for c in input():e=a!=c;b+=(str(k)+a)*e;k+=1-k*e;a=c
 print(b[1:]+str(k)+a)

Cobalah online!

Python 3 rekursif, 136 130 129 byte

f=lambda r,c,s,k=1:s and(c==s[0]and f(r,c,s[1:],k+1)or f(r+str(k)+c,s[0],s[1:]))or r[1:]+str(k)+c
while 1:print(f('','',input()))

Cobalah online!

Pendekatan berulang tampaknya cukup berhasil, sedangkan versi rekursif memiliki banyak ruang untuk perbaikan.

movatica
sumber
Pendekatan yang bagus! Sepertinya whileloop dalam kode Anda hanya ada di sana untuk menunjukkan input. Tanpa itu, kode Anda masih valid. Dalam hal ini, loop tidak perlu menjadi bagian dari kode dan Anda dapat mengurangi contoh pertama menjadi 85 byte seperti: Coba online!
Jitse
Contoh kedua Anda dapat dikurangi menjadi 121 byte seperti ini: Coba online!
Jitse
Ya, loop sementara hanya untuk input garis. Tetapi pertanyaannya perlu membaca semua baris, bukan hanya satu, jadi eksternalisasi loop akan melanggar aturan.
movatica
1

05AB1E , 9 byte

|εÅγs.ιJ,

Cobalah online.

Atau sebagai alternatif:

|εÅγøí˜J,

Cobalah online.

Penjelasan:

|          # Read all lines of input as list
 ε         # For-each over the lines:
  Åγ       #  Run-length encode, pushing the list of characters and lengths separately
    s      #  Swap so the characters at at the top and lengths below it
         #  Interleave the two lists
       J   #  Join the list of characters and lengths together to a single string
        ,  #  And output it with trailing newline

|εÅγ       # Same as above
    ø      #  Zip/transpose; creating pairs of [character, length]
     í     #  Reverse each pair to [length, character]
      ˜    #  Deep flatten the pairs to a single list
       J,  #  Join them together to a single string, and output it with trailing newline
Kevin Cruijssen
sumber
1

Bahasa Wolfram (Mathematica) , 98 byte

Print[""<>StringCases[#,s:x_..:>ToString@StringLength@s<>x]]&/@StringSplit[$ScriptInputString,"
"]

Cobalah online!

Format I / O yang lebih fleksibel mengurangi solusi ini menjadi 54 byte :

""<>StringCases[#,s:x_..:>ToString@StringLength@s<>x]&

Cobalah online!

Roma
sumber
0

Bash: 104 karakter

while read s;do e=;while [[ $s ]];do c=${s:0:1};n=${s##+($c)};e+=$[${#s}-${#n}]$c;s=$n;done;echo $e;done

Contoh dijalankan:

bash-4.2$ while read s;do e=;while [[ $s ]];do c=${s:0:1};n=${s##+($c)};e+=$[${#s}-${#n}]$c;s=$n;done;echo $e;done <<END
heeeello
woooorld
END
1h4e2l1o
1w4o1r1l1d
manatwork
sumber
0

Zsh, 117

while read s;do n=1;for i in {1..$#s};do if [[ $s[i] != $s[i+1] ]];then echo -n $n$s[i];n=0;fi;((n++));done;echo;done

Jalankan seperti ini:

zsh script.zsh < infile

De-golf

while read s; do                      # while stdin has more
  n=1                                 # repeat counter
  for i in {1..$#s}; do               # for each character
    if [[ $s[i] != $s[i+1] ]]; then   # same as next one?
      echo -n $n$s[i]                 # print if no
      n=0
    fi
    ((n++))
  done
  echo                                # newline between words
done
Thor
sumber
Apakah ruang putih itu perlu atau dapatkah Anda mempersingkat `jika ['menjadi' jika ['dll?
mroman
The [[membangun adalah perintah pada itu sendiri (seperti [) dan telah dipisahkan dari perintah lain. Untuk menggunakan [lebih dari [[itu, diperlukan argumen untuk dikutip sehingga empat "perlu ditambahkan.
Thor
0

APL (24)

,↑{(⍕⍴⍵),⊃⍵}¨B⊂⍨B≠¯1⌽B←⍞
marinus
sumber
0

Burlesque (17B)

{=[{J[-jL[Q}\m}WL

{=[{^^[~\/L[Sh}\m}WL

Versi yang lebih lama / Alternatif dan lebih panjang:

{= [{^^ L [Sh \ / -] Sh. +} M [\ [} WL
{= [{^^ L [Sh \ / -] [-. +} M [\ [} WL
{= [{^^ L [Sh \ / - ~. +} M [\ [} WL
{= [{^^ L [Sh \ / -]. +} \ M} WL
{= [{^^ L [Sh \ / [~. +} \ M} WL
{= [{^^ L [Sh \ / [~ _ +} \ m} WL
{= [{^^ L [Sh \ / fc. +} \ M} WL
{= [{^^ L [Sh \ / - ~. +} \ M} WL
{= [{^^ L [Sh \ / -] \ /} \ m} WL
mroman
sumber
0

Retina , 12 byte

(.)\1*
$.0$1

Cobalah online.

Penjelasan:

Dapatkan bagian dari 1 atau lebih dari karakter yang sama, menangkap karakter dalam grup tangkapan 1.

(.)\1*

Gantilah dengan panjang total pertandingan, digabungkan dengan karakter dari grup tangkapan 1:

$.0$1
Kevin Cruijssen
sumber
0

Python 3 , 84 byte

def f(s,c=1):i,*j=s;b=j[:1]==[i];print(end='%s%s'%(c,i)*(b^1));f(j,1+b*c)
f(input())

Cobalah online!

Penjelasan

Cek apakah karakter pertama dan kedua dari string sama. Jika ya, tambah penghitung dengan 1. Jika tidak, cetak penghitung dan item pertama dan setel ulang penghitung ke 1. Dalam kedua kasus, fungsinya disebut secara rekursif dengan karakter pertama dihapus.

Meningkatkan kesalahan saat akhir string tercapai.


Tanpa batasan I / O, tetapi dengan jumlah byte minimal:

Python 3.8 (pra-rilis) , 70 byte

f=lambda s:'%s%s'%(len(s)-len(t:=s.lstrip(p:=s[0])),p)+f(t)if s else''

Cobalah online!

Setara Python 3 (77 byte)

Penjelasan

Lepaskan semua karakter berulang dari awal string. Kemudian mengembalikan string yang berisi (1.) perbedaan panjang antara string asli dan string yang dilucuti; (2.) karakter pertama dari string asli; (3.) hasil dari fungsi rekursif yang diterapkan pada string yang dilucuti. Rekursi berakhir ketika string kosong ditemukan.

Jitse
sumber
0

[Scala (shell)], 150 byte

scala.io.Source.stdin.getLines.foreach(s=>println{val(x,y,z)=s.tail.foldLeft(("",s.head,1)){case((a,b,c),d)=>if(b==d)(a,b,c+1)else(a+c+b,d,1)};x+z+y})

Cobalah online!

Di sini Lambda murni de-golf (103 byte):

  s => {
    val (x,y,z) = s.tail.foldLeft(("", s.head, 1)) {
      case ((a, b, c), d) =>
        if (b == d)
          (a, b, c + 1)
        else
          (a + c + b, d, 1)
    }
    x+z+y
  }
selada kubik
sumber
0

Julia 1.1 , 94 84 81 byte

foldl(((n,l),c)->(c==l||print(n,l);((c==l&&n)+1,c)),readline()*'\n',init=("",""))

Cobalah online!

Simeon Schaub
sumber
Ini adalah 80 byte . Saya pikir itu bisa lebih pendek
H.PWiz
Sayangnya, kode Anda tidak berfungsi pada Julia 1.1 untuk saya. Aku masih berhasil mendapatkan 81 dengan menambahkan ekstra '\n' untuk readline()bukannya mencetak tuple terakhir manual
Simeon Schaub
0

CJam , 2 byte

e`

e`adalah built-in untuk pengkodean run-length. Output implisit CJam mengabaikan tanda kurung array, dan karenanya berubah [[1 'h] [2 'e]]menjadi"1h2e"

Cobalah online!

lolad
sumber
0

Zsh, 70 byte

coba online!

for ((n=1;i++<#w;n++))[[ $w[i] != $w[i+1] ]]&&printf $n$w[i]&&n=0
echo

Ini adalah versi jauh lebih golf dari jawaban zsh sebelumnya ( tautan tio ). Mungkin bisa di-golf lebih banyak menggunakan konversi string => array daripada iterasi.

roblogic
sumber