plint

French poetry validator (local mirror of https://gitlab.com/a3nm/plint)
git clone https://a3nm.net/git/plint/
Log | Files | Refs | README

commit 5400e99e1a18bba2cd5d7a97442339e0a60cc843
parent cc5ea7bfcdfb88adbf85a24676b0e5992d605195
Author: Antoine Amarilli <a3nm@a3nm.net>
Date:   Tue, 13 Mar 2012 15:35:01 +0100

refactor rhyme

Diffstat:
rhyme.py | 126++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 70 insertions(+), 56 deletions(-)

diff --git a/rhyme.py b/rhyme.py @@ -11,6 +11,68 @@ NBEST = 5 # phonetic vowels vowel = list("Eeaio592O#@y%u") +class Constraint: + def __init__(self, phon, eye, aphon): + self.phon = phon # minimal number of common suffix phones + self.eye = eye # minimal number of common suffix letters + self.aphon = aphon # minimal number of common suffix vowel phones + + def mmax(self, a, b): + """max, with -1 representing infty""" + if a == -1 or b == -1: + return -1 + else: + return max(a, b) + + def restrict(self, c): + """take the max between us and constraint object c""" + if not c: + return + self.phon = self.mmax(self.phon, c.phon) + self.eye = self.mmax(self.eye, c.eye) + self.aphon = self.mmax(self.aphon, c.aphon) + +class Rhyme: + def __init__(self, line, constraint): + self.constraint = constraint + self.phon = lookup(line) + self.eye = line + + def match(self, phon, eye): + """limit our phon and eye to those which match phon and eye and which + respect constraints""" + new_phon = set() + for x in self.phon: + for y in phon: + val = phon_rhyme(x, y) + if val >= self.constraint.phon and self.constraint.phon >= 0: + new_phon.add(x[-val:]) + val = assonance_rhyme(x, y) + if val >= self.constraint.aphon and self.constraint.aphon >= 0: + new_phon.add(x[-val:]) + self.phon = new_phon + if self.eye: + val = eye_rhyme(self.eye, eye) + if val >= self.constraint.eye and self.constraint.eye >= 0: + self.eye = self.eye[-val:] + else: + self.eye = None + + def restrict(self, r): + """take the intersection between us and rhyme object r""" + self.constraint.restrict(r.constraint) + self.match(r.phon, r.eye) + + def feed(self, line, constraint=None): + """extend us with a line and a constraint""" + return self.restrict(Rhyme(line, constraint)) + + def satisfied(self): + return self.eye or len(self.phon) > 0 + + def print(self): + pprint(self.phon) + def suffix(x, y): """length of the longest common suffix of x and y""" bound = min(len(x), len(y)) @@ -19,7 +81,7 @@ def suffix(x, y): return i return bound -def rhyme(x, y): +def phon_rhyme(x, y): """are x and y acceptable phonetic rhymes?""" assert(isinstance(x, str)) assert(isinstance(y, str)) @@ -33,7 +95,7 @@ def strip_consonants(x): return str([a for a in x if a in vowel or a == 'j']) def assonance_rhyme(x, y): - return rhyme(strip_consonants(x), strip_consonants(y)) + return phon_rhyme(strip_consonants(x), strip_consonants(y)) def eye_rhyme(x, y): """value of x and y as an eye rhyme""" @@ -55,51 +117,6 @@ def lookup(s): frhyme.lookup(escape(a), NBEST)])), s)) return functools.reduce(concat_couples, sets, set([''])) -def init_rhyme(line, constraint): - """initialize a rhyme""" - return (lookup(line), line, constraint) - -def mmax(a, b): - """max, with -1 representing infty""" - if a == -1 or b == -1: - return -1 - else: - return max(a, b) - -def max_constraints(a, b): - # TODO get rid of that - return (mmax(a[0], b[0]), mmax(a[1], b[1]), mmax(a[2], b[2])) - -def check_rhyme(current, new): - oldp, old, old_constraints = current - new, new_constraints = new - constraints = max_constraints(new_constraints, old_constraints) - newp = lookup(new) - newp_r, new_r = match(oldp, old, newp, new, constraints) - return (newp_r, new_r, constraints) - -def match(ap, a, bp, b, constraints): - # ap is the possible pronunciations, a the only possible writing - normalc, eyec, assonancec = constraints - rp = set() - for x in ap: - for y in bp: - val = rhyme(x, y) - if val >= normalc and normalc >= 0: - rp.add(x[-val:]) - val = assonance_rhyme(x, y) - if val >= assonancec and assonancec >= 0: - rp.add(x[-val:]) - if a != None: - val = eye_rhyme(a, b) - if val >= eyec and eyec >= 0: - r = a[0][-val:] - else: - r = None - else: - r = None - return rp, r - #workaround for lexique def escape(t): return re.sub('œ', 'oe', re.sub('æ', 'ae', t)) @@ -112,17 +129,14 @@ if __name__ == '__main__': line = line.lower().strip().split(' ') if len(line) < 1: continue - constraint = (1, -1, -1) - np, p, c = init_rhyme(line[0], constraint) - pprint(np) - ok = True + constraint = Constraint(1, -1, -1) + rhyme = Rhyme(line[0], constraint) for x in line[1:]: - np, n, c = check_rhyme((np, p, c), (x, constraint)) - pprint(np) - if n == None and len(np) == 0: + rhyme.feed(x) + rhyme.print() + if not rhyme.satisfied(): print("No.") - ok = False break - if ok: + if rhyme.satisfied(): print ("Yes.")