plint

French poetry validator
git clone https://a3nm.net/git/plint/
Log | Files | Refs | README

commit 3f9d9be40d8b538554d00b46dc3a00bcd6ece05e
parent abbbc1f5662f739b96c804ca7836988986e10fa0
Author: Antoine Amarilli <a3nm@a3nm.net>
Date:   Sun, 10 Jul 2011 21:50:50 -0400

cleanup, refactoring...

Diffstat:
common.py | 6++++++
hemistiches.py | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
poetlint.py | 64+++++-----------------------------------------------------------
3 files changed, 78 insertions(+), 59 deletions(-)

diff --git a/common.py b/common.py @@ -4,6 +4,12 @@ import unicodedata import re vowels = 'aeiouyœæ' +consonants = "[bcçdfghjklmnpqrstvwxz*-]" + +# Forbidden at the end of a hemistiche. "-ent" would also be forbidden +# in some cases but not others... +sure_end_fem = ['es', 'e'] + # http://stackoverflow.com/questions/517923/what-is-the-best-way-to-remove-accents-in-a-python-unicode-string def strip_accents_one(s, with_except): diff --git a/hemistiches.py b/hemistiches.py @@ -0,0 +1,67 @@ +from common import sure_end_fem + +hemis_types = { + 'ok' : '/', # correct + 'bad' : '!', # something wrong + 'cut' : ':', # falls at the middle of a word + 'fem' : '\\', # preceding word ends by a mute e + } + + +def check_spaces(align, pos): + if pos >= len(align): + # not enough syllabes for hemistiche + return "bad" + if align[pos] == ' ': + # word boundary here, so this is ok + return "ok" + # skip consonants + if not isinstance(align[pos], tuple): + return check_spaces(align, pos + 1) + # hemistiche falls at the middle of a word + return "cut" + +def check_hemistiche(align, pos, hem): + if pos >= len(align): + # not enough syllabes for hemistiche + return ("bad", pos) + if hem == 0: + # hemistiche should end here, check that this is a word boundary + return (check_spaces(align, pos), pos) + if hem < 0: + # hemistiche falls at the middle of a vowel cluster + return ("cut", pos) + # skip consonants + if not isinstance(align[pos], tuple): + return check_hemistiche(align, pos +1, hem) + # hemistiche is there, we should not have a feminine ending here + if hem == 1: + if pos + 1 >= len(align): + # not enough syllabes for hemistiche + return ("bad", pos) + if ((align[pos][0] + align[pos+1]).rstrip() in sure_end_fem): + # check that this isn't a one-syllabe wourd (which is allowed) + ok = False + for i in range(2): + for j in ' -': + if j in align[pos-i-1]: + ok = True + if not ok: + # hemistiche ends in feminine + return ("fem", pos) + return check_hemistiche(align, pos+1, hem - align[pos][1]) + +def check_hemistiches(align, hems): + """From a sorted list of distinct hemistiche positions, return a + dictionary which maps each position to the status of this + hemistiche""" + + result = {} + pos = 0 + h2 = 0 + for h in hems: + r, pos = check_hemistiche(align, pos, h-h2) + h2 = h + result[h] = r + return result + diff --git a/poetlint.py b/poetlint.py @@ -7,22 +7,12 @@ import haspirater import rhyme from pprint import pprint from vowels import possible_weights -from common import strip_accents, normalize, is_vowels - -consonants = "[bcçdfghjklmnpqrstvwxz*-]" - -# Forbidden at the end of a hemistiche. "-ent" would also be forbidden -# in some cases but not others... -sure_end_fem = ['es', 'e'] - -hemis_types = { - 'ok' : '/', # correct - 'bad' : '!', # something wrong - 'cut' : ':', # falls at the middle of a word - 'fem' : '\\', # preceding word ends by a mute e - } +from common import strip_accents, normalize, is_vowels, consonants, \ + sure_end_fem +from hemistiches import check_hemistiches def annotate_aspirated(word): + """Annotate aspirated 'h'""" if word[0] != 'h': return word if haspirater.lookup(word): @@ -30,40 +20,6 @@ def annotate_aspirated(word): else: return word -def check_spaces(align, pos): - if pos >= len(align): - return "bad" - if align[pos] == ' ': - return "ok" - if not isinstance(align[pos], tuple): - return check_spaces(align, pos + 1) - return "cut" - -def check_hemistiche(align, pos, hem): - if pos >= len(align): - return ("bad", pos) - if hem == 0: - return (check_spaces(align, pos), pos) - if hem < 0: - return ("cut", pos) - if not isinstance(align[pos], tuple): - return check_hemistiche(align, pos +1, hem) - if hem == 1: - if pos + 1 >= len(align): - # this is weird - return ("bad", pos) - if ((align[pos][0] + align[pos+1]).rstrip() in sure_end_fem): - # no feminine at hemistiche - # maybe it's a lone word? - ok = False - for i in range(2): - for j in ' -': - if j in align[pos-i-1]: - ok = True - if not ok: - #print ("refuse hemistiche", file=sys.stderr) - return ("fem", pos) - return check_hemistiche(align, pos+1, hem - align[pos][1]) def fit(chunks, pos, left): if pos >= len(chunks): @@ -324,16 +280,6 @@ class Template: #TODO cleanup return sum([x[1] for x in align if isinstance(x, tuple)]) - def check_hemis(self, pattern, align): - hemis = {} - pos = 0 - h2 = 0 - for h in pattern.hemistiches: - r, pos = check_hemistiche(align, pos, h-h2) - h2 = h - hemis[h] = r - return hemis - def rate(self, pattern, align): """Rate align according to pattern""" align, fem, hemis = align @@ -353,7 +299,7 @@ class Template: # compute alignments, check hemistiches, sort by score possible = parse(line, pattern.length + 2) possible = list(map((lambda p : (p[0], p[1], - self.check_hemis(pattern, p[0]))), possible)) + check_hemistiches(p[0], pattern.hemistiches))), possible)) possible = map((lambda x : (self.rate(pattern, x), x)), possible) possible = sorted(possible, key=(lambda x : x[0]))