Analiza składni literału Pythona

9

Wyzwanie polega na przeanalizowaniu łańcucha, podobnie jak Python, i wydrukowaniu jego zawartości.

  • Dane wejściowe (argument wiersza polecenia lub standardowe wejście) : literał ciągu (np. "hello") (Lub wiele literałów, patrz konkatenacja literału ciągu poniżej)
  • Dane wyjściowe (standardowe wyjście) : zawartość ciągu (np. hello)

Zasady parsowania łańcucha:

  • Dosłowny ciąg jest ujęty w pasujące pary pojedynczych cudzysłowów ( 'a'), podwójnych cudzysłowów ( "a"), potrójnych pojedynczych cudzysłowów ( '''a''') lub potrójnych podwójnych cudzysłowów ( """a"""). Pierwszy powtórzenie typu cudzysłowów, które otworzyły łańcuch, kończy łańcuch.
  • Odwrotny ukośnik ucieka: \' w ciągu staje się ', \"staje się "i \\staje \. Nie musisz implementować żadnych innych znaków ucieczki odwrotnego ukośnika. Ukośnik odwrotny, który nie jest częścią sekwencji ucieczki, pozostaje ukośnikiem odwrotnym.
  • Łączenie literałów łańcuchowych: zawartość sąsiadujących literałów łańcuchowych jest łączona. Na przykład "hello" 'world'staje się helloworld.
  • Dane wejściowe mogą zawierać spacje, które nie są częścią żadnego literału.
  • Nie musisz obsługiwać żadnych innych białych znaków, ani w literałach, ani poza nimi.

Dodatkowe zasady:

  • eval, execi podobne rzeczy nie są parsowane przy analizie literału lub jego części.
  • Możesz założyć, że dane wejściowe są prawidłowe.
  • Możesz założyć, że maksymalna długość wejściowa wynosi 1023 znaki.

Przykłady:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (bez nawiasów, ale ze spacjami) -> """'''

Najkrótszy kod wygrywa.

trzęsienie ziemi
źródło
Czy wyjście ma mieć postać, którą można zapisać, czy wystarczy wydrukować go i zrobić z nim?
DavidC
@David Drukowanie to wszystko, co musisz zrobić.
trzęsienie ziemi
Więc w (np.) „\ Z” kod jest wymagany do wyprowadzenia odwrotnego ukośnika i z? Ale „staje się tylko apostrofem, nawet jeśli pojawia się w cudzysłowach lub potrójnych cudzysłowach? Czy to jest poprawne?
breadbox
@breadbox Dokładnie.
trzęsienie ziemi
Czy kod powinien obsługiwać nieprzetworzone ciągi znaków? A co z łączeniem łańcuchów nie-surowych i surowych?
Bakuriu

Odpowiedzi:

4

Perl, 54 znaki

#!/usr/bin/perl -p
s/ |("""|'''|"|')((\\?.)*?)\1/$2/g;s/\\(["'\\])/$1/g

Właśnie kiedy to pisałem, zauważyłem, że jest prawie identyczny z rozwiązaniem Ruby Jana Dvoraka. Jestem trochę zdziwiony tym, jak bardzo jest ono podobne, ale powiem „Wielkie umysły myślą podobnie” i pozwól temu odejść.

Ten program podkreśla dziwny przypadek narożny w liczeniu znaków w skryptach Perla: Po przeczytaniu obecność pojedynczych cudzysłowów w skrypcie oznacza, że ​​muszę policzyć -popcję jako dwa znaki w stosunku do mojej sumy. Zazwyczaj przy obliczaniu rozmiarów skryptu Perla początkowy znak myślnika na opcjach jest uważany za wolny, z uzasadnienia, że ​​można go połączyć z tym, -ektóry wprowadza odpowiedni program ... ale wtedy musisz również uwzględnić wszelkie dodatkowe znaki ucieczki musisz wpisać skrypt w wierszu polecenia. Pojedyncze cudzysłowy wymagają dużej liczby #!/usr/bin/perlznaków ucieczki, więc aby uniknąć kary, muszę je liczyć jako skrypt uruchamiany z pliku, a zatem otrzymuję za darmo, ale nie żadnych znaków opcji. To trochę mylące.

chlebak
źródło
2
Jeśli chcesz być inny, (('|")\2{2}?)ma taką samą długość jak("""|'''|"|')
Peter Taylor
3

C, 178 znaków

char*p,*q,b[1024];d;main(t){for(p=q=gets(b);*p=*q++;)
d?*p==92&!(*q-*p&&*q-34&&*q-39)?*p++=*q++:*p-d||t&&*q-d|q[1]-d?++p:
(d=0,q+=2*t):*p-32?d=*p,t=*q==d&q[1]==d,q+=2*t:0;puts(b);}

Jest to jedno z tych rozwiązań C, w których wszystko odbywa się w łańcuchu operatorów trójskładnikowych.

Program działa, kopiując znaki z powrotem do tego samego bufora, zastępując metaznaki. dtrzyma separator, gdy znajduje się w ciągu, i tjest prawdą, jeśli separator jest potrójny.

chlebak
źródło
Myślę, że musisz dołączyć warunkową dodatkową inkrementację zmiennej kontrolnej pętli. Dla 'foo \\' bar 'daje foo \ ar', który wygląda jakby zastąpił \\ przez \, ale następnie kontynuuje parsowanie ze świeżo wprowadzonym \, widząc następny token jako \ '.
manatwork
W rzeczywistości ten przykład jest nieprawidłowym wejściem. 'foo\\'odnosi się do ciągu foo \, po którym następuje znak, który nie jest ani białą spacją, ani ogranicznikiem łańcucha.
breadbox
Ups Źle odczytałem tę zasadę. Zatem oczywiście twój kod jest poprawny.
manatwork
3

Rubin, 74 73 znaki

puts gets.gsub(/('''|"""|'|")((\\?.)*?)\1|./,'\2').gsub /\\([\\'"])/,'\1'

Rdzeniem są tutaj dwa wyrażenia regularne: pierwszy określa granice ciągów i wybiera tylko zawartość. Zmiana polega na usunięciu wszystkiego, co nie jest wewnątrz łańcuchów, a także upuszcza niezamknięte łańcuchy.Odwrotne ukośniki są traktowane jako dodatnie-opcjonalne, po których następuje cokolwiek. A zatem,Ponieważ silnik (\\?.)wyrażeń regularnych nie będzie się przesuwał w celu uzyskania prawidłowych danych wejściowych (dzięki @breadbox), jedyny ukośnik odwrotny nie może się tam znaleźć. Cytaty są przetwarzane przez leniwe powtarzanie. Drugi regex następnie usuwa ukośnik przed każdą możliwą do ucieczki postacią. Wyrażenie regularne zależy od silnika, aby zawsze najpierw wybierać najbardziej lewą alternatywę.

Rozważyłem również podejście stan-maszyna, ale okazało się dość duże (19 stanów x 4 klasy znaków) w porównaniu do rozwiązania wyrażenia regularnego. Nadal mogę opublikować automat państwowy, jeśli ktoś jest zainteresowany.

John Dvorak
źródło
Jedna drobna usterka z tą metodą: „foo \\” bar ”staje się foo \ zamiast„ foo \ ”bar”.
manatwork
@manatwork jest to poprawne, chyba że coś zostało utracone w formatowaniu. Pierwszy ukośnik odwraca się od drugiego. 'foo\\'jest pierwszym ciągiem i bar'znajduje się poza kontekstem ciągu, gdy dane wejściowe to'foo\\'bar'
John Dvorak
Ups Nie mam pojęcia, jak to obliczyłem wcześniej. Oczywiście, że to prawda. Przepraszam.
manatwork
Podczas próby uruchomienia tego pojawia się komunikat o błędzie: „zagnieżdżony *? + W wyrażeniu regularnym”. Czy potrzebuję minimalnej flagi wersji lub środowiska wykonawczego?
breadbox
@breadbox Nie sprawdziłem innych wersji, ale korzystam z Ruby 1.9.3 (JRuby 1.7.2). powinienem założyć przynajmniej 1.9.3 i edytować to w?
John Dvorak,