abydos/phonetic/_phonet.py
def encode(self, word, mode=1, lang='de'):
        """Return the phonet code for a word.

        Parameters
        ----------
        word : str
            The word to transform
        mode : int
            The ponet variant to employ (1 or 2)
        lang : str
            ``de`` (default) for German, ``none`` for no language

        Returns
        -------
        str
            The phonet value

        Examples
        --------
        >>> pe = Phonet()
        >>> pe.encode('Christopher')
        'KRISTOFA'
        >>> pe.encode('Niall')
        'NIAL'
        >>> pe.encode('Smith')
        'SMIT'
        >>> pe.encode('Schmidt')
        'SHMIT'

        >>> pe.encode('Christopher', mode=2)
        'KRIZTUFA'
        >>> pe.encode('Niall', mode=2)
        'NIAL'
        >>> pe.encode('Smith', mode=2)
        'ZNIT'
        >>> pe.encode('Schmidt', mode=2)
        'ZNIT'

        >>> pe.encode('Christopher', lang='none')
        'CHRISTOPHER'
        >>> pe.encode('Niall', lang='none')
        'NIAL'
        >>> pe.encode('Smith', lang='none')
        'SMITH'
        >>> pe.encode('Schmidt', lang='none')
        'SCHMIDT'

        """
        phonet_hash = Counter()
        alpha_pos = Counter()

        phonet_hash_1 = Counter()
        phonet_hash_2 = Counter()

        def _initialize_phonet(lang):
            """Initialize phonet variables.

            Parameters
            ----------
            lang : str
                Language to use for rules

            """
            if lang == 'none':
                _phonet_rules = self._rules_no_lang
            else:
                _phonet_rules = self._rules_german

            phonet_hash[''] = -1

            # German and international umlauts
            for j in {
                'À',
                'Á',
                'Â',
                'Ã',
                'Ä',
                'Å',
                'Æ',
                'Ç',
                'È',
                'É',
                'Ê',
                'Ë',
                'Ì',
                'Í',
                'Î',
                'Ï',
                'Ð',
                'Ñ',
                'Ò',
                'Ó',
                'Ô',
                'Õ',
                'Ö',
                'Ø',
                'Ù',
                'Ú',
                'Û',
                'Ü',
                'Ý',
                'Þ',
                'ß',
                'Œ',
                'Š',
                'Ÿ',
            }:
                alpha_pos[j] = 1
                phonet_hash[j] = -1

            # "normal" letters ('A'-'Z')
            for i, j in enumerate('ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
                alpha_pos[j] = i + 2
                phonet_hash[j] = -1

            for i in range(26):
                for j in range(28):
                    phonet_hash_1[i, j] = -1
                    phonet_hash_2[i, j] = -1

            # for each phonetc rule
            for i in range(len(_phonet_rules)):
                rule = _phonet_rules[i]

                if rule and i % 3 == 0:
                    # calculate first hash value
                    k = _phonet_rules[i][0]

                    if phonet_hash[k] < 0 and (
                        _phonet_rules[i + 1] or _phonet_rules[i + 2]
                    ):
                        phonet_hash[k] = i

                    # calculate second hash values
                    if k and alpha_pos[k] >= 2:
                        k = alpha_pos[k]

                        j = k - 2
                        rule = rule[1:]

                        if not rule:
                            rule = ' '
                        elif rule[0] == '(':
                            rule = rule[1:]
                        else:
                            rule = rule[0]

                        while rule and (rule[0] != ')'):
                            k = alpha_pos[rule[0]]

                            if k > 0:
                                # add hash value for this letter
                                if phonet_hash_1[j, k] < 0:
                                    phonet_hash_1[j, k] = i
                                    phonet_hash_2[j, k] = i

                                if phonet_hash_2[j, k] >= (i - 30):
                                    phonet_hash_2[j, k] = i
                                else:
                                    k = -1

                            if k <= 0:
                                # add hash value for all letters
                                if phonet_hash_1[j, 0] < 0:
                                    phonet_hash_1[j, 0] = i

                                phonet_hash_2[j, 0] = i

                            rule = rule[1:]

        def _phonet(term, mode, lang):
            """Return the phonet coded form of a term.

            Parameters
            ----------
            term : str
                Term to transform
            mode : int
                The ponet variant to employ (1 or 2)
            lang : str
                ``de`` (default) for German, ``none`` for no language

            Returns
            -------
            str
                The phonet value

            """
            if lang == 'none':
                _phonet_rules = self._rules_no_lang
            else:
                _phonet_rules = self._rules_german

            char0 = ''
            dest = term

            if not term:
                return ''

            term_length = len(term)

            # convert input string to upper-case
            src = term.translate(self._upper_trans)

            # check "src"
            i = 0
            j = 0
            zeta = 0

            while i < len(src):
                char = src[i]

                pos = alpha_pos[char]

                if pos >= 2:
                    xpos = pos - 2

                    if i + 1 == len(src):
                        pos = alpha_pos['']
                    else:
                        pos = alpha_pos[src[i + 1]]

                    start1 = phonet_hash_1[xpos, pos]
                    start2 = phonet_hash_1[xpos, 0]
                    end1 = phonet_hash_2[xpos, pos]
                    end2 = phonet_hash_2[xpos, 0]

                    # preserve rule priorities
                    if (start2 >= 0) and ((start1 < 0) or (start2 < start1)):
                        pos = start1
                        start1 = start2
                        start2 = pos
                        pos = end1
                        end1 = end2
                        end2 = pos

                    if (end1 >= start2) and (start2 >= 0):
                        if end2 > end1:
                            end1 = end2

                        start2 = -1
                        end2 = -1
                else:
                    pos = phonet_hash[char]
                    start1 = pos
                    end1 = 10000
                    start2 = -1
                    end2 = -1

                pos = start1
                zeta0 = 0

                if pos >= 0:
                    # check rules for this char
                    while (_phonet_rules[pos] is None) or (
                        _phonet_rules[pos][0] == char
                    ):
                        if pos > end1:
                            if start2 > 0:
                                pos = start2
                                start1 = start2
                                start2 = -1
                                end1 = end2
                                end2 = -1
                                continue

                            break

                        if (_phonet_rules[pos] is None) or (
                            _phonet_rules[pos + mode] is None
                        ):
                            # no conversion rule available
                            pos += 3
                            continue

                        # check whole string
                        matches = 1  # number of matching letters
                        priority = 5  # default priority
                        rule = _phonet_rules[pos]
                        rule = rule[1:]

                        while (
                            rule
                            and (len(src) > (i + matches))
                            and (src[i + matches] == rule[0])
                            and not rule[0].isdigit()
                            and (rule not in '(-<^$')
                        ):
                            matches += 1
                            rule = rule[1:]

                        if rule and (rule[0] == '('):
                            # check an array of letters
                            if (
                                (len(src) > (i + matches))
                                and src[i + matches].isalpha()
                                and (src[i + matches] in rule[1:])
                            ):
                                matches += 1

                                while rule and rule[0] != ')':
                                    rule = rule[1:]

                                # if rule[0] == ')':
                                rule = rule[1:]

                        if rule:
                            priority0 = ord(rule[0])
                        else:
                            priority0 = 0

                        matches0 = matches

                        while rule and rule[0] == '-' and matches > 1:
                            matches -= 1
                            rule = rule[1:]

                        if rule and rule[0] == '<':
                            rule = rule[1:]

                        if rule and rule[0].isdigit():
                            # read priority
                            priority = int(rule[0])
                            rule = rule[1:]

                        if rule and rule[0:2] == '^^':
                            rule = rule[1:]

                        if (
                            not rule
                            or (
                                (rule[0] == '^')
                                and ((i == 0) or not src[i - 1].isalpha())
                                and (
                                    (rule[1:2] != '$')
                                    or (
                                        not (
                                            src[
                                                i + matches0 : i + matches0 + 1
                                            ].isalpha()
                                        )
                                        and (
                                            src[
                                                i + matches0 : i + matches0 + 1
                                            ]
                                            != '.'
                                        )
                                    )
                                )
                            )
                            or (
                                (rule[0] == '$')
                                and (i > 0)
                                and src[i - 1].isalpha()
                                and (
                                    (
                                        not src[
                                            i + matches0 : i + matches0 + 1
                                        ].isalpha()
                                    )
                                    and (
                                        src[i + matches0 : i + matches0 + 1]
                                        != '.'
                                    )
                                )
                            )
                        ):
                            # look for continuation, if:
                            # matches > 1 und NO '-' in first string */
                            pos0 = -1

                            start3 = 0
                            start4 = 0
                            end3 = 0
                            end4 = 0

                            if (
                                (matches > 1)
                                and src[i + matches : i + matches + 1]
                                and (priority0 != ord('-'))
                            ):
                                char0 = src[i + matches - 1]
                                pos0 = alpha_pos[char0]

                                if pos0 >= 2 and src[i + matches]:
                                    xpos = pos0 - 2
                                    pos0 = alpha_pos[src[i + matches]]
                                    start3 = phonet_hash_1[xpos, pos0]
                                    start4 = phonet_hash_1[xpos, 0]
                                    end3 = phonet_hash_2[xpos, pos0]
                                    end4 = phonet_hash_2[xpos, 0]

                                    # preserve rule priorities
                                    if (start4 >= 0) and (
                                        (start3 < 0) or (start4 < start3)
                                    ):
                                        pos0 = start3
                                        start3 = start4
                                        start4 = pos0
                                        pos0 = end3
                                        end3 = end4
                                        end4 = pos0

                                    if (end3 >= start4) and (start4 >= 0):
                                        if end4 > end3:
                                            end3 = end4

                                        start4 = -1
                                        end4 = -1
                                else:
                                    pos0 = phonet_hash[char0]
                                    start3 = pos0
                                    end3 = 10000
                                    start4 = -1
                                    end4 = -1

                                pos0 = start3

                            # check continuation rules for src[i+matches]
                            if pos0 >= 0:
                                while (_phonet_rules[pos0] is None) or (
                                    _phonet_rules[pos0][0] == char0
                                ):
                                    if pos0 > end3:
                                        if start4 > 0:
                                            pos0 = start4
                                            start3 = start4
                                            start4 = -1
                                            end3 = end4
                                            end4 = -1
                                            continue

                                        priority0 = -1

                                        # important
                                        break

                                    if (_phonet_rules[pos0] is None) or (
                                        _phonet_rules[pos0 + mode] is None
                                    ):
                                        # no conversion rule available
                                        pos0 += 3
                                        continue

                                    # check whole string
                                    matches0 = matches
                                    priority0 = 5
                                    rule = _phonet_rules[pos0]
                                    rule = rule[1:]

                                    while (
                                        rule
                                        and (
                                            src[
                                                i + matches0 : i + matches0 + 1
                                            ]
                                            == rule[0]
                                        )
                                        and (
                                            not rule[0].isdigit()
                                            or (rule in '(-<^$')
                                        )
                                    ):
                                        matches0 += 1
                                        rule = rule[1:]

                                    if rule and rule[0] == '(':
                                        # check an array of letters
                                        if src[
                                            i + matches0 : i + matches0 + 1
                                        ].isalpha() and (
                                            src[i + matches0] in rule[1:]
                                        ):
                                            matches0 += 1

                                            while rule and rule[0] != ')':
                                                rule = rule[1:]

                                            # if rule[0] == ')':
                                            rule = rule[1:]

                                    while rule and rule[0] == '-':
                                        # "matches0" is NOT decremented
                                        # because of
                                        #    "if (matches0 == matches)"
                                        rule = rule[1:]

                                    if rule and rule[0] == '<':
                                        rule = rule[1:]

                                    if rule and rule[0].isdigit():
                                        priority0 = int(rule[0])
                                        rule = rule[1:]

                                    if (
                                        not rule
                                        or
                                        # rule == '^' is not possible here
                                        (
                                            (rule[0] == '$')
                                            and not src[
                                                i + matches0 : i + matches0 + 1
                                            ].isalpha()
                                            and (
                                                src[
                                                    i
                                                    + matches0 : i
                                                    + matches0
                                                    + 1
                                                ]
                                                != '.'
                                            )
                                        )
                                    ):
                                        if matches0 == matches:
                                            # this is only a partial string
                                            pos0 += 3
                                            continue

                                        if priority0 < priority:
                                            # priority is too low
                                            pos0 += 3
                                            continue

                                        # continuation rule found
                                        break

                                    pos0 += 3

                                # end of "while"
                                if (priority0 >= priority) and (
                                    (_phonet_rules[pos0] is not None)
                                    and (_phonet_rules[pos0][0] == char0)
                                ):

                                    pos += 3
                                    continue

                            # replace string
                            if _phonet_rules[pos] and (
                                '<' in _phonet_rules[pos][1:]
                            ):
                                priority0 = 1
                            else:
                                priority0 = 0

                            rule = _phonet_rules[pos + mode]

                            if (priority0 == 1) and (zeta == 0):
                                # rule with '<' is applied
                                if (
                                    (j > 0)
                                    and rule
                                    and (
                                        (dest[j - 1] == char)
                                        or (dest[j - 1] == rule[0])
                                    )
                                ):
                                    j -= 1

                                zeta0 = 1
                                zeta += 1
                                matches0 = 0

                                while rule and src[i + matches0]:
                                    src = (
                                        src[0 : i + matches0]
                                        + rule[0]
                                        + src[i + matches0 + 1 :]
                                    )
                                    matches0 += 1
                                    rule = rule[1:]

                                if matches0 < matches:
                                    src = (
                                        src[0 : i + matches0]
                                        + src[i + matches :]
                                    )

                                char = src[i]
                            else:
                                i = i + matches - 1
                                zeta = 0

                                while len(rule) > 1:
                                    if (j == 0) or (dest[j - 1] != rule[0]):
                                        dest = (
                                            dest[0:j]
                                            + rule[0]
                                            + dest[min(len(dest), j + 1) :]
                                        )
                                        j += 1

                                    rule = rule[1:]

                                # new "current char"
                                if not rule:
                                    rule = ''
                                    char = ''
                                else:
                                    char = rule[0]

                                if (
                                    _phonet_rules[pos]
                                    and '^^' in _phonet_rules[pos][1:]
                                ):
                                    if char:
                                        dest = (
                                            dest[0:j]
                                            + char
                                            + dest[min(len(dest), j + 1) :]
                                        )
                                        j += 1

                                    src = src[i + 1 :]
                                    i = 0
                                    zeta0 = 1

                            break

                        pos += 3

                        if pos > end1 and start2 > 0:
                            pos = start2
                            start1 = start2
                            end1 = end2
                            start2 = -1
                            end2 = -1

                if zeta0 == 0:
                    if char and ((j == 0) or (dest[j - 1] != char)):
                        # delete multiple letters only
                        dest = (
                            dest[0:j] + char + dest[min(j + 1, term_length) :]
                        )
                        j += 1

                    i += 1
                    zeta = 0

            dest = dest[0:j]

            return dest

        _initialize_phonet(lang)

        word = unicode_normalize('NFKC', text_type(word))
        return _phonet(word, mode, lang)
def encode(self, word, mode=1, lang='de'):
        """Return the phonet code for a word.

        Parameters
        ----------
        word : str
            The word to transform
        mode : int
            The ponet variant to employ (1 or 2)
        lang : str
            ``de`` (default) for German, ``none`` for no language

        Returns
        -------
        str
            The phonet value

        Examples
        --------
        >>> pe = Phonet()
        >>> pe.encode('Christopher')
        'KRISTOFA'
        >>> pe.encode('Niall')
        'NIAL'
        >>> pe.encode('Smith')
        'SMIT'
        >>> pe.encode('Schmidt')
        'SHMIT'

        >>> pe.encode('Christopher', mode=2)
        'KRIZTUFA'
        >>> pe.encode('Niall', mode=2)
        'NIAL'
        >>> pe.encode('Smith', mode=2)
        'ZNIT'
        >>> pe.encode('Schmidt', mode=2)
        'ZNIT'

        >>> pe.encode('Christopher', lang='none')
        'CHRISTOPHER'
        >>> pe.encode('Niall', lang='none')
        'NIAL'
        >>> pe.encode('Smith', lang='none')
        'SMITH'
        >>> pe.encode('Schmidt', lang='none')
        'SCHMIDT'

        """
        phonet_hash = Counter()
        alpha_pos = Counter()

        phonet_hash_1 = Counter()
        phonet_hash_2 = Counter()

        def _initialize_phonet(lang):
            """Initialize phonet variables.

            Parameters
            ----------
            lang : str
                Language to use for rules

            """
            if lang == 'none':
                _phonet_rules = self._rules_no_lang
            else:
                _phonet_rules = self._rules_german

            phonet_hash[''] = -1

            # German and international umlauts
            for j in {
                'À',
                'Á',
                'Â',
                'Ã',
                'Ä',
                'Å',
                'Æ',
                'Ç',
                'È',
                'É',
                'Ê',
                'Ë',
                'Ì',
                'Í',
                'Î',
                'Ï',
                'Ð',
                'Ñ',
                'Ò',
                'Ó',
                'Ô',
                'Õ',
                'Ö',
                'Ø',
                'Ù',
                'Ú',
                'Û',
                'Ü',
                'Ý',
                'Þ',
                'ß',
                'Œ',
                'Š',
                'Ÿ',
            }:
                alpha_pos[j] = 1
                phonet_hash[j] = -1

            # "normal" letters ('A'-'Z')
            for i, j in enumerate('ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
                alpha_pos[j] = i + 2
                phonet_hash[j] = -1

            for i in range(26):
                for j in range(28):
                    phonet_hash_1[i, j] = -1
                    phonet_hash_2[i, j] = -1

            # for each phonetc rule
            for i in range(len(_phonet_rules)):
                rule = _phonet_rules[i]

                if rule and i % 3 == 0:
                    # calculate first hash value
                    k = _phonet_rules[i][0]

                    if phonet_hash[k] < 0 and (
                        _phonet_rules[i + 1] or _phonet_rules[i + 2]
                    ):
                        phonet_hash[k] = i

                    # calculate second hash values
                    if k and alpha_pos[k] >= 2:
                        k = alpha_pos[k]

                        j = k - 2
                        rule = rule[1:]

                        if not rule:
                            rule = ' '
                        elif rule[0] == '(':
                            rule = rule[1:]
                        else:
                            rule = rule[0]

                        while rule and (rule[0] != ')'):
                            k = alpha_pos[rule[0]]

                            if k > 0:
                                # add hash value for this letter
                                if phonet_hash_1[j, k] < 0:
                                    phonet_hash_1[j, k] = i
                                    phonet_hash_2[j, k] = i

                                if phonet_hash_2[j, k] >= (i - 30):
                                    phonet_hash_2[j, k] = i
                                else:
                                    k = -1

                            if k <= 0:
                                # add hash value for all letters
                                if phonet_hash_1[j, 0] < 0:
                                    phonet_hash_1[j, 0] = i

                                phonet_hash_2[j, 0] = i

                            rule = rule[1:]

        def _phonet(term, mode, lang):
            """Return the phonet coded form of a term.

            Parameters
            ----------
            term : str
                Term to transform
            mode : int
                The ponet variant to employ (1 or 2)
            lang : str
                ``de`` (default) for German, ``none`` for no language

            Returns
            -------
            str
                The phonet value

            """
            if lang == 'none':
                _phonet_rules = self._rules_no_lang
            else:
                _phonet_rules = self._rules_german

            char0 = ''
            dest = term

            if not term:
                return ''

            term_length = len(term)

            # convert input string to upper-case
            src = term.translate(self._upper_trans)

            # check "src"
            i = 0
            j = 0
            zeta = 0

            while i < len(src):
                char = src[i]

                pos = alpha_pos[char]

                if pos >= 2:
                    xpos = pos - 2

                    if i + 1 == len(src):
                        pos = alpha_pos['']
                    else:
                        pos = alpha_pos[src[i + 1]]

                    start1 = phonet_hash_1[xpos, pos]
                    start2 = phonet_hash_1[xpos, 0]
                    end1 = phonet_hash_2[xpos, pos]
                    end2 = phonet_hash_2[xpos, 0]

                    # preserve rule priorities
                    if (start2 >= 0) and ((start1 < 0) or (start2 < start1)):
                        pos = start1
                        start1 = start2
                        start2 = pos
                        pos = end1
                        end1 = end2
                        end2 = pos

                    if (end1 >= start2) and (start2 >= 0):
                        if end2 > end1:
                            end1 = end2

                        start2 = -1
                        end2 = -1
                else:
                    pos = phonet_hash[char]
                    start1 = pos
                    end1 = 10000
                    start2 = -1
                    end2 = -1

                pos = start1
                zeta0 = 0

                if pos >= 0:
                    # check rules for this char
                    while (_phonet_rules[pos] is None) or (
                        _phonet_rules[pos][0] == char
                    ):
                        if pos > end1:
                            if start2 > 0:
                                pos = start2
                                start1 = start2
                                start2 = -1
                                end1 = end2
                                end2 = -1
                                continue

                            break

                        if (_phonet_rules[pos] is None) or (
                            _phonet_rules[pos + mode] is None
                        ):
                            # no conversion rule available
                            pos += 3
                            continue

                        # check whole string
                        matches = 1  # number of matching letters
                        priority = 5  # default priority
                        rule = _phonet_rules[pos]
                        rule = rule[1:]

                        while (
                            rule
                            and (len(src) > (i + matches))
                            and (src[i + matches] == rule[0])
                            and not rule[0].isdigit()
                            and (rule not in '(-<^$')
                        ):
                            matches += 1
                            rule = rule[1:]

                        if rule and (rule[0] == '('):
                            # check an array of letters
                            if (
                                (len(src) > (i + matches))
                                and src[i + matches].isalpha()
                                and (src[i + matches] in rule[1:])
                            ):
                                matches += 1

                                while rule and rule[0] != ')':
                                    rule = rule[1:]

                                # if rule[0] == ')':
                                rule = rule[1:]

                        if rule:
                            priority0 = ord(rule[0])
                        else:
                            priority0 = 0

                        matches0 = matches

                        while rule and rule[0] == '-' and matches > 1:
                            matches -= 1
                            rule = rule[1:]

                        if rule and rule[0] == '<':
                            rule = rule[1:]

                        if rule and rule[0].isdigit():
                            # read priority
                            priority = int(rule[0])
                            rule = rule[1:]

                        if rule and rule[0:2] == '^^':
                            rule = rule[1:]

                        if (
                            not rule
                            or (
                                (rule[0] == '^')
                                and ((i == 0) or not src[i - 1].isalpha())
                                and (
                                    (rule[1:2] != '$')
                                    or (
                                        not (
                                            src[
                                                i + matches0 : i + matches0 + 1
                                            ].isalpha()
                                        )
                                        and (
                                            src[
                                                i + matches0 : i + matches0 + 1
                                            ]
                                            != '.'
                                        )
                                    )
                                )
                            )
                            or (
                                (rule[0] == '$')
                                and (i > 0)
                                and src[i - 1].isalpha()
                                and (
                                    (
                                        not src[
                                            i + matches0 : i + matches0 + 1
                                        ].isalpha()
                                    )
                                    and (
                                        src[i + matches0 : i + matches0 + 1]
                                        != '.'
                                    )
                                )
                            )
                        ):
                            # look for continuation, if:
                            # matches > 1 und NO '-' in first string */
                            pos0 = -1

                            start3 = 0
                            start4 = 0
                            end3 = 0
                            end4 = 0

                            if (
                                (matches > 1)
                                and src[i + matches : i + matches + 1]
                                and (priority0 != ord('-'))
                            ):
                                char0 = src[i + matches - 1]
                                pos0 = alpha_pos[char0]

                                if pos0 >= 2 and src[i + matches]:
                                    xpos = pos0 - 2
                                    pos0 = alpha_pos[src[i + matches]]
                                    start3 = phonet_hash_1[xpos, pos0]
                                    start4 = phonet_hash_1[xpos, 0]
                                    end3 = phonet_hash_2[xpos, pos0]
                                    end4 = phonet_hash_2[xpos, 0]

                                    # preserve rule priorities
                                    if (start4 >= 0) and (
                                        (start3 < 0) or (start4 < start3)
                                    ):
                                        pos0 = start3
                                        start3 = start4
                                        start4 = pos0
                                        pos0 = end3
                                        end3 = end4
                                        end4 = pos0

                                    if (end3 >= start4) and (start4 >= 0):
                                        if end4 > end3:
                                            end3 = end4

                                        start4 = -1
                                        end4 = -1
                                else:
                                    pos0 = phonet_hash[char0]
                                    start3 = pos0
                                    end3 = 10000
                                    start4 = -1
                                    end4 = -1

                                pos0 = start3

                            # check continuation rules for src[i+matches]
                            if pos0 >= 0:
                                while (_phonet_rules[pos0] is None) or (
                                    _phonet_rules[pos0][0] == char0
                                ):
                                    if pos0 > end3:
                                        if start4 > 0:
                                            pos0 = start4
                                            start3 = start4
                                            start4 = -1
                                            end3 = end4
                                            end4 = -1
                                            continue

                                        priority0 = -1

                                        # important
                                        break

                                    if (_phonet_rules[pos0] is None) or (
                                        _phonet_rules[pos0 + mode] is None
                                    ):
                                        # no conversion rule available
                                        pos0 += 3
                                        continue

                                    # check whole string
                                    matches0 = matches
                                    priority0 = 5
                                    rule = _phonet_rules[pos0]
                                    rule = rule[1:]

                                    while (
                                        rule
                                        and (
                                            src[
                                                i + matches0 : i + matches0 + 1
                                            ]
                                            == rule[0]
                                        )
                                        and (
                                            not rule[0].isdigit()
                                            or (rule in '(-<^$')
                                        )
                                    ):
                                        matches0 += 1
                                        rule = rule[1:]

                                    if rule and rule[0] == '(':
                                        # check an array of letters
                                        if src[
                                            i + matches0 : i + matches0 + 1
                                        ].isalpha() and (
                                            src[i + matches0] in rule[1:]
                                        ):
                                            matches0 += 1

                                            while rule and rule[0] != ')':
                                                rule = rule[1:]

                                            # if rule[0] == ')':
                                            rule = rule[1:]

                                    while rule and rule[0] == '-':
                                        # "matches0" is NOT decremented
                                        # because of
                                        #    "if (matches0 == matches)"
                                        rule = rule[1:]

                                    if rule and rule[0] == '<':
                                        rule = rule[1:]

                                    if rule and rule[0].isdigit():
                                        priority0 = int(rule[0])
                                        rule = rule[1:]

                                    if (
                                        not rule
                                        or
                                        # rule == '^' is not possible here
                                        (
                                            (rule[0] == '$')
                                            and not src[
                                                i + matches0 : i + matches0 + 1
                                            ].isalpha()
                                            and (
                                                src[
                                                    i
                                                    + matches0 : i
                                                    + matches0
                                                    + 1
                                                ]
                                                != '.'
                                            )
                                        )
                                    ):
                                        if matches0 == matches:
                                            # this is only a partial string
                                            pos0 += 3
                                            continue

                                        if priority0 < priority:
                                            # priority is too low
                                            pos0 += 3
                                            continue

                                        # continuation rule found
                                        break

                                    pos0 += 3

                                # end of "while"
                                if (priority0 >= priority) and (
                                    (_phonet_rules[pos0] is not None)
                                    and (_phonet_rules[pos0][0] == char0)
                                ):

                                    pos += 3
                                    continue

                            # replace string
                            if _phonet_rules[pos] and (
                                '<' in _phonet_rules[pos][1:]
                            ):
                                priority0 = 1
                            else:
                                priority0 = 0

                            rule = _phonet_rules[pos + mode]

                            if (priority0 == 1) and (zeta == 0):
                                # rule with '<' is applied
                                if (
                                    (j > 0)
                                    and rule
                                    and (
                                        (dest[j - 1] == char)
                                        or (dest[j - 1] == rule[0])
                                    )
                                ):
                                    j -= 1

                                zeta0 = 1
                                zeta += 1
                                matches0 = 0

                                while rule and src[i + matches0]:
                                    src = (
                                        src[0 : i + matches0]
                                        + rule[0]
                                        + src[i + matches0 + 1 :]
                                    )
                                    matches0 += 1
                                    rule = rule[1:]

                                if matches0 < matches:
                                    src = (
                                        src[0 : i + matches0]
                                        + src[i + matches :]
                                    )

                                char = src[i]
                            else:
                                i = i + matches - 1
                                zeta = 0

                                while len(rule) > 1:
                                    if (j == 0) or (dest[j - 1] != rule[0]):
                                        dest = (
                                            dest[0:j]
                                            + rule[0]
                                            + dest[min(len(dest), j + 1) :]
                                        )
                                        j += 1

                                    rule = rule[1:]

                                # new "current char"
                                if not rule:
                                    rule = ''
                                    char = ''
                                else:
                                    char = rule[0]

                                if (
                                    _phonet_rules[pos]
                                    and '^^' in _phonet_rules[pos][1:]
                                ):
                                    if char:
                                        dest = (
                                            dest[0:j]
                                            + char
                                            + dest[min(len(dest), j + 1) :]
                                        )
                                        j += 1

                                    src = src[i + 1 :]
                                    i = 0
                                    zeta0 = 1

                            break

                        pos += 3

                        if pos > end1 and start2 > 0:
                            pos = start2
                            start1 = start2
                            end1 = end2
                            start2 = -1
                            end2 = -1

                if zeta0 == 0:
                    if char and ((j == 0) or (dest[j - 1] != char)):
                        # delete multiple letters only
                        dest = (
                            dest[0:j] + char + dest[min(j + 1, term_length) :]
                        )
                        j += 1

                    i += 1
                    zeta = 0

            dest = dest[0:j]

            return dest

        _initialize_phonet(lang)

        word = unicode_normalize('NFKC', text_type(word))
        return _phonet(word, mode, lang)
def encode ( self , word , mode = 1 , lang = 'de' ) : phonet_hash = Counter ( ) alpha_pos = Counter ( ) phonet_hash_1 = Counter ( ) phonet_hash_2 = Counter ( ) def _initialize_phonet ( lang ) : """Initialize phonet variables.

            Parameters
            ----------
            lang : str
                Language to use for rules

            """ if lang == 'none' : _phonet_rules = self . _rules_no_lang else : _phonet_rules = self . _rules_german phonet_hash [ '' ] = - 1 # German and international umlauts for j in { 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß', 'Œ', 'Š', 'Ÿ', } : alpha_pos [ j ] = 1 phonet_hash [ j ] = - 1 # "normal" letters ('A'-'Z') for i , j in enumerate ( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ) : alpha_pos [ j ] = i + 2 phonet_hash [ j ] = - 1 for i in range ( 26 ) : for j in range ( 28 ) : phonet_hash_1 [ i , j ] = - 1 phonet_hash_2 [ i , j ] = - 1 # for each phonetc rule for i in range ( len ( _phonet_rules ) ) : rule = _phonet_rules [ i ] if rule and i % 3 == 0 : # calculate first hash value k = _phonet_rules [ i ] [ 0 ] if phonet_hash [ k ] < 0 and ( _phonet_rules [ i + 1 ] or _phonet_rules [ i + 2 ] ) : phonet_hash [ k ] = i # calculate second hash values if k and alpha_pos [ k ] >= 2 : k = alpha_pos [ k ] j = k - 2 rule = rule [ 1 : ] if not rule : rule = ' ' elif rule [ 0 ] == '(' : rule = rule [ 1 : ] else : rule = rule [ 0 ] while rule and ( rule [ 0 ] != ')' ) : k = alpha_pos [ rule [ 0 ] ] if k > 0 : # add hash value for this letter if phonet_hash_1 [ j , k ] < 0 : phonet_hash_1 [ j , k ] = i phonet_hash_2 [ j , k ] = i if phonet_hash_2 [ j , k ] >= ( i - 30 ) : phonet_hash_2 [ j , k ] = i else : k = - 1 if k <= 0 : # add hash value for all letters if phonet_hash_1 [ j , 0 ] < 0 : phonet_hash_1 [ j , 0 ] = i phonet_hash_2 [ j , 0 ] = i rule = rule [ 1 : ] def _phonet ( term , mode , lang ) : """Return the phonet coded form of a term.

            Parameters
            ----------
            term : str
                Term to transform
            mode : int
                The ponet variant to employ (1 or 2)
            lang : str
                ``de`` (default) for German, ``none`` for no language

            Returns
            -------
            str
                The phonet value

            """ if lang == 'none' : _phonet_rules = self . _rules_no_lang else : _phonet_rules = self . _rules_german char0 = '' dest = term if not term : return '' term_length = len ( term ) # convert input string to upper-case src = term . translate ( self . _upper_trans ) # check "src" i = 0 j = 0 zeta = 0 while i < len ( src ) : char = src [ i ] pos = alpha_pos [ char ] if pos >= 2 : xpos = pos - 2 if i + 1 == len ( src ) : pos = alpha_pos [ '' ] else : pos = alpha_pos [ src [ i + 1 ] ] start1 = phonet_hash_1 [ xpos , pos ] start2 = phonet_hash_1 [ xpos , 0 ] end1 = phonet_hash_2 [ xpos , pos ] end2 = phonet_hash_2 [ xpos , 0 ] # preserve rule priorities if ( start2 >= 0 ) and ( ( start1 < 0 ) or ( start2 < start1 ) ) : pos = start1 start1 = start2 start2 = pos pos = end1 end1 = end2 end2 = pos if ( end1 >= start2 ) and ( start2 >= 0 ) : if end2 > end1 : end1 = end2 start2 = - 1 end2 = - 1 else : pos = phonet_hash [ char ] start1 = pos end1 = 10000 start2 = - 1 end2 = - 1 pos = start1 zeta0 = 0 if pos >= 0 : # check rules for this char while ( _phonet_rules [ pos ] is None ) or ( _phonet_rules [ pos ] [ 0 ] == char ) : if pos > end1 : if start2 > 0 : pos = start2 start1 = start2 start2 = - 1 end1 = end2 end2 = - 1 continue break if ( _phonet_rules [ pos ] is None ) or ( _phonet_rules [ pos + mode ] is None ) : # no conversion rule available pos += 3 continue # check whole string matches = 1 # number of matching letters priority = 5 # default priority rule = _phonet_rules [ pos ] rule = rule [ 1 : ] while ( rule and ( len ( src ) > ( i + matches ) ) and ( src [ i + matches ] == rule [ 0 ] ) and not rule [ 0 ] . isdigit ( ) and ( rule not in '(-<^$' ) ) : matches += 1 rule = rule [ 1 : ] if rule and ( rule [ 0 ] == '(' ) : # check an array of letters if ( ( len ( src ) > ( i + matches ) ) and src [ i + matches ] . isalpha ( ) and ( src [ i + matches ] in rule [ 1 : ] ) ) : matches += 1 while rule and rule [ 0 ] != ')' : rule = rule [ 1 : ] # if rule[0] == ')': rule = rule [ 1 : ] if rule : priority0 = ord ( rule [ 0 ] ) else : priority0 = 0 matches0 = matches while rule and rule [ 0 ] == '-' and matches > 1 : matches -= 1 rule = rule [ 1 : ] if rule and rule [ 0 ] == '<' : rule = rule [ 1 : ] if rule and rule [ 0 ] . isdigit ( ) : # read priority priority = int ( rule [ 0 ] ) rule = rule [ 1 : ] if rule and rule [ 0 : 2 ] == '^^' : rule = rule [ 1 : ] if ( not rule or ( ( rule [ 0 ] == '^' ) and ( ( i == 0 ) or not src [ i - 1 ] . isalpha ( ) ) and ( ( rule [ 1 : 2 ] != '$' ) or ( not ( src [ i + matches0 : i + matches0 + 1 ] . isalpha ( ) ) and ( src [ i + matches0 : i + matches0 + 1 ] != '.' ) ) ) ) or ( ( rule [ 0 ] == '$' ) and ( i > 0 ) and src [ i - 1 ] . isalpha ( ) and ( ( not src [ i + matches0 : i + matches0 + 1 ] . isalpha ( ) ) and ( src [ i + matches0 : i + matches0 + 1 ] != '.' ) ) ) ) : # look for continuation, if: # matches > 1 und NO '-' in first string */ pos0 = - 1 start3 = 0 start4 = 0 end3 = 0 end4 = 0 if ( ( matches > 1 ) and src [ i + matches : i + matches + 1 ] and ( priority0 != ord ( '-' ) ) ) : char0 = src [ i + matches - 1 ] pos0 = alpha_pos [ char0 ] if pos0 >= 2 and src [ i + matches ] : xpos = pos0 - 2 pos0 = alpha_pos [ src [ i + matches ] ] start3 = phonet_hash_1 [ xpos , pos0 ] start4 = phonet_hash_1 [ xpos , 0 ] end3 = phonet_hash_2 [ xpos , pos0 ] end4 = phonet_hash_2 [ xpos , 0 ] # preserve rule priorities if ( start4 >= 0 ) and ( ( start3 < 0 ) or ( start4 < start3 ) ) : pos0 = start3 start3 = start4 start4 = pos0 pos0 = end3 end3 = end4 end4 = pos0 if ( end3 >= start4 ) and ( start4 >= 0 ) : if end4 > end3 : end3 = end4 start4 = - 1 end4 = - 1 else : pos0 = phonet_hash [ char0 ] start3 = pos0 end3 = 10000 start4 = - 1 end4 = - 1 pos0 = start3 # check continuation rules for src[i+matches] if pos0 >= 0 : while ( _phonet_rules [ pos0 ] is None ) or ( _phonet_rules [ pos0 ] [ 0 ] == char0 ) : if pos0 > end3 : if start4 > 0 : pos0 = start4 start3 = start4 start4 = - 1 end3 = end4 end4 = - 1 continue priority0 = - 1 # important break if ( _phonet_rules [ pos0 ] is None ) or ( _phonet_rules [ pos0 + mode ] is None ) : # no conversion rule available pos0 += 3 continue # check whole string matches0 = matches priority0 = 5 rule = _phonet_rules [ pos0 ] rule = rule [ 1 : ] while ( rule and ( src [ i + matches0 : i + matches0 + 1 ] == rule [ 0 ] ) and ( not rule [ 0 ] . isdigit ( ) or ( rule in '(-<^$' ) ) ) : matches0 += 1 rule = rule [ 1 : ] if rule and rule [ 0 ] == '(' : # check an array of letters if src [ i + matches0 : i + matches0 + 1 ] . isalpha ( ) and ( src [ i + matches0 ] in rule [ 1 : ] ) : matches0 += 1 while rule and rule [ 0 ] != ')' : rule = rule [ 1 : ] # if rule[0] == ')': rule = rule [ 1 : ] while rule and rule [ 0 ] == '-' : # "matches0" is NOT decremented # because of #    "if (matches0 == matches)" rule = rule [ 1 : ] if rule and rule [ 0 ] == '<' : rule = rule [ 1 : ] if rule and rule [ 0 ] . isdigit ( ) : priority0 = int ( rule [ 0 ] ) rule = rule [ 1 : ] if ( not rule or # rule == '^' is not possible here ( ( rule [ 0 ] == '$' ) and not src [ i + matches0 : i + matches0 + 1 ] . isalpha ( ) and ( src [ i + matches0 : i + matches0 + 1 ] != '.' ) ) ) : if matches0 == matches : # this is only a partial string pos0 += 3 continue if priority0 < priority : # priority is too low pos0 += 3 continue # continuation rule found break pos0 += 3 # end of "while" if ( priority0 >= priority ) and ( ( _phonet_rules [ pos0 ] is not None ) and ( _phonet_rules [ pos0 ] [ 0 ] == char0 ) ) : pos += 3 continue # replace string if _phonet_rules [ pos ] and ( '<' in _phonet_rules [ pos ] [ 1 : ] ) : priority0 = 1 else : priority0 = 0 rule = _phonet_rules [ pos + mode ] if ( priority0 == 1 ) and ( zeta == 0 ) : # rule with '<' is applied if ( ( j > 0 ) and rule and ( ( dest [ j - 1 ] == char ) or ( dest [ j - 1 ] == rule [ 0 ] ) ) ) : j -= 1 zeta0 = 1 zeta += 1 matches0 = 0 while rule and src [ i + matches0 ] : src = ( src [ 0 : i + matches0 ] + rule [ 0 ] + src [ i + matches0 + 1 : ] ) matches0 += 1 rule = rule [ 1 : ] if matches0 < matches : src = ( src [ 0 : i + matches0 ] + src [ i + matches : ] ) char = src [ i ] else : i = i + matches - 1 zeta = 0 while len ( rule ) > 1 : if ( j == 0 ) or ( dest [ j - 1 ] != rule [ 0 ] ) : dest = ( dest [ 0 : j ] + rule [ 0 ] + dest [ min ( len ( dest ) , j + 1 ) : ] ) j += 1 rule = rule [ 1 : ] # new "current char" if not rule : rule = '' char = '' else : char = rule [ 0 ] if ( _phonet_rules [ pos ] and '^^' in _phonet_rules [ pos ] [ 1 : ] ) : if char : dest = ( dest [ 0 : j ] + char + dest [ min ( len ( dest ) , j + 1 ) : ] ) j += 1 src = src [ i + 1 : ] i = 0 zeta0 = 1 break pos += 3 if pos > end1 and start2 > 0 : pos = start2 start1 = start2 end1 = end2 start2 = - 1 end2 = - 1 if zeta0 == 0 : if char and ( ( j == 0 ) or ( dest [ j - 1 ] != char ) ) : # delete multiple letters only dest = ( dest [ 0 : j ] + char + dest [ min ( j + 1 , term_length ) : ] ) j += 1 i += 1 zeta = 0 dest = dest [ 0 : j ] return dest _initialize_phonet ( lang ) word = unicode_normalize ( 'NFKC' , text_type ( word ) ) return _phonet ( word , mode , lang )
Return the phonet code for a word.

        Parameters
        ----------
        word : str
            The word to transform
        mode : int
            The ponet variant to employ (1 or 2)
        lang : str
            ``de`` (default) for German, ``none`` for no language

        Returns
        -------
        str
            The phonet value

        Examples
        --------
        >>> pe = Phonet()
        >>> pe.encode('Christopher')
        'KRISTOFA'
        >>> pe.encode('Niall')
        'NIAL'
        >>> pe.encode('Smith')
        'SMIT'
        >>> pe.encode('Schmidt')
        'SHMIT'

        >>> pe.encode('Christopher', mode=2)
        'KRIZTUFA'
        >>> pe.encode('Niall', mode=2)
        'NIAL'
        >>> pe.encode('Smith', mode=2)
        'ZNIT'
        >>> pe.encode('Schmidt', mode=2)
        'ZNIT'

        >>> pe.encode('Christopher', lang='none')
        'CHRISTOPHER'
        >>> pe.encode('Niall', lang='none')
        'NIAL'
        >>> pe.encode('Smith', lang='none')
        'SMITH'
        >>> pe.encode('Schmidt', lang='none')
        'SCHMIDT'
Return the phonet code for a word .