plint

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

commit ac34ae80c3be3f9f6b3569420478fb6b536c7a19
parent feed537f31169cea5f9c79556fe0c3ee91f19e99
Author: Antoine Amarilli <a3nm@a3nm.net>
Date:   Sun, 11 Aug 2019 01:12:22 +0200

fix handling of single-syllable words at end

concerns both rhyme gender and metric (when there are hyphens)

Diffstat:
verse.py | 51++++++++++++++++++++++++++++++++++++++-------------
versetest.py | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+), 13 deletions(-)

diff --git a/verse.py b/verse.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 import common -from common import apostrophes, consonants, normalize, is_consonants, is_vowels, sure_end_fem, strip_accents_one +from common import apostrophes, consonants, normalize, is_consonants, is_vowels, sure_end_fem, strip_accents_one, strip_accents import re import vowels import haspirater @@ -203,10 +203,22 @@ class Verse: # remove leading and trailing crap for w in self.chunks: for p in range(len(w)): + seen_space = False + seen_hyphen = False while len(w[p]['text']) > 0 and w[p]['text'][0] in ' -': + if w[p]['text'][0] == ' ': + seen_space = True + else: + seen_hyphen = True w[p]['text'] = w[p]['text'][1:] while len(w[p]['text']) > 0 and w[p]['text'][-1] in ' -': + if w[p]['text'][-1] == ' ': + seen_space = True + else: + seen_hyphen = True w[p]['text'] = w[p]['text'][:-1] + if seen_hyphen and not seen_space: + w[p]['had_hyphen'] = True # collapse empty chunks created by simplifications for i, w in enumerate(self.chunks): @@ -417,7 +429,7 @@ class Verse: self.possible = self.fit(0, 0, self.pattern.hemistiches) def contains_break(self, chunk): - return '-' in chunk['text'] or 'wordend' in chunk + return '-' in chunk['text'] or 'wordend' in chunk.keys() or 'had_hyphen' in chunk.keys() def possible_weights(self, pos): if self.template.options['diaeresis'] == "classical": @@ -455,8 +467,12 @@ class Verse: return possible return self.possible_weights(pos) if (pos == len(self.chunks) - 1 and self.chunks[pos]['text'] == 'e' and - pos > 0 and (self.chunks[pos-1]['text'].endswith('-c') or - self.chunks[pos-1]['text'].endswith('-j'))): + pos > 0 and (self.chunks[pos-1]['text'].endswith('-c') + or self.chunks[pos-1]['text'].endswith('-j') + or (self.chunks[pos-1]['text'] == 'c' + and 'had_hyphen' in self.chunks[pos-1].keys()) + or (self.chunks[pos-1]['text'] == 'j' + and 'had_hyphen' in self.chunks[pos-1].keys()))): return [0] # -ce and -je are elided if (pos >= len(self.chunks) - 1 and self.chunks[pos]['text'] in ['ie', 'ée']): @@ -476,17 +492,26 @@ class Verse: if self.text.endswith(a): # if vowel before, it must be fem try: - if self.text[-len(a)-1] in common.vowels: + if strip_accents(self.text[-len(a)-1]) in common.vowels: return ['F'] except IndexError: - return ['M', 'F'] - # check that this isn't a one-syllabe word - for i in range(4): - try: - if '-' in self.chunks[-i-1]['text'] or 'wordend' in self.chunks[-i-1]: - return ['M', 'F'] - except IndexError: - return ['M', 'F'] + # too short + if self.text == "es": + return ['M'] + else: + return ['F'] + # check that this isn't a one-syllabe word that ends with "es" + # => must be masculine as '-es' cannot be mute then + # => except if there is another vowel before ("fées") + if (self.text.endswith("es") and (len(self.text) == 2 or + strip_accents(self.text[-3]) not in common.vowels)): + for i in range(4): + try: + if ('had_hyphen' in self.chunks[-i-1].keys() or 'wordend' in + self.chunks[-i-1].keys()): + return ['M'] + except IndexError: + return ['M'] return ['F'] if not self.text.endswith('ent'): return ['M'] diff --git a/versetest.py b/versetest.py @@ -326,6 +326,62 @@ class SanityCheck2(unittest.TestCase): self.assertEqual(1, len(gend)) self.assertEqual('F', next(iter(gend))) +class Genders(unittest.TestCase): + def testSingleSyllJe(self): + text = "Patati patata patatatah où suis-je" + v = verse.Verse(text, template.Template(), template.Pattern("12")) + v.parse() + gend = v.genders() + self.assertTrue(v.valid()) + self.assertEqual(1, len(gend)) + self.assertEqual('F', next(iter(gend))) + + def testSingleSyllJeBis(self): + text = "Patati patata patatah la verrai-je" + v = verse.Verse(text, template.Template(), template.Pattern("12")) + v.parse() + gend = v.genders() + self.assertTrue(v.valid()) + self.assertEqual(1, len(gend)) + self.assertEqual('F', next(iter(gend))) + + def testSingleSyllLe(self): + text = "Patati patata patatata prends-le" + v = verse.Verse(text, template.Template(), template.Pattern("12")) + v.parse() + gend = v.genders() + self.assertTrue(v.valid()) + self.assertEqual(1, len(gend)) + self.assertEqual('F', next(iter(gend))) + + def testSingleSyllCe(self): + text = "Patati patata patatata mais qu'est-ce" + v = verse.Verse(text, template.Template(), template.Pattern("12")) + v.parse() + gend = v.genders() + self.assertTrue(v.valid()) + self.assertEqual(1, len(gend)) + self.assertEqual('F', next(iter(gend))) + + def testSingleSyllHyphen(self): + text = "Patati patata patata mange-les" + v = verse.Verse(text, template.Template(), template.Pattern("12")) + v.parse() + gend = v.genders() + self.assertTrue(v.valid()) + self.assertEqual(1, len(gend)) + self.assertEqual('M', next(iter(gend))) + + def testSingleSyllNoHyphen(self): + text = "Patati patata patata mange les" + v = verse.Verse(text, template.Template(), template.Pattern("12")) + v.parse() + gend = v.genders() + self.assertTrue(v.valid()) + self.assertEqual(1, len(gend)) + self.assertEqual('M', next(iter(gend))) + + class TemplateTest(unittest.TestCase): def testSingleHyphens(self): t = template.Template("12")