Bücher voller Unsinn: Identifizieren Sie Limericks

15

Wie wir alle wissen, sind Limericks kurze, fünfzeilige, gelegentlich unzüchtige Gedichte mit einem AABBA-Reimschema und einer anapestischen Anzeige (was auch immer das ist):

Einen Limerick absurd schreiben
Zeile eins und Zeile fünf Reim in Wort
Und so wie du es dir vorgestellt hast
Reimen sie sich mit der zweiten
Die vierte Zeile muss sich mit der dritten reimen

Sie müssen das kürzeste Programm schreiben , das bei Eingabe eines Eingabetexts ausgibt, ob es den Eindruck hat, dass die Eingabe ein gültiger Limerick ist. Die Eingabe kann wahlweise über die Befehlszeile oder über die Standardeingabe erfolgen, und die Ausgabe kann wahlweise über ein einfaches "J" / "N" oder einen Vertrauensfaktor erfolgen.

Hier ist ein weiteres Beispiel für einen korrekten Limerick:

Es gab eine junge Dame, deren Augen
in Bezug auf Farbe und Größe einzigartig waren.
Als sie sie weit öffnete,
wandten sich alle ab
und gingen überrascht davon

Aber das Gedicht unten ist eindeutig kein Limerick, da es nicht reimt:

Es gab einen alten Mann von St. Bees
, der von einer Wespe in den Arm gestochen wurde.
Auf die Frage: "Tut es weh?"
Er antwortete: "Nein,
ich bin so froh, dass es keine Hornisse war."

Dies ist auch nicht der Fall, da der Zähler völlig falsch ist:

Ich hörte von einem Mann aus Berlin
, der das Zimmer, in dem er war, hasste.
Als ich fragte, warum
er mit einem Seufzer sagen würde:
"Nun, siehst du, letzte Nacht waren ein paar Trottel in der Nähe, die die Bären feierten, die die Verdammten gewannen WM, und sie waren sehr laut, so dass ich wegen des Lärms nicht schlafen konnte. "

Hinweise

Hier sind einige Hinweise, anhand derer Sie entscheiden können, ob Ihre Eingabe ein Limerick ist oder nicht:

  • Limericks sind immer fünf Zeilen lang.
  • Die Zeilen 1, 2 und 5 sollten sich reimen.
  • Die Zeilen 3 und 4 sollten sich reimen.
  • Die Zeilen 1, 2 und 5 haben ungefähr 3x3 = 9 Silben, während die dritte und vierte Zeile 2x3 = 6 Silben haben

Beachten Sie, dass mit Ausnahme der ersten keine davon schnell und zuverlässig ist: Eine 100% ige Korrektheitsbewertung ist nicht möglich.

Regeln

  • Ihr Beitrag sollte zumindest die Beispiele 1 bis 3 deterministisch kategorisieren.

  • Sie sind erlaubt jede Programmiersprache verwenden würden Sie, außer natürlich Programmiersprachen speziell für diesen Wettbewerb (siehe entworfen , um wie hier ).

  • Sie sind nicht jede Bibliothek außer Ihrer Programmiersprache Standardangebot zu nutzen.

  • Sie sind davon ausgehen darf , dass diese Datei , die CMU Sphinx pronounciation Wörterbuch, in einer Datei ist ‚c‘ im aktuellen Verzeichnis genannt.

  • Sie dürfen die Testeingaben nicht hart codieren: Ihr Programm sollte ein allgemeines Limerick-Kategorisierungsprogramm sein.

  • Sie sind erlaubt , anzunehmen , dass die Eingabe ASCII ist, ohne spezielle Formatierung (wie in den Beispielen), aber Ihr Programm soll nicht von Interpunktion verwechselt werden.

Boni

Folgende Boni stehen zur Verfügung:

  • Ihr Programm gibt das Ergebnis als Limerick aus? Subtrahieren 150 Zeichen Länge Bonus!
  • Ihr Programm erkennt auch Sonette korrekt? Subtrahiere 150 zusätzliche Zeichen !
  • Ihr Programm gibt das Ergebnis als Sonett aus, wenn es auf einem Sonett verwendet wird. Subtrahiere 100 zusätzliche zusätzliche Zeichen !

Schließlich...

Denken Sie daran, zu erwähnen, welche Boni Sie Ihrer Meinung nach verdient haben, und subtrahieren Sie den Bonus von der Anzahl Ihrer Charaktere, um Ihre Punktzahl zu erreichen. Dies ist ein Code-Golf- Wettbewerb: Der kürzeste Eintrag (dh der Eintrag mit der niedrigsten Punktzahl) gewinnt.

Wenn Sie mehr (positive) Testdaten benötigen, lesen Sie die OEDILF oder das Book of Nonsense . Negative Testdaten sollten einfach zu konstruieren sein.

Viel Glück!

Wandern Nauta
quelle
Dies sollte code-challengean den Boni liegen. Bitte lesen Sie die Tag-Beschreibungen
user80551
2
@ user80551 Konsens über Meta scheint anders zu sein.
Türklinke
Ich habe die Art der Boni geklärt, ich hoffe, das klärt die Verwirrung.
Wander Nauta
2
Goooooooo Bären!
Alvonellos
Ich verstehe die Boni nicht. Wie soll ich "Y" in Form eines Limericks ausgeben?
Squeamish Ossifrage

Antworten:

8

Python: 400 - 150 - 150 = 100

Das kürzeste Skript, das ich mir einfallen lassen konnte, ist das ...

import re,sys;f,e,c=re.findall,lambda l,w:f('^'+w.upper()+'  (.+)',l),lambda*v:all([a[i]==a[v[0]]for i in v]);a=[sum([[e(l,w)[0].split()for l in open('c')if e(l,w)][0]for w in f(r'\w+',v)],[])[-2:]for v in sys.stdin];n=len(a);print n==14and c(0,3,4,7)*c(1,2,5,6)*c(8,11)*c(9,12)*c(10,13)*"Sonnet"or"For a critic\nOf limerick\nWell-equipped\nIs this script.\n%s limerick!"%(n==5and c(0,1,4)and c(2,3))

... aber versuche es nicht einmal. Es analysiert das bereitgestellte Wörterbuch für jedes Wort, das es trifft, und ist daher sehr langsam. Außerdem wird ein Fehler generiert, wenn ein Wort nicht im Wörterbuch enthalten ist.

Der Code erfüllt dennoch die Anforderungen: Erkennen, ob der über stdin übergebene Text ein Limerick, ein Sonett oder keiner von beiden ist.

Mit nur 20 weiteren Zeichen ist hier die optimierte Version:

import re,sys;f,e,c=re.findall,lambda l:f(r'^(\w+)  (.+)',l),lambda*v:all([a[i]==a[v[0]]for i in v]);d={e(l)[0][0]:e(l)[0][1].split()for l in open('c')if e(l)};a=[sum([d.get(w.upper(),[])for w in f(r'\w+',v)],[])[-2:]for v in sys.stdin];n=len(a);print n==14and c(0,3,4,7)*c(1,2,5,6)*c(8,11)*c(9,12)*c(10,13)*"Sonnet"or"For a critic\nOf limerick\nWell-equipped\nIs this script.\n%s limerick!"%(n==5and c(0,1,4)and c(2,3))

Eigenschaften

  • Sonette erkennen können (-150)
  • Antworten auf Limericks mit einem Limerick (-150)
  • relativ schnell: nur eine Datei parst pro Ausführung

Verwendung

cat poem.txt | python poem-check.py

3 verschiedene Ausgänge sind möglich:

  • Ein Limmerick sagt, dass der Eingang eins ist, wenn dies der Fall ist
  • Ein Limmerick sagt, dass der Eingang kein Eingang ist, wenn dies der Fall ist
  • "Sonett", wenn die Eingabe als solche erkannt wird

Erweiterter Code mit Erläuterungen

import re, sys

# just a shortened version of the 're.findall' function...
f = re.findall
# function used to parse a line of the dictionary
e = lambda l:f(r'^(\w+)  (.+)', l)

# create a cache of the dictionary, where each word is associated with the list of phonemes it contains
d = {e(l)[0][0]:e(l)[0][1].split(' ') for l in open('c') if e(l)}

# for each verse (line) 'v' found in the input 'sys.stdin', create a list of the phoneme it contains;
# the result array 'a' contains a list, each item of it corresponding to the last two phonemes of a verse
a = [sum([d.get(w.upper(), []) for w in f(r'\w+',v)],[])[-2:] for v in sys.stdin]

# let's store the length of 'a' in 'n'; it is actually the number of verses in the input
n = len(a)
# function used to compare the rhymes of the lines which indexes are passed as arguments
c = lambda*v:all([a[i] == a[v[0]] for i in v])

# test if the input is a sonnet, aka: it has 14 verses, verses 0, 3, 4 and 7 rhyme together, verses 1, 2, 5 and 6 rhyme together, verses 8 and 11 rhyme together, verses 9 and 12 rhyme together, verses 10 and 13 rhyme together
if n==14 and c(0,3,4,7) and c(1,2,5,6) and c(8,11) and c(9,12) and c(10,13):
    print("Sonnet")
else:
    # test if the input is a limerick, aka: it has 5 verses, verses 0, 1 and 4 rhyme together, verses 2 and 3 rhyme together
    is_limerick = n==5 and c(0,1,4) and c(2,3)
    print("For critics\nOf limericks,\nWell-equipped\nIs this script.\n%s limerick!", is_limmerick)
Mathieu Rodic
quelle
Sieht gut aus! Ich habe es noch nicht getestet, aber sind Sie sicher, dass die Eingabe "entweder über die Befehlszeile oder über die Standardeingabe" erfolgt (siehe Frage)? Wenn nicht, sollten Sie das hinzufügen (wahrscheinlich ein sys.stdin.read()oder open(sys.argv[1]).read()irgendwo) und nachzählen.
Wander Nauta
Okay! Korrigiert :)
Mathieu Rodic
Wie prüft der Algorithmus auf Reime?
DavidC
Mit Hilfe der von Wander Nauta zur Verfügung gestellten Datei in der Frage! Es hat wirklich geholfen.
Mathieu Rodic
1
Ordentlich! Schade, dass ich dich nicht zweimal unterstützen kann.
Wander Nauta
2

ECMAScript 6 (138 Punkte; versuchen Sie es in Firefox):

288- 150Punktebonus für das Einbeziehen von Limerick (eingeklemmt von @MathieuRodic).

a=i.split(d=/\r?\n/).map(x=>x.split(' '));b=/^\W?(\w+) .*? (\w+\d( [A-Z]+)*)$/;c.split('\r\n').map(x=>b.test(x)&&eval(x.replace(b,'d["$1"]="$2"')));e=f=>d[a[f][a[f].length-1]];alert('For critics\nOf limericks,\nWell-equipped\nIs this script.\n'+(a[4]&&e(0)==e(1)&e(0)==e(4))+' limerick!')

Anmerkungen:

Erwartet, dass die Variable cden Inhalt der Wörterbuchdatei enthält, da Sie keine Dateien in einfachem ECMAScript lesen können.

ECMAScript hat keine Standardeingabe, wird jedoch promptallgemein als "Standardeingabe" betrachtet. promptDa jedoch Zeilenumbrüche in den meisten (wenn nicht allen) Browsern in Leerzeichen umgewandelt werden, akzeptiere ich Eingaben von der Variablen i.

Ungolfed-Code:

// If you paste a string with multiple lines into a `prompt`, the browser replaces each line break with a space, for some reason.
//input = prompt();

// Split into lines, with each line split into words
lines = input.split('\n').map(x => x.split(' '));

dictionaryEntryRegEx = /^\W?(\w+) .*? (\w+\d( [A-Z]+)*)$/;
dictionary = {};
// Split it into
c.split(/\r?\n/).map(x => dictionaryEntryRegEx && eval(x.replace(dictionaryEntryRegEx, 'dictionary["$1"] = "$2"')));

// Get the last word in the line
getLastWordOfLine = (lineNumber) => dictionary[line[lineNumber][line[lineNumber].length - 1]]

alert('For critics\nOf limericks,\nWell-equipped\nIs this script.\n' + (lines[4] && getLastWordOfLine(0) === getLastWordOfLine(1) && getLastWordOfLine(0) === getLastWordOfLine(4)) + ' limerick!');
Zahnbürste
quelle
Ordentlich! Dies erfordert jedoch keine Eingabe über die Befehlszeile oder über die Standardeingabe, was für die Frage erforderlich ist. Vielleicht könnten Sie es umschreiben, um Node.js oder etwas anderes zu verwenden.
Wander Nauta
@ WanderNauta Danke. Bitte sehen Sie sich die neueste Bearbeitung an, da ich erkläre, warum ich nicht die Standardeingabe verwende.
Zahnbürste