Analizza una stringa Python letterale


9

La sfida è analizzare una stringa come fa Python e stampare il contenuto della stringa.

  • Input (argomento della riga di comando o stdin) : una stringa letterale (ad esempio "hello") (o più letterali, vedere la concatenazione letterale di stringa di seguito)
  • Output (stdout) : il contenuto della stringa (ad es. hello)

Regole per l'analisi della stringa:

  • Un letterale stringa è racchiuso tra coppie corrispondenti di virgolette singole ( 'a'), virgolette doppie ( "a"), triple virgolette singole ( '''a''') o triple virgolette doppie ( """a"""). La prima ripetizione del tipo di virgolette che ha aperto la stringa termina la stringa.
  • Backslash fuoriesce: \' all'interno di una stringa diventa ', \"diventa "e \\diventa \. Non è necessario implementare altre fughe di barra rovesciata. Una barra rovesciata che non fa parte di una sequenza di escape rimane una barra rovesciata.
  • Concatenazione letterale di stringa: i contenuti dei letterali di stringa adiacenti vengono concatenati. Ad esempio, "hello" 'world'diventa helloworld.
  • L'input può contenere spazi che non fanno parte di alcun valore letterale.
  • Non è necessario supportare alcun altro tipo di spazio bianco, né all'interno né all'esterno dei letterali.

Regole aggiuntive:

  • eval, execE roba simile non è consentito per l'analisi letterale o parti di esso.
  • Si può presumere che l'input sia valido.
  • È possibile assumere una lunghezza massima di input di 1023 caratteri.

Esempi:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (senza parentesi, ma con spazi) -> """'''

Il codice più corto vince.


L'output deve essere in un modulo che può essere archiviato o è sufficiente per stamparlo ed eseguirlo?
DavidC,

@David Printing è tutto ciò che devi fare.
terremoto del

Quindi in (ad es.) "\ Z", il codice è specificamente richiesto per produrre la barra rovesciata e la z? Ma \ 'diventa solo un apostrofo, anche se appare tra virgolette doppie o triple? È corretto?
breadbox,

@breadbox Esattamente.
terremoto del

Il codice dovrebbe supportare stringhe non elaborate? E la concatenazione di stringhe non grezze e grezze?
Bakuriu,

Risposte:


4

Perl, 54 caratteri

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

Proprio mentre stavo pubblicando questo, ho notato che è quasi identico alla soluzione Ruby di Jan Dvorak. Sono un po 'fuori di testa da quanto sia simile, in realtà, ma ho intenzione di dire "Le grandi menti pensano allo stesso modo" e lasciarlo andare.

Questo programma evidenzia uno strano caso angolare nel conteggio dei caratteri negli script Perl: secondo la mia lettura, la presenza di virgolette singole nello script significa che devo contare l' -popzione come due caratteri per il mio totale. In genere, quando si calcolano le dimensioni dello script Perl, il trattino iniziale sulle opzioni è considerato libero, sulla base della giustificazione che può essere combinato con quello -eche introduce il programma in modo corretto ... ma poi si deve anche tenere conto di eventuali escape extra devi inserire lo script dalla riga di comando. Le virgolette singole richiedono un sacco di escape, quindi per evitare tale penalità devo contarlo come uno script eseguito da un file, e quindi ottengo il carattere #!/usr/bin/perlgratuito, ma non i caratteri di opzione. È un po 'confuso.


2
Se vuoi essere diverso, ha (('|")\2{2}?)la stessa lunghezza di("""|'''|"|')
Peter Taylor,

3

C, 178 caratteri

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

Questa è una di quelle soluzioni in C in cui tutto è fatto all'interno di una banda di catena dell'operatore ternario.

Il programma funziona copiando i caratteri nello stesso buffer, sovrascrivendo i metacaratteri. dcontiene il delimitatore all'interno di una stringa ed tè vero se il delimitatore è una tripla virgoletta.


Penso che sia necessario includere un'incremento supplementare condizionale della variabile di controllo del ciclo. Per 'foo \\' bar 'dà foo \ ar', che sembra che sostituisca \\ con \, ma poi continua l'analisi con il appena immesso \, vedendo il token successivo come \ '.
arte

In realtà, quell'esempio è un input non valido. 'foo\\'si riferisce alla stringa foo \, che è quindi seguita da un carattere che non è né spazi bianchi né un delimitatore di stringa.
breadbox,

Ops. Ho letto male quella regola. Quindi ovviamente il tuo codice è corretto.
arte

3

Rubino, 74 73 caratteri

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

Il nucleo qui sono due regex: il primo determina i confini della stringa e seleziona solo il contenuto. L'alterazione è lì per rimuovere tutto ciò che non è all'interno delle stringhe e inoltre rilascia stringhe non chiuse.Le barre rovesciate vengono considerate come facoltative-opzionali seguite da qualsiasi cosa. Così,Poiché il motore regex non esegue il backtracking (\\?.)per input validi (grazie a @breadbox), una sola barra rovesciata non può corrispondere lì. Le citazioni vengono gestite tramite ripetizione pigra. La seconda regex quindi rimuove una barra rovesciata prima di ogni carattere sfuggente. Il regex dipende dal motore per scegliere sempre l'alternativa più a sinistra prima.

Ho anche considerato un approccio macchina-stato, ma si è rivelato abbastanza grande (19 stati x 4 classi di caratteri) rispetto alla soluzione regex. Posso comunque pubblicare la macchina statale se qualcuno è interessato.


Un piccolo inconveniente con questo metodo: 'foo \\' bar 'diventa foo \ invece di' foo \ 'bar'.
arte

@manatwork è corretto, a meno che qualcosa non sia stato perso nella formattazione. La prima barra rovesciata sfugge alla seconda. 'foo\\'è la prima stringa ed bar'è al di fuori di un contesto di stringa quando l'input è'foo\\'bar'
John Dvorak,

Ops. Non ho idea di come l'ho calcolato prima. Certo che è corretto. Scusate.
arte

Quando provo a eseguirlo, viene visualizzato un messaggio di errore: "nidificato *? + In regexp". C'è qualche versione minima o flag di runtime di cui ho bisogno?
breadbox,

@breadbox Non ho controllato altre versioni, ma sto eseguendo ruby ​​1.9.3 (JRuby 1.7.2). dovrei assumere 1.9.3 almeno e modificarlo in?
John Dvorak,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.