Esempio n. 1
0
 def correct_first_two_dactyls(self, scansion: str) -> str:
     """If a hexameter or pentameter starts with spondee,
     an unstressed syllable in the third position must actually be stressed,
     so we will convert it: - - | U    ->  - - | -
     And/or if the starting pattern is spondee + trochee + stressed, then the unstressed
     trochee can be corrected: - - | - u | -   ->  - - | - -| -
     :param scansion:
     :return:
     >>> print(VerseScanner().correct_first_two_dactyls(
     ... " -   - U   U -  -  U U U U  U U  - -")) # doctest: +NORMALIZE_WHITESPACE
      -   - -   - -  -  U U U U  U U  - -
     """
     mark_list = StringUtils.mark_list(scansion)
     new_line = self.correct_invalid_start(scansion)
     raw_scansion = new_line.replace(" ", "")
     if raw_scansion.startswith(self.constants.SPONDEE + self.constants.TROCHEE +
                                        self.constants.STRESSED):
         new_scansion = list(self.constants.SPONDEE + self.constants.SPONDEE
                             + self.constants.STRESSED + raw_scansion[5:])
         corrected = "".join(new_scansion)
         new_sequence = list(" " * len(scansion))
         for idx, car in enumerate(corrected):
             new_sequence[mark_list[idx]] = car
         return "".join(new_sequence)
     return new_line
Esempio n. 2
0
 def correct_first_two_dactyls(self, scansion: str) -> str:
     """If a hexameter or pentameter starts with spondee,
     an unstressed syllable in the third position must actually be stressed,
     so we will convert it: - - | U    ->  - - | -
     And/or if the starting pattern is spondee + trochee + stressed, then the unstressed
     trochee can be corrected: - - | - u | -   ->  - - | - -| -
     :param scansion:
     :return:
     >>> print(VerseScanner().correct_first_two_dactyls(
     ... " -   - U   U -  -  U U U U  U U  - -")) # doctest: +NORMALIZE_WHITESPACE
      -   - -   - -  -  U U U U  U U  - -
     """
     mark_list = StringUtils.mark_list(scansion)
     new_line = self.correct_invalid_start(scansion)
     raw_scansion = new_line.replace(" ", "")
     if raw_scansion.startswith(self.constants.SPONDEE +
                                self.constants.TROCHEE +
                                self.constants.STRESSED):
         new_scansion = list(self.constants.SPONDEE +
                             self.constants.SPONDEE +
                             self.constants.STRESSED + raw_scansion[5:])
         corrected = "".join(new_scansion)
         new_sequence = list(" " * len(scansion))
         for idx, car in enumerate(corrected):
             new_sequence[mark_list[idx]] = car
         return "".join(new_sequence)
     return new_line
Esempio n. 3
0
    def make_dactyls(self, scansion: str) -> str:
        """If a pentameter line has 14 syllables, it starts and ends with double dactyls.

        >>> print(PentameterScanner().make_dactyls("U  U  U  U  U  U  U  U  U  U  U  U  U  U"))
        -  U  U  -  U  U  -  -  U  U  -  U  U  U
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        new_vals = self.DACTYLIC_PENTAMETER[:-1] + vals[-1]
        corrected = "".join(new_vals)
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 4
0
    def make_spondaic(self, scansion: str) -> str:
        """If a pentameter line has 12 syllables, then it must start with double spondees.

        >>> print(PentameterScanner().make_spondaic("U  U  U  U  U  U  U  U  U  U  U  U"))
        -  -  -  -  -  -  U  U  -  U  U  U
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        new_vals = self.SPONDAIC_PENTAMETER[:-1] + vals[-1]
        corrected = "".join(new_vals)
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 5
0
    def correct_invalid_start(self, scansion: str) -> str:
        """The third syllable of a hendecasyllabic line is long, so we will convert it

        :param scansion:
        :return: scansion string with corrected start
        >>> print(HendecasyllableScanner().correct_invalid_start(
        ... "- U U  U U  - U   -  U - U").strip())
        - U -  U U  - U   -  U - U
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        corrected = vals[:2] + [self.constants.STRESSED] + vals[3:]
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 6
0
    def correct_invalid_start(self, scansion: str) -> str:
        """The third syllable of a hendecasyllabic line is long, so we will convert it

        :param scansion:
        :return: scansion string with corrected start
        >>> print(HendecasyllableScanner().correct_invalid_start(
        ... "- U U  U U  - U   -  U - U").strip())
        - U -  U U  - U   -  U - U
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        corrected = vals[:2] + [self.constants.STRESSED] + vals[3:]
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 7
0
    def correct_penultimate_dactyl_chain(self, scansion: str) -> str:
        """For pentameter the last two feet of the verse are predictable dactyls,
        and do not regularly allow substitutions.
        :param scansion: scansion line thus far
        :return: corrected line of scansion

        >>> print(PentameterScanner().correct_penultimate_dactyl_chain(
        ... "U  U  U  U  U  U  U  U  U  U  U  U  U  U"))
        U  U  U  U  U  U  U  -  U  U  -  U  U  U
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        n_vals = vals[:-7] + [self.constants.DACTYL + self.constants.DACTYL] + [vals[-1]]
        corrected = "".join(n_vals)
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 8
0
 def correct_invalid_start(self, scansion: str) -> str:
     """If a hexameter, hendecasyllables, or pentameter scansion starts with spondee,
     an unstressed syllable in the third position must actually be stressed,
     so we will convert it: - - | U    ->  - - | -
     :param scansion:
     :return:
     >>> print(VerseScanner().correct_invalid_start(
     ... " -   - U   U -  -  U U U U  U U  - -").strip())
     -   - -   - -  -  U U U U  U U  - -
     """
     mark_list = StringUtils.mark_list(scansion)
     raw_scansion = scansion.replace(" ", "")
     if raw_scansion.startswith(self.constants.SPONDEE + self.constants.UNSTRESSED):
         new_scansion = list(self.constants.SPONDEE + self.constants.SPONDEE + raw_scansion[4:])
         corrected = "".join(new_scansion)
         new_sequence = list(" " * len(scansion))
         for idx, car in enumerate(corrected):
             new_sequence[mark_list[idx]] = car
         return "".join(new_sequence)
     return scansion
Esempio n. 9
0
    def correct_antepenult_chain(self, scansion: str) -> str:
        """For hendecasyllables the last three feet of the verse are predictable
        and do not regularly allow substitutions.

        :param scansion: scansion line thus far
        :return: corrected line of scansion

        >>> print(HendecasyllableScanner().correct_antepenult_chain(
        ... "-U -UU UU UU UX").strip())
        -U -UU -U -U -X
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        new_vals = vals[:len(vals) - 6] + [self.constants.TROCHEE +
                                           self.constants.TROCHEE +
                                           self.constants.STRESSED] + vals[-1:]
        corrected = "".join(new_vals)
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 10
0
    def correct_antepenult_chain(self, scansion: str) -> str:
        """For hendecasyllables the last three feet of the verse are predictable
        and do not regularly allow substitutions.

        :param scansion: scansion line thus far
        :return: corrected line of scansion

        >>> print(HendecasyllableScanner().correct_antepenult_chain(
        ... "-U -UU UU UU UX").strip())
        -U -UU -U -U -X
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        new_vals = vals[:len(vals) - 6] + [
            self.constants.TROCHEE + self.constants.TROCHEE +
            self.constants.STRESSED
        ] + vals[-1:]
        corrected = "".join(new_vals)
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 11
0
 def correct_invalid_start(self, scansion: str) -> str:
     """If a hexameter, hendecasyllables, or pentameter scansion starts with spondee,
     an unstressed syllable in the third position must actually be stressed,
     so we will convert it: - - | U    ->  - - | -
     :param scansion:
     :return:
     >>> print(VerseScanner().correct_invalid_start(
     ... " -   - U   U -  -  U U U U  U U  - -").strip())
     -   - -   - -  -  U U U U  U U  - -
     """
     mark_list = StringUtils.mark_list(scansion)
     raw_scansion = scansion.replace(" ", "")
     if raw_scansion.startswith(self.constants.SPONDEE +
                                self.constants.UNSTRESSED):
         new_scansion = list(self.constants.SPONDEE +
                             self.constants.SPONDEE + raw_scansion[4:])
         corrected = "".join(new_scansion)
         new_sequence = list(" " * len(scansion))
         for idx, car in enumerate(corrected):
             new_sequence[mark_list[idx]] = car
         return "".join(new_sequence)
     return scansion
Esempio n. 12
0
    def correct_dactyl_chain(self, scansion: str) -> str:
        """Three or more unstressed accents in a row is a broken dactyl chain,
         best detected and processed backwards.

         Since this method takes a Procrustean approach to modifying the scansion pattern,
         it is not used by default in the scan method; however, it is available as an optional
         keyword parameter, and users looking to further automate the generation of scansion
         candidates should consider using this as a fall back.
        :param scansion: scansion with broken dactyl chain; inverted amphibrachs not allowed
        :return: corrected line of scansion

        >>> print(HexameterScanner().correct_dactyl_chain(
        ... "-   U U  -  - U U -  - - U U  - x"))
        -   - -  -  - U U -  - - U U  - x
        >>> print(HexameterScanner().correct_dactyl_chain(
        ... "-   U  U U  U -     -   -   -  -   U  U -   U")) # doctest: +NORMALIZE_WHITESPACE
        -   -  - U  U -     -   -   -  -   U  U -   U
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        #  ignore last two positions, save them
        feet = [vals.pop(), vals.pop()]
        length = len(vals)
        idx = length - 1
        while idx > 0:
            one = vals[idx]
            two = vals[idx - 1]
            if idx > 1:
                three = vals[idx - 2]
            else:
                three = ""
            # Dactyl foot is okay, no corrections
            if one == self.constants.UNSTRESSED and \
                            two == self.constants.UNSTRESSED and \
                            three == self.constants.STRESSED:
                feet += [one]
                feet += [two]
                feet += [three]
                idx -= 3
                continue
            # Spondee foot is okay, no corrections
            if one == self.constants.STRESSED and \
                            two == self.constants.STRESSED:
                feet += [one]
                feet += [two]
                idx -= 2
                continue
            # handle "U U U" foot as "- U U"
            if one == self.constants.UNSTRESSED and \
                            two == self.constants.UNSTRESSED and \
                            three == self.constants.UNSTRESSED:
                feet += [one]
                feet += [two]
                feet += [self.constants.STRESSED]
                idx -= 3
                continue
            # handle "U U -" foot as "- -"
            if one == self.constants.STRESSED and \
                            two == self.constants.UNSTRESSED and \
                            three == self.constants.UNSTRESSED:
                feet += [self.constants.STRESSED]
                feet += [self.constants.STRESSED]
                idx -= 2
                continue
            # handle "-  U" foot as "- -"
            if one == self.constants.UNSTRESSED and \
                            two == self.constants.STRESSED:
                feet += [self.constants.STRESSED]
                feet += [two]
                idx -= 2
                continue
        corrected = "".join(feet[::-1])
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)
Esempio n. 13
0
    def correct_dactyl_chain(self, scansion: str) -> str:
        """Three or more unstressed accents in a row is a broken dactyl chain,
         best detected and processed backwards.
         Since this method takes a Procrustean approach to modifying the scansion pattern,
         it is not used by default in the scan method; however, it is available as an optional
         keyword parameter, and users looking to further automate the generation of scansion
         candidates should consider using this as a fall back.
        :param scansion: scansion with broken dactyl chain; inverted amphibrachs not allowed
        :return: corrected line of scansion

        >>> print(HexameterScanner().correct_dactyl_chain(
        ... "-   U U  -  - U U -  - - U U  - x").strip())
        -   - -  -  - U U -  - - U U  - x
        >>> print(HexameterScanner().correct_dactyl_chain(
        ... "-   U  U U  U -     -   -   -  -   U  U -   U").strip())
        -   -  - U  U -     -   -   -  -   U  U -   U
        """
        mark_list = StringUtils.mark_list(scansion)
        vals = list(scansion.replace(" ", ""))
        #  ignore last two positions, save them
        feet = [vals.pop(), vals.pop()]
        length = len(vals)
        idx = length - 1
        while idx > 0:
            one = vals[idx]
            two = vals[idx - 1]
            if idx > 1:
                three = vals[idx - 2]
            else:
                three = ""
            # Dactyl foot is okay, no corrections
            if one == self.constants.UNSTRESSED and \
                            two == self.constants.UNSTRESSED and \
                            three == self.constants.STRESSED:
                feet += [one]
                feet += [two]
                feet += [three]
                idx -= 3
                continue
            # Spondee foot is okay, no corrections
            if one == self.constants.STRESSED and \
                            two == self.constants.STRESSED:
                feet += [one]
                feet += [two]
                idx -= 2
                continue
            # handle "U U U" foot as "- U U"
            if one == self.constants.UNSTRESSED and \
                            two == self.constants.UNSTRESSED and \
                            three == self.constants.UNSTRESSED:
                feet += [one]
                feet += [two]
                feet += [self.constants.STRESSED]
                idx -= 3
                continue
            # handle "U U -" foot as "- -"
            if one == self.constants.STRESSED and \
                            two == self.constants.UNSTRESSED and \
                            three == self.constants.UNSTRESSED:
                feet += [self.constants.STRESSED]
                feet += [self.constants.STRESSED]
                idx -= 2
                continue
            # handle "-  U" foot as "- -"
            if one == self.constants.UNSTRESSED and \
                            two == self.constants.STRESSED:
                feet += [self.constants.STRESSED]
                feet += [two]
                idx -= 2
                continue

        corrected = "".join(feet[::-1])
        new_line = list(" " * len(scansion))
        for idx, car in enumerate(corrected):
            new_line[mark_list[idx]] = car
        return "".join(new_line)