Analysieren Sie ein Python-String-Literal

9

Die Herausforderung besteht darin, eine Zeichenfolge wie Python zu analysieren und den Inhalt der Zeichenfolge zu drucken.

  • Eingabe (Befehlszeilenargument oder stdin) : ein Zeichenfolgenliteral (z. B. "hello") (oder mehrere Literale, siehe Verkettung von Zeichenfolgenliteralen unten)
  • Output (stdout) : Der Inhalt der Zeichenfolge (z hello)

Regeln zum Parsen der Zeichenfolge:

  • Ein String-Literal ist in übereinstimmenden Paaren von einfachen Anführungszeichen ( 'a'), doppelten Anführungszeichen ( "a"), dreifachen einfachen Anführungszeichen ( '''a''') oder dreifachen doppelten Anführungszeichen ( """a""") enthalten. Das erste Wiederauftreten des Anführungszeichentyps, der die Zeichenfolge geöffnet hat, beendet die Zeichenfolge.
  • Backslash entweicht: \' Innerhalb einer Zeichenfolge wird ', \"wird "und \\wird \. Sie müssen keine weiteren Backslash-Escapezeichen implementieren. Ein Backslash, der nicht Teil einer Escape-Sequenz ist, bleibt ein Backslash.
  • Verkettung von Zeichenfolgenliteralen : Der Inhalt benachbarter Zeichenfolgenliterale wird verkettet. Zum Beispiel "hello" 'world'wird helloworld.
  • Die Eingabe kann Leerzeichen enthalten, die nicht Teil eines Literals sind.
  • Sie müssen keine anderen Leerzeichen unterstützen, weder innerhalb noch außerhalb von Literalen.

Zusätzliche Regeln:

  • eval, execUnd ähnliche Sachen sind nicht erlaubt für das Parsen der wörtlichen oder Teile davon.
  • Sie können davon ausgehen, dass die Eingabe gültig ist.
  • Sie können eine maximale Eingabelänge von 1023 Zeichen annehmen.

Beispiele:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (ohne Klammern, aber mit Leerzeichen) -> """'''

Der kürzeste Code gewinnt.

Flornbeben
quelle
Soll die Ausgabe eine Form haben, die gespeichert werden kann, oder reicht es aus, sie auszudrucken und damit fertig zu werden?
DavidC
@ David Printing ist alles, was Sie tun müssen.
Flornbeben
In (z. B.) "\ z" wird der Code speziell benötigt, um den Backslash und das z? Aber \ 'wird nur ein Apostroph, selbst wenn es in doppelten oder dreifachen Anführungszeichen erscheint? Ist das korrekt?
Brotkasten
@ Brotbox Genau.
Flornbeben
Sollte der Code Raw-Strings unterstützen? Und was ist mit der Verkettung von nicht rohen und rohen Zeichenfolgen?
Bakuriu

Antworten:

4

Perl, 54 Zeichen

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

Gerade als ich dies veröffentlichte, bemerkte ich, dass es fast identisch mit Jan Dvoraks Ruby-Lösung ist. Ich bin ein wenig verstört darüber, wie ähnlich es tatsächlich ist, aber ich werde sagen "Große Köpfe denken gleich" und es dabei loslassen.

Dieses Programm hebt einen seltsamen Eckfall beim Zählen von Zeichen in Perl-Skripten hervor: Beim Lesen bedeutet das Vorhandensein von einfachen Anführungszeichen im Skript, dass ich die -pOption als zwei Zeichen für meine Gesamtzahl zählen muss. Wenn Sie Perl-Skriptgrößen berechnen, wird das anfängliche Bindestrichzeichen für die Optionen normalerweise als frei angesehen, mit der Begründung, dass es mit dem Zeichen gebündelt werden kann -e, das das eigentliche Programm einführt. Dann müssen Sie jedoch auch zusätzliche Escapezeichen berücksichtigen Sie müssen das Skript in der Befehlszeile eingeben. Die einfachen Anführungszeichen erfordern viel Escapezeichen. Um diese Strafe zu vermeiden, muss ich sie als Skript zählen, das aus einer Datei ausgeführt wird. Daher erhalte ich die #!/usr/bin/perlkostenlosen, aber keine Optionszeichen. Es ist ein bisschen verwirrend.

Brot-Box
quelle
2
Wenn Sie anders sein wollen, (('|")\2{2}?)ist die gleiche Länge wie("""|'''|"|')
Peter Taylor
3

C, 178 Zeichen

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

Dies ist eine dieser C-Lösungen, bei denen alles innerhalb einer Kettenbande mit ternären Operatoren erledigt wird.

Das Programm kopiert Zeichen zurück in denselben Puffer und überschreibt die Metazeichen. dEnthält das Trennzeichen innerhalb einer Zeichenfolge und tist wahr, wenn das Trennzeichen ein dreifaches Anführungszeichen ist.

Brot-Box
quelle
Ich denke, Sie müssen eine bedingte zusätzliche Inkrementierung der Regelungsvariablen einschließen. Für 'foo \\' bar 'gibt es foo \ ar', das aussieht, als würde es \\ durch \ ersetzen, setzt dann aber das Parsen mit dem frisch eingegebenen \ fort und sieht das nächste Token als \ '.
Manatwork
Tatsächlich ist dieses Beispiel eine ungültige Eingabe. 'foo\\'bezieht sich auf die Zeichenfolge foo \, auf die dann ein Zeichen folgt, das weder ein Leerzeichen noch ein Zeichenfolgenbegrenzer ist.
Brotkasten
Hoppla. Ich habe diese Regel falsch verstanden. Dann ist Ihr Code natürlich korrekt.
Manatwork
3

Rubin, 74 73 Zeichen

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

Der Kern hier sind zwei reguläre Ausdrücke: Der erste bestimmt die Zeichenfolgengrenzen und wählt nur den Inhalt aus. Die Änderung dient dazu, alles zu entfernen, was nicht in Zeichenfolgen enthalten ist, und es werden auch nicht geschlossene Zeichenfolgen gelöscht.Backslashes werden als Possessiv-Optional behandelt, gefolgt von allem. Somit,Da die Regex-Engine (\\?.)für gültige Eingaben nicht zurückkehrt (danke @breadbox), kann dort kein einziger Backslash gefunden werden. Zitate werden durch faule Wiederholung behandelt. Der zweite reguläre Ausdruck entfernt dann vor jedem entkommenen Zeichen einen Backslash. Die Regex hängt vom Motor ab, um immer zuerst die Alternative ganz links auszuwählen.

Ich habe auch einen State-Machine-Ansatz in Betracht gezogen, der sich jedoch im Vergleich zur Regex-Lösung als ziemlich groß herausstellte (19 Zustände x 4 Zeichenklassen). Ich kann die Zustandsmaschine immer noch posten, wenn jemand interessiert ist.

John Dvorak
quelle
Ein kleiner Fehler bei dieser Methode: 'foo \\' bar 'wird zu foo \ anstelle von' foo \ 'bar'.
Manatwork
@manatwork Dies ist korrekt, es sei denn, bei der Formatierung ist etwas verloren gegangen. Der erste Backslash entgeht dem zweiten. 'foo\\'ist die erste Zeichenfolge und bar'befindet sich außerhalb eines Zeichenfolgenkontexts, wenn die Eingabe lautet'foo\\'bar'
John Dvorak
Hoppla. Keine Ahnung, wie ich es früher berechnet habe. Natürlich ist es richtig. Es tut uns leid.
Manatwork
Wenn ich versuche, dies auszuführen, erhalte ich die Fehlermeldung "verschachtelt *? + In regulärer Ausdruck". Gibt es eine Mindestversion oder ein Laufzeitflag, die ich benötige?
Brotkasten
@breadbox Ich habe keine anderen Versionen überprüft, aber ich verwende Ruby 1.9.3 (JRuby 1.7.2). sollte ich mindestens 1.9.3 annehmen und das in bearbeiten?
John Dvorak