Parsing format kamus Kutu Buku


42

Saya baru-baru ini memanjakan diri dalam beberapa nostalgia dalam bentuk Kutu Buku Deluxe:

Jika Anda belum pernah melihatnya, ini adalah permainan kata yang tujuannya adalah untuk menghubungkan ubin yang berdekatan untuk membentuk kata-kata. Untuk menentukan apakah string adalah kata yang valid, string akan diperiksa terhadap kamus internalnya, yang disimpan dalam format terkompresi yang terlihat seperti ini:

aa
2h
3ed
ing
s
2l
3iis
s
2rdvark
8s
4wolf
7ves

Aturan untuk membongkar kamus sederhana:

  1. Baca angka di awal baris, dan salin banyak karakter dari awal kata sebelumnya. (Jika tidak ada nomor, salin karakter sebanyak yang Anda lakukan terakhir kali.)

  2. Tambahkan huruf-huruf berikut ke kata.

Jadi, kata pertama kami adalah aa, diikuti oleh 2h, yang berarti "menyalin dua huruf pertama aadan menambahkan h," membentuk aah. Kemudian 3edmenjadi aahed, dan karena baris berikutnya tidak memiliki angka, kami menyalin 3 karakter lagi untuk membentuk aahing. Proses ini berlanjut di seluruh kamus. Kata-kata yang dihasilkan dari input sampel kecil adalah:

aa
aah
aahed
aahing
aahs
aal
aaliis
aals
aardvark
aardvarks
aardwolf
aardwolves

Tantangan Anda adalah melakukan pembongkaran ini dalam sesedikit mungkin byte.

Setiap baris input akan berisi nol atau lebih digit 0-9 diikuti oleh satu atau lebih huruf kecil a-z. Anda dapat mengambil input dan memberikan output sebagai daftar string, atau sebagai string tunggal dengan kata-kata yang dipisahkan oleh karakter selain 0-9/ a-z.

Berikut ini adalah test case kecil lainnya dengan beberapa case edge yang tidak dicakup dalam contoh:

abc cba 1de fg hi 0jkl mno abcdefghijk 10l
=> abc cba cde cfg chi jkl mno abcdefghijk abcdefghijl

Anda juga dapat menguji kode Anda pada kamus lengkap: input , output .


Apakah ada kemungkinan tidak ada nomor di baris kedua? Juga, dapatkah kita berasumsi bahwa tidak ada nomor kecuali 0akan memiliki nomor 0s?
Erik the Outgolfer

@EriktheOutgolfer Ya, itu mungkin; Saya telah menambahkan itu ke dalam test case. Dan ya, Anda dapat menganggap itu (dan juga jumlahnya tidak akan lebih besar dari panjang kata sebelumnya).
Gagang Pintu

11
Itu format kompresi yang lucu:]
Poke

1
The locateProgram menggunakan jenis encoding pada nama path.
Dan D.

Saya menulis program ini untuk penggunaan saya yang sebenarnya, sekitar 15 tahun yang lalu. Sayangnya saya tidak berpikir saya punya sumbernya lagi ...
hobbs

Jawaban:


13

Vim, 57 byte

:%s/\a/ &
:%norm +hkyiwjP
:g/\d/norm diw-@"yl+P
:%s/ //g

Cobalah online!


Apakah <H<Galih-alih penggantian yang terakhir akan berhasil?
Kritixi Lithos

@cowsquack Sayangnya, tidak. Setiap input yang tidak dimulai dengan angka meningkatkan jumlah spasi terdepan sehingga tidak ada cara untuk menjamin <solusi akan mengurangi waktu yang cukup.
DJMcMayhem

Saya pikir Anda bisa melakukan :%s/ *alih - alih penggantian terakhir untuk menghemat dua byte.
Dexter CD

10

JavaScript (ES6),  66 62  61 byte

a=>a.map(p=s=>a=a.slice([,x,y]=/(\d*)(.*)/.exec(s),p=x||p)+y)

Cobalah online!

Berkomentar

a =>                  // a[] = input, re-used to store the previous word
  a.map(p =           // initialize p to a non-numeric value
  s =>                // for each string s in a[]:
    a =               //   update a:
      a.slice(        //     extract the correct prefix from the previous word:
        [, x, y] =    //       load into x and y:
          /(\d*)(.*)/ //         the result of a regular expression which splits the new
          .exec(s),   //         entry into x = leading digits and y = trailing letters
                      //       this array is interpreted as 0 by slice()
        p = x || p    //       update p to x if x is not an empty string; otherwise leave
                      //       it unchanged; use this as the 2nd parameter of slice()
      )               //     end of slice()
      + y             //     append the new suffix
  )                   // end of map()

5

Perl 6 , 50 48 byte

-2 byte terima kasih kepada nwellnhof

{my$l;.map:{$!=S[\d*]=substr $!,0,$l [R||]=~$/}}

Cobalah online!

Port solusi Arnauld . Sobat, R||trik itu adalah rollercoaster dari 'Saya pikir ini bisa mungkin', untuk 'nah, itu tidak mungkin', untuk 'agak mungkin mungkin' dan akhirnya 'aha!'

Penjelasan:

{my$l;.map:{$!=S[\d*]=substr $!,0,$l [R||]=~$/}}
{                                              }  # Anonymous code block
 my$l;    # Declare the variable $l, which is used for the previous number
      .map:{                                  }  # Map the input list to
            $!=              # $! is used to save the previous word
               S[\d*]=       # Substitute the number for
                      substr $!,0    # A substring of the previous word
                                 ,              # With the length of 
                                           ~$0     # The num if it exists
                                  $l [R||]=        # Otherwise the previous num

Bagian yang $l [R||]=~$/diterjemahkan secara kasar $l= ~$/||+$ltetapi ... memiliki jumlah byte yang sama :(. Awalnya, ini menyimpan byte menggunakan variabel anonim sehingga my$lhilang tapi itu tidak berfungsi karena ruang lingkup sekarang substitusi, bukan kode kunci map. Baiklah. Bagaimanapun, Radalah metaoperator terbalik, sehingga membalik argumen ||, sehingga $lvariabel akhirnya diberi nomor baru ( ~$/) jika ada, jika tidak, itu sendiri lagi.

Itu bisa menjadi 47 byte jika Perl 6 tidak melempar kesalahan kompiler agak berlebihan untuk =~.


5

Ruby , 49 45 43 byte

$0=$_=$0[/.{0#{p=$_[/\d+/]||p}}/]+$_[/\D+/]

Cobalah online!

Penjelasan

$0=                                         #Previous word, assign the value of
   $_=                                      #Current word, assign the value of
      $0[/.{0#{              }}/]           #Starting substring of $0 of length p which is
               p=$_[/\d+/]||p               #defined as a number in the start of $_ if any 
                                 +$_[/\D+/] #Plus any remaining non-digits in $_

5

C, 65 57 byte

n;f(){char c[99];while(scanf("%d",&n),gets(c+n))puts(c);}

Cobalah online!

Penjelasan:

n;                     /* n is implicitly int, and initialized to zero. */

f() {                  /* the unpacking function. */

    char c[99];        /* we need a buffer to read into, for the longest line in
                          the full dictionary we need 12 + 1 bytes. */

    while(             /* loop while there is input left. */

        scanf("%d",&n) /* Read into n, if the read fails because this line
                          doesn't have a number n's value does not change.
                          scanf's return value is ignored. */

        ,              /* chain expressions with the comma operator. The loop
                          condition is on the right side of the comma. */

        gets(c+n))     /* we read into c starting from cₙ. c₀, c₁.. up to cₙ is
                          the shared prefix of the word we are reading and the
                          previous word. When gets is successful it returns c+n
                          else it will return NULL. When the loop condition is
                          NULL the loop exits. */

        puts(c);}      /* print the unpacked word. */

5

brainfuck , 201 byte

,[[[-<+>>>+<<]>-[---<+>]<[[-<]>>]<[-]>>[<<,>>>[-[-<++++++++++>]]++++<[->+<]-[----->-<]<]<]>>>[[>>]+[-<<]>>[[>>]+[<<]>>-]]+[>>]<[-]<[<<]>[->[>>]<+<[<<]>]>[>.>]+[>[-]<,.[->+>+<<]>>----------]<[<<]>-<<<,]

Cobalah online!

Membutuhkan baris tambahan di akhir input. Versi tanpa persyaratan ini lebih panjang 6 byte:

brainfuck , 207 byte

,[[[-<+>>>+<<]>-[---<+>]<[[-<]>>]<[-]>>[<<,>>>[-[-<++++++++++>]]++++<[->+<]-[----->-<]<]<]>>>[[>>]+[-<<]>>[[>>]+[<<]>>-]]+[>>]<[-]<[<<]>[->[>>]<+<[<<]>]>[>.>]+[>[-]<,[->+>+<<]>>[----------<.<]>>]<[<<]>-<<<,]

Cobalah online!

Kedua versi menganggap semua angka benar-benar kurang dari 255.

Penjelasan

Rekaman itu ditata sebagai berikut:

tempinputcopy 85 0 inputcopy number 1 a 1 a 1 r 1 d 0 w 0 o 0 l 0 f 0 ...

Sel "angka" sama dengan 0 jika tidak ada digit yang dimasukkan, dan n +1 jika angka n yang dimasukkan. Input diambil di sel bertanda "85".

,[                     take input and start main loop
 [                     start number input loop
  [-<+>>>+<<]          copy input to tempinputcopy and inputcopy
  >-[---<+>]           put the number 85 in the cell where input was taken
  <[[-<]>>]            test whether input is less than 85; ending position depends on result of comparison
                       (note that digits are 48 through 57 while letters are 97 through 122)
  <[-]>                clean up by zeroing out the cell that didn't already become zero
  >[                   if input was a digit:
   <<,>>               get next input character
   >[-[-<++++++++++>]] multiply current value by 10 and add to current input
   ++++                set number cell to 4 (as part of subtracting 47)
   <[->+<]             add input plus 10*number back to number cell
   -[----->-<]         subtract 51
  <]                   move to cell we would be at if input were a letter
 <]                    move to input cell; this is occupied iff input was a digit

                       part 2: update/output word

 >>>                   move to number cell
 [                     if occupied (number was input):
  [>>]+[-<<]>>         remove existing marker 1s and decrement number cell to true value
  [[>>]+[<<]>>-]       create the correct amount of marker 1s
 ]
 +[>>]<[-]             zero out cell containing next letter from previous word
 <[<<]>                return to inputcopy
 [->[>>]<+<[<<]>]      move input copy to next letter cell
 >[>.>]                output word so far
 +[                    do until newline is read:
  >[-]<                zero out letter cell
  ,.                   input and output next letter or newline
  [->+>+<<]            copy to letter cell and following cell
  >>----------         subtract 10 to compare to newline
 ]
 <[<<]>-               zero out number cell (which was 1 to make copy loop shorter)
 <<<,                  return to input cell and take input
]                      repeat until end of input

4

Python 3.6+, 172 195 156 123 122 121 104 byte

import re
def f(l,n=0,w=""):
 for s in l:t=re.match("\d*",s)[0];n=int(t or n);w=w[:n]+s[len(t):];yield w

Cobalah online!

Penjelasan

Saya menyerah, dan menggunakan Ekspresi Reguler. Ini menyimpan setidaknya 17 byte. :

t=re.match("\d*",s)[0]

Ketika string tidak dimulai dengan angka sama sekali, panjang string ini akan menjadi 0. Ini berarti:

n=int(t or n)

akan menjadi njika tkosong, dan int(t)sebaliknya.

w=w[:n]+s[len(t):]

menghapus angka dari ekspresi reguler yang ditemukan s(jika tidak ada angka yang ditemukan, itu akan menghapus 0karakter, meninggalkan tidak sdikunci) dan menggantikan semua kecuali nkarakter pertama dari kata sebelumnya dengan fragmen kata saat ini; dan:

yield w

menampilkan kata saat ini.


4

Haskell, 82 81 byte

tail.map concat.scanl p["",""]
p[n,l]a|[(i,r)]<-reads a=[take i$n++l,r]|1<2=[n,a]

Mengambil dan mengembalikan daftar string.

Cobalah online!

        scanl p["",""]        -- fold function 'p' into the input list starting with
                              -- a list of two empty strings and collect the
                              -- intermediate results in a list
  p [n,l] a                   -- 1st string of the list 'n' is the part taken form the last word
                              -- 2nd string of the list 'l' is the part from the current line
                              -- 'a' is the code from the next line
     |[(i,r)]<-reads a        -- if 'a' can be parsed as an integer 'i' and a string 'r'
       =[take i$n++l,r]       -- go on with the first 'i' chars from the last line (-> 'n' and 'l' concatenated) and the new ending 'r'
     |1<2                     -- if parsing is not possible
       =[n,a]                 -- go on with the previous beginning of the word 'n' and the new end 'a'
                              -- e.g. [         "aa",     "2h",      "3ed",       "ing"       ] 
                              -- ->   [["",""],["","aa"],["aa","h"],["aah","ed"],["aah","ing"]]
  map concat                  -- concatenate each sublist
tail                          -- drop first element. 'scanl' saves the initial value in the list of intermediate results. 

Sunting: -1 byte berkat @Nitrodon.


1
Berlawanan dengan kebijaksanaan golf Haskell yang biasa, Anda sebenarnya dapat menyimpan satu byte di sini dengan tidak mendefinisikan fungsi pembantu sebagai operator infiks.
Nitrodon

@Nitrodon: terlihat dengan baik! Terima kasih!
nimi

3

Japt, 19 18 17 bytes

Awalnya terinspirasi oleh solusi JS Arnauld .

;£=¯V=XkB ªV +XoB

Cobalah

                      :Implicit input of string array U
 £                    :Map each X
   ¯                  :  Slice U to index
      Xk              :    Remove from X
;       B             :     The lowercase alphabet (leaving only the digits or an empty string, which is falsey)
          ªV          :    Logical OR with V (initially 0)
    V=                :    Assign the result to V for the next iteration
             +        :  Append
              Xo      :  Remove everything from X, except
;               B     :   The lowercase alphabet
  =                   :  Reassign the resulting string to U for the next iteration

2

Jelly , 16 byte

⁹fØDVo©®⁸ḣ;ḟØDµ\

Cobalah online!

Bagaimana itu bekerja

⁹fØDVo©®⁸ḣ;ḟØDµ\  Main link. Argument: A (array of strings)

              µ\  Cumulatively reduce A by the link to the left.
⁹                     Yield the right argument.
  ØD                  Yield "0123456789".
 f                    Filter; keep only digits.
    V                 Eval the result. An empty string yields 0.
     o©               Perform logical OR and copy the result to the register.
       ®              Yield the value in the register (initially 0).
        ⁸ḣ            Head; keep that many character of the left argument.
          ;           Concatenate the result and the right argument.
            ØD        Yield "0123456789".
           ḟ          Filterfalse; keep only non-digits.


1

Retina 0.8.2 , 69 byte

+`((\d+).*¶)(\D)
$1$2$3
\d+
$*
+m`^((.)*(.).*¶(?<-2>.)*)(?(2)$)1
$1$3

Cobalah online! Tautan termasuk kasus uji yang lebih sulit. Penjelasan:

+`((\d+).*¶)(\D)
$1$2$3

Untuk semua baris yang dimulai dengan huruf, salin nomor dari baris sebelumnya, putar sampai semua baris dimulai dengan angka.

\d+
$*

Ubah nomornya menjadi unary.

+m`^((.)*(.).*¶(?<-2>.)*)(?(2)$)1
$1$3

Gunakan grup penyeimbang untuk mengganti semua 1dengan huruf yang sesuai dari baris sebelumnya. (Ini ternyata menjadi sedikit lebih golf daripada mengganti semua jalur 1s.)


1

Merah , 143 byte

func[b][a: charset[#"a"-#"z"]u: b/1 n: 0 foreach c b[parse c[copy m to a
p: copy s to end(if p<> c[n: do m]print u: rejoin[copy/part u n s])]]]

Cobalah online!



1

Groovy , 74 byte

{w="";d=0;it.replaceAll(/(\d*)(.+)/){d=(it[1]?:d)as int;w=w[0..<d]+it[2]}}

Cobalah online!

Penjelasan:

{                                                                        }  Closure, sole argument = it
 w="";d=0;                                                                  Initialize variables
          it.replaceAll(/(\d*)(.+)/){                                   }   Replace every line (since this matches every line) and implicitly return. Loop variable is again it
                                     d=(it[1]?:d)as int;                    If a number is matched, set d to the number as an integer, else keep the value
                                                        w=w[0..<d]+it[2]    Set w to the first d characters of w, plus the matched string


0

Perl 5 -p , 45 41 byte

s:\d*:substr($p,0,$l=$&+$l*/^\D/):e;$p=$_

Cobalah online!

Penjelasan:

s:\d*:substr($p,0,$l=$&+$l*/^\D/):e;$p=$_ Full program, implicit input
s:   :                           :e;      Replace
  \d*                                       Any number of digits
      substr($p,0,              )           By a prefix of $p (previous result or "")
                  $l=  +                      With a length (assigned to $l) of the sum
                     $&                         of the matched digits
                          *                     and the product
                        $l                        of $l (previous length or 0)
                           /^\D/                  and whether there is no number in the beginning (1 or 0)
                                                (product is $l if no number)
                                    $p=$_ Assign output to $p
                                          Implicit output


0

05AB1E , 20 19 17 byte

õUvyþDõÊi£U}Xyá«=

Cobalah secara online atau verifikasi semua kasus uji .

Penjelasan:

õ                  # Push an empty string ""
 U                 # Pop and store it in variable `X`
v                  # Loop `y` over the (implicit) input-list
 yþ                #  Push `y`, and leave only the digits (let's call it `n`)
   DõÊi  }         #  If it's NOT equal to an empty string "":
       £           #   Pop and push the first `n` characters of the string
        U          #   Pop and store it in variable `X`
          X        #  Push variable `X`
           yá      #  Push `y`, and leave only the letters
             «     #  Merge them together
              =    #  Print it (without popping)

0

Common Lisp, 181 byte

(do(w(p 0))((not(setf g(read-line t()))))(multiple-value-bind(a b)(parse-integer g :junk-allowed t)(setf p(or a p)w(concatenate'string(subseq w 0 p)(subseq g b)))(format t"~a~%"w)))

Cobalah online!

Tidak Disatukan:

(do (w (p 0))   ; w previous word, p previous integer prefix (initialized to 0)
    ((not (setf g (read-line t ()))))   ; read a line into new variable g
                                        ; and if null terminate: 
  (multiple-value-bind (a b)            ; let a, b the current integer prefix
      (parse-integer g :junk-allowed t) ; and the position after the prefix
    (setf p (or a p)                    ; set p to a (if nil (no numeric prefix) to 0)
          w (concatenate 'string        ; set w to the concatenation of prefix
             (subseq w 0 p)             ; characters from the previous word 
             (subseq g b)))             ; and the rest of the current line
    (format t"~a~%"w)))                 ; print the current word

Seperti biasa, pengidentifikasi panjang Common Lisp membuatnya sangat tidak cocok untuk PPCG.



0

C # (Visual C # Interactive Compiler) , 134 byte

a=>{int l=0,m,n;var p="";return a.Select(s=>{for(m=n=0;s[m]<58;n=n*10+s[m++]-48);return p=p.Substring(0,l=m>0?n:l)+s.Substring(m);});}

Cobalah online!

-9 byte terima kasih kepada @ASCIIHanya!

Kurang bermain golf ...

// a is an input list of strings
a=>{
  // l: last prefix length
  // m: current number of digits
  // n: current prefix length
  int l=0,m,n;
  // previous word
  var p="";
  // run a LINQ select against the input
  // s is the current word
  return a.Select(s=>{
    // nibble digits from start of the
    // current word to build up the
    // current prefix length
    for(m=n=0;
      s[m]<58;
      n=n*10+s[m++]-48);
    // append the prefix from the
    // previous word to the current
    // word and capture values
    // for the next iteration
    return
      p=p.Substring(0,l=m>0?n:l)+
      s.Substring(m);
  });
}


Itu cukup keren :) Saya berubah l=n>0?n:lmenjadi l=m>0?n:lkarena tidak mengambil kasing ketika garis dimulai dengan nol ( 0jkl). Terima kasih atas tipnya!
dana

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.