Kitap kurdu sözlük biçimini ayrıştırma


42

Son zamanlarda kendimi Bookworm Deluxe biçiminde bazı nostalji konusunda şımartıyorum:

Daha önce görmediyseniz, hedefin bitişik fayansları kelimeler oluşturmak için birbirine bağlamaktır. Bir dizgenin geçerli bir kelime olup olmadığını belirlemek için, bu kelimeye benzeyen sıkıştırılmış bir formatta saklanan kendi iç sözlüğüne göre kontrol eder:

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

Sözlüğü açmak için kurallar basit:

  1. Satırın başındaki numarayı okuyun ve önceki kelimenin başından itibaren bu kadar çok karakteri kopyalayın. (Sayı yoksa, en son yaptığınız kadar karakter kopyalayın.)

  2. Aşağıdaki harfleri kelimeye ekleyin.

Yani, bizim ilk kelime olup aa, ardından 2h"ilk iki harfini kopyalama aracı olan aaekleme ve hşekillendirme," aah. Sonra 3edolur aahedve bir sonraki satırın numarası olmadığından, tekrar oluşturmak için 3 karakter kopyalarız aahing. Bu işlem sözlüğün geri kalanında da devam eder. Küçük örnek girişinden elde edilen kelimeler:

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

Buradaki zorluk, bu paket açma işlemini olabildiğince az sayıda baytta yapmak.

Her giriş satırı, sıfır veya daha fazla rakamdan 0-9 sonra bir veya daha fazla küçük harf içerir a-z. Girdi alabilir ve çıktıları bir dize listesi olarak veya 0-9/ dışında herhangi bir karakterle ayrılmış sözcüklerle tek bir dize olarak verebilirsiniz a-z.

Örnekte ele alınmayan birkaç kenarlı durumu olan başka bir küçük test durumu:

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

Ayrıca, kodunuzu tüm sözlükte test edebilirsiniz: input , output .


İkinci satırda sayı olmaması ihtimali var mı? Ayrıca, 0lider sayısı dışında hiçbir sayının olmadığını varsayabilir miyiz 0?
Outgolfer Erik

@EriktheOutgolfer Evet, bu mümkün; Bunu test vakasına ekledim. Ve evet, bunu varsayabilirsiniz (bunun yanı sıra, sayı önceki kelimenin uzunluğundan daha büyük olmayacak).
Doorknob

11
Bu şirin bir sıkıştırma formatı var:]
Poke

1
locateProgram pathnames kodlayan bu tür kullanır.
Dan D.

Bu programı fiili kullanımım için yaklaşık 15 yıl önce yazdım. Ne yazık ki artık kaynağına sahip sanmıyorum ...
hobbs

Yanıtlar:



10

JavaScript (ES6),  66 62  61 bayt

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

Çevrimiçi deneyin!

Yorumlananlar

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 bayt

Nwellnhof sayesinde -2 bayt

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

Çevrimiçi deneyin!

Arnauld'un çözümünün limanı . Dostum, bu R||numara 'Sanırım mümkün olabilir', 'hayır, imkansız', 'belki de mümkün' ve nihayet 'aha!'

Açıklama:

{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

$l [R||]=~$/Bölüm kabaca çevirir $l= ~$/||+$lo bayt aynı miktarda var ... ama :(. Başlangıçta, anonim bir değişken kullanarak baytları kurtardı, böylece my$lgitti, fakat kapsam şimdi mapkod bloğu değil yerine geçti . Oh iyi. Her neyse, Rters meta-işlemcisidir, bu nedenle argümanlarını tersine çevirir ||, böylece $ldeğişken ~$/varsa yeni sayıya ( ) atanır , aksi takdirde yeniden.

Perl 6 için bir tür gereksiz derleyici hatası atmak olsaydı, 47 bayt olabilir =~.


5

Ruby , 49 45 43 bayt

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

Çevrimiçi deneyin!

açıklama

$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 bayt

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

Çevrimiçi deneyin!

Açıklama:

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 bayt

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

Çevrimiçi deneyin!

Giriş sonunda izleyen bir yeni satır gerektirir. Bu gereksinimi olmayan bir sürüm 6 bayttır:

beyin fırtınası , 207 bayt

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

Çevrimiçi deneyin!

Her iki sürüm de tüm sayıların kesinlikle 255'ten az olduğunu varsayar.

açıklama

Bant şu şekilde düzenlenmiştir:

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

Rakam girilmezse "sayı" hücresi 0'a, n sayısı ise n + 1 olur. "85" işaretli hücreye giriş yapılır.

,[                     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 bayt

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

Çevrimiçi deneyin!

açıklama

Mağarada bulundum ve Normal İfadeler kullandım. Bu en az 17 bayt kurtardı. :

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

Dize hiç bir rakam ile başlamazsa, bu dizenin uzunluğu olacaktır 0. Bu şu demek:

n=int(t or n)

olacak neğer tis boşaltın ve int(t)aksi.

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

Düzenli ifadenin bulduğu sayıyı kaldırır s(eğer sayı bulunmazsa, 0karakterleri kaldırır , karşılıksız sbırakılır) ve nönceki kelimenin ilk karakterlerinin dışındaki karakterleri geçerli sözcük parçasıyla değiştirir; ve:

yield w

Geçerli sözcüğü çıktılar.


4

Haskell, 82 81 bayt

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

Dizelerin bir listesini alır ve döndürür.

Çevrimiçi deneyin!

        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. 

Düzenleme: @ Nitrodon sayesinde -1 bayt.


1
Her zamanki Haskell golf kez sanıldığı gibi yapabilirsiniz aslında burada bir byte tasarruf değil , bir infix operatörü olarak yardımcı fonksiyonunu tanımlayan.
Nitrodon

@ Nitrodon: iyi benekli! Teşekkürler!
nimi

3

Japt, 19 18 17 bayt

Başlangıçta Arnauld'un JS çözümünden ilham aldı .

;£=¯V=XkB ªV +XoB

Dene

                      :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

Jöle , 16 bayt

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

Çevrimiçi deneyin!

Nasıl çalışır

⁹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 bayt

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

Çevrimiçi deneyin! Link daha zor test vakaları içerir. Açıklama:

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

Harflerle başlayan tüm satırlar için önceki satırdan sayıyı kopyalayın, tüm satırlar bir sayı ile başlayana kadar döngü yapın.

\d+
$*

Numarayı birliğe dönüştür.

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

Tüm 1s'leri önceki satırdaki ilgili harfle değiştirmek için dengeleme gruplarını kullanın . (Bu, s'nin tüm çalışmalarını değiştirmek yerine biraz daha golf sahası olduğu ortaya çıkar 1.)




1

Groovy , 74 bayt

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

Çevrimiçi deneyin!

Açıklama:

{                                                                        }  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 bayt

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

Çevrimiçi deneyin!

Açıklama:

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 bayt

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

Çevrimiçi deneyin veya tüm test durumlarını doğrulayın .

Açıklama:

õ                  # 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

Ortak Lisp, 181 bayt

(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)))

Çevrimiçi deneyin!

Ungolfed:

(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

Her zamanki gibi, Common Lisp'in uzun tanımlayıcıları onu PPCG için özellikle uygun yapmaz.



0

C # (Visual C # Etkileşimli Derleyici) , 134 bayt

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);});}

Çevrimiçi deneyin!

@ASCIIOnly sayesinde -9 bayt!

Daha az golf oynadım ...

// 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);
  });
}


Ne kadar güzel :) Ben değiştirdi l=n>0?n:liçin l=m>0?n:lbir çizgi sıfır ile başladığımda (dava açmıyorsun çünkü 0jkl). Bahşiş için teşekkürler!
Dana

0

Scala , 226 129 102 bayt

ASCII @ sadece burada çalışmaları için (ve Groovy cevap için) teşekkürler.

s=>{var(w,d,r)=("",0,"(\\d*)(.+)".r)
s map(_ match{case r(a,b)=>{if(a>"")d=a.toInt
w=w.take(d)+b}
w})}

Çevrimiçi deneyin!


: | her iki bağlantı da aynı
ASCII-yalnızca

evet, düzenleme. Nasıl döneceğimi bilmiyordum ve acelem vardı bu yüzden yaptığım şeyi değiştirmedim.
V. Courtois,



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.