ナンセンスだらけの本:リメリックを特定する


15

ご存知のように、リメリックは、AABBA韻を踏むスキームとアナペスティックメーター(それが何であれ)を備えた、短い5行の、時折みだらな詩です:

リムリックの不条理書く
言葉でライン1とライン5つの韻を
そして、あなたが数えてきたと同じように
彼らが第二と韻
四行目は、第三と韻必要があります

入力テキストが入力されると、入力が有効なライムリックであると考えられるかどうかを出力する最短のプログラムを作成する必要があります。入力は、オプションでコマンドラインまたは標準入力を介して行うことができ、出力は、オプションで単純な「Y」/「N」または信頼スコアのいずれかです。

正しいlimerickの別の例を次に示します。


が色と大きさに関して独特だった若い女性がいまし
た彼女がそれらを大きく開いたとき、
人々はすべて背を向け、
そして驚きで出発しました

しかし、以下の詩は明らかにされていない、それは韻しないため、リメリック:


スズメバチによって腕に刺された聖蜂の老人がいました。
「痛いですか?」
「いいえ、そうではありません
。スズメバチではなかったことをとてもうれしく思います。」

メーターがすべて間違っているので、これもそうではありません。

ベルリンの男が
自分のいる部屋を嫌っていた
と聞いた。
彼がため息をついて言う理由について尋ねたとき
、「昨夜、くまのくびきを勝ち取った祝賀会の周りに少数の愚か者がいた。ワールドカップ、そして彼らは本当に騒々しかったので、私は騒のために眠れませんでした。」

手がかり

入力がリメリックかどうかを判断するために使用できる手がかりのいくつかを次に示します。

  • リムリックの長さは常に5行です。
  • 1行目、2行目、5行目は韻を踏む必要があります。
  • 3行目と4行目は韻を踏む必要があります。
  • 1行目、2行目、5行目は約3x3 = 9の音節を持ち、3行目と4行目は2x3 = 6の音節を持っています

最初のものを除いて、これらのどれも厳格なものではないことに注意してください。100%の正確性評価は不可能です。

ルール

  • エントリは、少なくとも例1から3を決定論的な方法で正しく分類する必要があります。

  • あなたはされている(具体的に参照このコンテストのために設計されたコースプログラミング言語のを除いて、ご希望の任意のプログラミング言語を使用することができ、ここで)。

  • プログラミング言語の標準製品以外のライブラリを使用することはできません

  • このファイル(CMU Sphinxの発音辞書)が現在のディレクトリの「c」というファイルにあると仮定することできます

  • テスト入力用にハードコーディングすることは許可されていません。プログラムは一般的なlimerickカテゴライザーでなければなりません。

  • 入力は特別なフォーマット(例のように)なしでASCIIであると仮定することできますが、プログラムは中断によって混同されるべきではありません。

ボーナス

以下のボーナスが利用可能です:

  • あなたのプログラムは結果をライムリックとして出力しますか?150文字の長さのボーナスを差し引きます!
  • あなたのプログラムはソネットも正しく識別していますか?150文字の余分な長さのボーナスを差し引きます!
  • あなたのプログラムは、ソネットで使用されたときに、その結​​果をソネットとして出力しますか?追加の長さのボーナスを100文字引きます!

最後に...

あなたがあなたに値すると思うボーナスを言及し、あなたのスコアに到達するためにあなたのキャラクターの数からボーナスを引くことを忘れないでください。これはコードゴルフコンテストです。最短のエントリー(つまり、最低スコアのエントリー)が勝ちます。

より多くの(陽性)テストデータが必要な場合は、OEDILFまたはBook of Nonsenseをご覧ください。負のテストデータは簡単に作成できる必要があります。

幸運を!


これはcode-challengeボーナスのためです。タグの説明をお読みください
user80551

2
@ user80551 メタに関するコンセンサスそうではないようです。
ドアノブ

ボーナスの性質を明確にしたので、混乱が解消されることを願っています。
ワンダーナウタ14年

2
Goooooooo Bears!
alvonellos

ボーナスがわかりません。「Y」をライムリックの形で出力するにはどうすればよいですか?
squeamish ossifrage 14年

回答:


8

Python:400-150-150 = 100

私が思いつく最短のスクリプトは、それです...

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

...でも試してはいけません。提供された辞書を、出会うすべての単語に対して解析するため、非常に遅くなります。また、単語が辞書にない場合は常にエラーが生成されます。

テキストを経て合格したかどうかを認識:かかわらコードはまだ要件を満たしているSTDINするリムリック、ソネット、またはどちらもそれらのです。

あと20文字だけで、最適化されたバージョンは次のとおりです。

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

特徴

  • ソネットを認識できる(-150)
  • リメリックでリメリックに答える(-150)
  • 比較的高速:実行ごとに解析されるファイルは1つのみ

使用法

cat poem.txt | python poem-check.py

3つの異なる出力が可能です。

  • 入力が1であると言っているリマーリック
  • もしそうなら、入力は1ではないと言っているリマーリック
  • 入力がそのように認識される場合、「Sonnet」

説明付きの拡張コード

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)

かっこいいね!私はまだそれをテストしていませんが、これは「コマンドラインまたは標準入力を介して」入力を取得しますか?(質問を参照)?そうでない場合は、(おそらくそれを追加する必要がありますsys.stdin.read()open(sys.argv[1]).read()どこか)と再集計を。
さまようナウタ14年

はい!それを修正:)
マチューロディック14年

アルゴリズムは韻をどのようにチェックしますか?
DavidC 14年

質問でワンダーナウタによって提供されたファイルの助けを借りて!本当に助かりました。
マチューロディック14年

1
きちんとした!残念ながら、2回賛成できません。
ワンダーナウタ14年

2

ECMAScript 6(138ポイント。Firefoxで試してください):

288- 150(@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!')

ノート:

cプレーンなECMAScriptではファイルを読み取ることができないため、変数には辞書ファイルの内容が含まれることが期待されます。

ECMAScriptには標準入力はありませんが、prompt一般に「標準入力」と見なされます。ただし、promptほとんどの(すべてではないにしても)ブラウザーで改行をスペースに変換するため、変数からの入力を受け入れていますi

未ゴルフコード:

// 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!');

きちんとした!ただし、これは「コマンドラインまたは標準入力からの入力」を必要としません。これは質問で必要です。Node.jsなどを使用するように書き直すことができます。
さまようナウタ14

@WanderNautaありがとうございます。標準入力を使用していない理由を説明していますので、最新の編集をご覧ください。
歯ブラシ14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.