Step 4: undouble vowel
If the words ends CVD, where C is a non-vowel, D is a non-vowel other than I, and V is double a, e, o or u,
remove one of the vowels from V (for example, maan -> man, brood -> brod).
540588
private function step4()
    {
        // D is a non-vowel other than I
        $d = Utf8::substr($this->word, -1, 1);
        if (in_array($d, array_merge(self::$vowels, array('I')))) {
            return false;
        }

        // V is double a, e, o or u
        $v = Utf8::substr($this->word, -3, 2);
        if (!in_array($v, array('aa', 'ee', 'oo', 'uu'))) {
            return false;
        }
        $singleV = Utf8::substr($v, 0, 1);

        // C is a non-vowel
        $c = Utf8::substr($this->word, -4, 1);
        if (in_array($c, self::$vowels)) {
            return false;
        }

        $this->word = Utf8::substr($this->word, 0, -4);
        $this->word .= $c . $singleV  .$d;
    }
992407
def backward_delete_word(self, e): # (Control-Rubout)
        """
        self.l_buffer.backward_delete_word(self.argument_reset)
        self.finalize()
998381
def apply_T2(word):
    ''''''
    WORD = word
    offset = 0

    for vv in vv_sequences(WORD):
        seq = vv.group(2)

        if not is_diphthong(seq) and not is_long(seq):
            i = vv.start(2) + 1 + offset
            WORD = WORD[:i] + '.' + WORD[i:]
            offset += 1

    RULE = ' T2' if word != WORD else ''

    return WORD, RULE
186885
def apply_T2(word):
    ''''''
    T2 = ''
    WORD = word.split('.')

    for i, v in enumerate(WORD):

        if not contains_diphthong(v):
            VV = contains_VV(v)

            if VV:
                I = v.find(VV) + 1
                WORD[i] = v[:I] + '.' + v[I:]
                T2 = ' T2'

    word = '.'.join(WORD)

    return word, T2
152250
def harmonic(word):
    ''''''
    depth = {'ä': 0, 'ö': 0, 'y': 0, 'a': 1, 'o': 1, 'u': 1}
    vowels = filter(lambda ch: is_front(ch) or is_back(ch), word)
    depths = (depth[x.lower()] for x in vowels)

    return len(set(depths)) < 2
1354794
def stem(self, word):
        
        chr_exceeded = False
        for i in range(len(word)):
            if ord(word[i]) > 255:
                chr_exceeded = True
                break

        if chr_exceeded:
            word = self.__cyrillic_to_roman(word)

        step1_success = False
        adjectival_removed = False
        verb_removed = False
        undouble_success = False
        superlative_removed = False

        rv, r2 = self.__regions_russian(word)

        # Step 1
        for suffix in self.__perfective_gerund_suffixes:
            if rv.endswith(suffix):
                if suffix in ("v", "vshi", "vshis'"):
                    if (rv[-len(suffix)-3:-len(suffix)] == "i^a" or
                        rv[-len(suffix)-1:-len(suffix)] == "a"):
                        word = word[:-len(suffix)]
                        r2 = r2[:-len(suffix)]
                        rv = rv[:-len(suffix)]
                        step1_success = True
                        break
                else:
                    word = word[:-len(suffix)]
                    r2 = r2[:-len(suffix)]
                    rv = rv[:-len(suffix)]
                    step1_success = True
                    break

        if not step1_success:
            for suffix in self.__reflexive_suffixes:
                if rv.endswith(suffix):
                    word = word[:-len(suffix)]
                    r2 = r2[:-len(suffix)]
                    rv = rv[:-len(suffix)]
                    break

            for suffix in self.__adjectival_suffixes:
                if rv.endswith(suffix):
                    if suffix in ('i^ushchi^ui^u', 'i^ushchi^ai^a',
                              'i^ushchui^u', 'i^ushchai^a', 'i^ushchoi^u',
                              'i^ushchei^u', 'i^ushchimi', 'i^ushchymi',
                              'i^ushchego', 'i^ushchogo', 'i^ushchemu',
                              'i^ushchomu', 'i^ushchikh', 'i^ushchykh',
                              'shchi^ui^u', 'shchi^ai^a', 'i^ushchee',
                              'i^ushchie', 'i^ushchye', 'i^ushchoe',
                              'i^ushchei`', 'i^ushchii`', 'i^ushchyi`',
                              'i^ushchoi`', 'i^ushchem', 'i^ushchim',
                              'i^ushchym', 'i^ushchom', 'vshi^ui^u',
                              'vshi^ai^a', 'shchui^u', 'shchai^a',
                              'shchoi^u', 'shchei^u', 'emi^ui^u',
                              'emi^ai^a', 'nni^ui^u', 'nni^ai^a',
                              'shchimi', 'shchymi', 'shchego', 'shchogo',
                              'shchemu', 'shchomu', 'shchikh', 'shchykh',
                              'vshui^u', 'vshai^a', 'vshoi^u', 'vshei^u',
                              'shchee', 'shchie', 'shchye', 'shchoe',
                              'shchei`', 'shchii`', 'shchyi`', 'shchoi`',
                              'shchem', 'shchim', 'shchym', 'shchom',
                              'vshimi', 'vshymi', 'vshego', 'vshogo',
                              'vshemu', 'vshomu', 'vshikh', 'vshykh',
                              'emui^u', 'emai^a', 'emoi^u', 'emei^u',
                              'nnui^u', 'nnai^a', 'nnoi^u', 'nnei^u',
                              'vshee', 'vshie', 'vshye', 'vshoe',
                              'vshei`', 'vshii`', 'vshyi`', 'vshoi`',
                              'vshem', 'vshim', 'vshym', 'vshom',
                              'emimi', 'emymi', 'emego', 'emogo',
                              'ememu', 'emomu', 'emikh', 'emykh',
                              'nnimi', 'nnymi', 'nnego', 'nnogo',
                              'nnemu', 'nnomu', 'nnikh', 'nnykh',
                              'emee', 'emie', 'emye', 'emoe', 'emei`',
                              'emii`', 'emyi`', 'emoi`', 'emem', 'emim',
                              'emym', 'emom', 'nnee', 'nnie', 'nnye',
                              'nnoe', 'nnei`', 'nnii`', 'nnyi`', 'nnoi`',
                              'nnem', 'nnim', 'nnym', 'nnom'):
                        if (rv[-len(suffix)-3:-len(suffix)] == "i^a" or
                            rv[-len(suffix)-1:-len(suffix)] == "a"):
                            word = word[:-len(suffix)]
                            r2 = r2[:-len(suffix)]
                            rv = rv[:-len(suffix)]
                            adjectival_removed = True
                            break
                    else:
                        word = word[:-len(suffix)]
                        r2 = r2[:-len(suffix)]
                        rv = rv[:-len(suffix)]
                        adjectival_removed = True
                        break

            if not adjectival_removed:
                for suffix in self.__verb_suffixes:
                    if rv.endswith(suffix):
                        if suffix in ("la", "na", "ete", "i`te", "li",
                                      "i`", "l", "em", "n", "lo", "no",
                                      "et", "i^ut", "ny", "t'", "esh'",
                                      "nno"):
                            if (rv[-len(suffix)-3:-len(suffix)] == "i^a" or
                                rv[-len(suffix)-1:-len(suffix)] == "a"):
                                word = word[:-len(suffix)]
                                r2 = r2[:-len(suffix)]
                                rv = rv[:-len(suffix)]
                                verb_removed = True
                                break
                        else:
                            word = word[:-len(suffix)]
                            r2 = r2[:-len(suffix)]
                            rv = rv[:-len(suffix)]
                            verb_removed = True
                            break

            if not adjectival_removed and not verb_removed:
                for suffix in self.__noun_suffixes:
                    if rv.endswith(suffix):
                        word = word[:-len(suffix)]
                        r2 = r2[:-len(suffix)]
                        rv = rv[:-len(suffix)]
                        break

        # Step 2
        if rv.endswith("i"):
            word = word[:-1]
            r2 = r2[:-1]

        # Step 3
        for suffix in self.__derivational_suffixes:
            if r2.endswith(suffix):
                word = word[:-len(suffix)]
                break

        # Step 4
        if word.endswith("nn"):
            word = word[:-1]
            undouble_success = True

        if not undouble_success:
            for suffix in self.__superlative_suffixes:
                if word.endswith(suffix):
                    word = word[:-len(suffix)]
                    superlative_removed = True
                    break
            if word.endswith("nn"):
                word = word[:-1]

        if not undouble_success and not superlative_removed:
            if word.endswith("'"):
                word = word[:-1]

        if chr_exceeded:
            word = self.__roman_to_cyrillic(word)


        return word
40522
def _starts_with_vowel(self, letter_group: str) -> bool:
        """"""
        if len(letter_group) == 0:
            return False
        return self._contains_vowels(letter_group[0])
247680
function() {

  var step2list = {
    ational: 'ate',
    tional: 'tion',
    enci: 'ence',
    anci: 'ance',
    izer: 'ize',
    bli: 'ble',
    alli: 'al',
    entli: 'ent',
    eli: 'e',
    ousli: 'ous',
    ization: 'ize',
    ation: 'ate',
    ator: 'ate',
    alism: 'al',
    iveness: 'ive',
    fulness: 'ful',
    ousness: 'ous',
    aliti: 'al',
    iviti: 'ive',
    biliti: 'ble',
    logi: 'log'
  };

  var step3list = {
    icate: 'ic',
    ative: '',
    alize: 'al',
    iciti: 'ic',
    ical: 'ic',
    ful: '',
    ness: ''
  };

  var c = "[^aeiou]";          // consonant
  var v = "[aeiouy]";          // vowel
  var C = c + "[^aeiouy]*";    // consonant sequence
  var V = v + "[aeiou]*";      // vowel sequence

  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem

  this.stemWord = function (w) {
    var stem;
    var suffix;
    var firstch;
    var origword = w;

    if (w.length < 3)
      return w;

    var re;
    var re2;
    var re3;
    var re4;

    firstch = w.substr(0,1);
    if (firstch == "y")
      w = firstch.toUpperCase() + w.substr(1);

    // Step 1a
    re = /^(.+?)(ss|i)es$/;
    re2 = /^(.+?)([^s])s$/;

    if (re.test(w))
      w = w.replace(re,"$1$2");
    else if (re2.test(w))
      w = w.replace(re2,"$1$2");

    // Step 1b
    re = /^(.+?)eed$/;
    re2 = /^(.+?)(ed|ing)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      re = new RegExp(mgr0);
      if (re.test(fp[1])) {
        re = /.$/;
        w = w.replace(re,"");
      }
    }
    else if (re2.test(w)) {
      var fp = re2.exec(w);
      stem = fp[1];
      re2 = new RegExp(s_v);
      if (re2.test(stem)) {
        w = stem;
        re2 = /(at|bl|iz)$/;
        re3 = new RegExp("([^aeiouylsz])\\1$");
        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
        if (re2.test(w))
          w = w + "e";
        else if (re3.test(w)) {
          re = /.$/;
          w = w.replace(re,"");
        }
        else if (re4.test(w))
          w = w + "e";
      }
    }

    // Step 1c
    re = /^(.+?)y$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      re = new RegExp(s_v);
      if (re.test(stem))
        w = stem + "i";
    }

    // Step 2
    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      suffix = fp[2];
      re = new RegExp(mgr0);
      if (re.test(stem))
        w = stem + step2list[suffix];
    }

    // Step 3
    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      suffix = fp[2];
      re = new RegExp(mgr0);
      if (re.test(stem))
        w = stem + step3list[suffix];
    }

    // Step 4
    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
    re2 = /^(.+?)(s|t)(ion)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      re = new RegExp(mgr1);
      if (re.test(stem))
        w = stem;
    }
    else if (re2.test(w)) {
      var fp = re2.exec(w);
      stem = fp[1] + fp[2];
      re2 = new RegExp(mgr1);
      if (re2.test(stem))
        w = stem;
    }

    // Step 5
    re = /^(.+?)e$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      re = new RegExp(mgr1);
      re2 = new RegExp(meq1);
      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
        w = stem;
    }
    re = /ll$/;
    re2 = new RegExp(mgr1);
    if (re.test(w) && re2.test(w)) {
      re = /.$/;
      w = w.replace(re,"");
    }

    // and turn initial Y back to y
    if (firstch == "y")
      w = firstch.toLowerCase() + w.substr(1);
    return w;
  }
}
1309812
def _step2(self, word):
        
        if len(word) <= 1: # Only possible at this stage given unusual inputs to stem_word like 'oed'
            return word

        ch = word[-2]

        if ch == 'a':
            if word.endswith("ational"):
                return word[:-7] + "ate" if self._m(word, len(word)-8) > 0 else word
            elif word.endswith("tional"):
                return word[:-2] if self._m(word, len(word)-7) > 0 else word
            else:
                return word
        elif ch == 'c':
            if word.endswith("enci"):
                return word[:-4] + "ence" if self._m(word, len(word)-5) > 0 else word
            elif word.endswith("anci"):
                return word[:-4] + "ance" if self._m(word, len(word)-5) > 0 else word
            else:
                return word
        elif ch == 'e':
            if word.endswith("izer"):
                return word[:-1] if self._m(word, len(word)-5) > 0 else word
            else:
                return word
        elif ch == 'l':
            if word.endswith("bli"):
                return word[:-3] + "ble" if self._m(word, len(word)-4) > 0 else word # --DEPARTURE--
            # To match the published algorithm, replace "bli" with "abli" and "ble" with "able"
            elif word.endswith("alli"):
                # --NEW--
                if self._m(word, len(word)-5) > 0:
                    word = word[:-2]
                    return self._step2(word)
                else:
                    return word
            elif word.endswith("fulli"):
                return word[:-2] if self._m(word, len(word)-6) else word # --NEW--
            elif word.endswith("entli"):
                return word[:-2] if self._m(word, len(word)-6) else word
            elif word.endswith("eli"):
                return word[:-2] if self._m(word, len(word)-4) else word
            elif word.endswith("ousli"):
                return word[:-2] if self._m(word, len(word)-6) else word
            else:
                return word
        elif ch == 'o':
            if word.endswith("ization"):
                return word[:-7] + "ize" if self._m(word, len(word)-8) else word
            elif word.endswith("ation"):
                return word[:-5] + "ate" if self._m(word, len(word)-6) else word
            elif word.endswith("ator"):
                return word[:-4] + "ate" if self._m(word, len(word)-5) else word
            else:
                return word
        elif ch == 's':
            if word.endswith("alism"):
                return word[:-3] if self._m(word, len(word)-6) else word
            elif word.endswith("ness"):
                if word.endswith("iveness"):
                    return word[:-4] if self._m(word, len(word)-8) else word
                elif word.endswith("fulness"):
                    return word[:-4] if self._m(word, len(word)-8) else word
                elif word.endswith("ousness"):
                    return word[:-4] if self._m(word, len(word)-8) else word
                else:
                    return word
            else:
                return word
        elif ch == 't':
            if word.endswith("aliti"):
                return word[:-3] if self._m(word, len(word)-6) else word
            elif word.endswith("iviti"):
                return word[:-5] + "ive" if self._m(word, len(word)-6) else word
            elif word.endswith("biliti"):
                return word[:-6] + "ble" if self._m(word, len(word)-7) else word
            else:
                return word
        elif ch == 'g': # --DEPARTURE--
            if word.endswith("logi"):
                return word[:-1] if self._m(word, len(word) - 4) else word # --NEW-- (Barry Wilkins)
            # To match the published algorithm, pass len(word)-5 to _m instead of len(word)-4
            else:
                return word

        else:
            return word
1016282
function consonantStringBackwards(tokens, i, orig_i) {
	var out = [];
	var t = '';
	while (i >= orig_i && tokens[i] != null) {
		t = tokens[i--];
		if (t == '+' || t == '^') continue;
		if (consonant(t) == null) break;
		out.unshift(t);
	}
	return out.join("+");
}
963362
private void parseSecondaryVowel() {
		if (!validViSyll)
			return;
		// get the current and next character in the syllable string
		char curChar, nextChar;
		if (iCurPos > strSyllable.length() - 1) {
			validViSyll = false;
			return;
		}
		curChar = strSyllable.charAt(iCurPos);

		if (iCurPos == strSyllable.length() - 1)
			nextChar = '$';
		else
			nextChar = strSyllable.charAt(iCurPos + 1);

		// get the tone and the original vowel (without tone)
		TONE tone = TONE.NO_TONE;
		int idx1 = vnVowels.indexOf(curChar);
		int idx2 = vnVowels.indexOf(nextChar);

		if (idx1 == -1)
			return;// current char is not a vowel
		tone = TONE.getTone(idx1 % 6);
		curChar = vnVowels.charAt((idx1 / 6) * 6);

		if (idx2 == -1) { // next char is not a vowel
			strSecondaryVowel = ZERO;
			return;
		}
		nextChar = vnVowels.charAt((idx2 / 6) * 6);
		if (tone.getValue() == TONE.NO_TONE.getValue())
			tone = TONE.getTone(idx2 % 6);

		// Check the secondary vowel
		if (curChar == 'o') {
			if (nextChar == 'a' || nextChar == 'e') {
				strSecondaryVowel += curChar;
				iCurPos++;
			} else
				strSecondaryVowel = ZERO; // oo
			return;
		} else if (curChar == 'u') {
			if (nextChar != 'i' && nextChar != '$') {
				strSecondaryVowel += curChar;
				iCurPos++;
			} else
				strSecondaryVowel = ZERO;
			return;
		}
	}
825690
def stem(self, word):
        
        word = word.lower()

        r1 = self.__r1_hungarian(word, self.__vowels, self.__digraphs)

        # STEP 1: Remove instrumental case
        if r1.endswith(self.__step1_suffixes):
            for double_cons in self.__double_consonants:
                if word[-2-len(double_cons):-2] == double_cons:
                    word = "".join((word[:-4], word[-3]))

                    if r1[-2-len(double_cons):-2] == double_cons:
                        r1 = "".join((r1[:-4], r1[-3]))
                    break

        # STEP 2: Remove frequent cases
        for suffix in self.__step2_suffixes:
            if word.endswith(suffix):
                if r1.endswith(suffix):
                    word = word[:-len(suffix)]
                    r1 = r1[:-len(suffix)]

                    if r1.endswith("\xE1"):
                        word = "".join((word[:-1], "a"))
                        r1 = "".join((r1[:-1], "a"))

                    elif r1.endswith("\xE9"):
                        word = "".join((word[:-1], "e"))
                        r1 = "".join((r1[:-1], "e"))
                break

        # STEP 3: Remove special cases
        for suffix in self.__step3_suffixes:
            if r1.endswith(suffix):
                if suffix == "\xE9n":
                    word = "".join((word[:-2], "e"))
                    r1 = "".join((r1[:-2], "e"))
                else:
                    word = "".join((word[:-len(suffix)], "a"))
                    r1 = "".join((r1[:-len(suffix)], "a"))
                break

        # STEP 4: Remove other cases
        for suffix in self.__step4_suffixes:
            if r1.endswith(suffix):
                if suffix == "\xE1stul":
                    word = "".join((word[:-5], "a"))
                    r1 = "".join((r1[:-5], "a"))

                elif suffix == "\xE9st\xFCl":
                    word = "".join((word[:-5], "e"))
                    r1 = "".join((r1[:-5], "e"))
                else:
                    word = word[:-len(suffix)]
                    r1 = r1[:-len(suffix)]
                break

        # STEP 5: Remove factive case
        for suffix in self.__step5_suffixes:
            if r1.endswith(suffix):
                for double_cons in self.__double_consonants:
                    if word[-1-len(double_cons):-1] == double_cons:
                        word = "".join((word[:-3], word[-2]))

                        if r1[-1-len(double_cons):-1] == double_cons:
                            r1 = "".join((r1[:-3], r1[-2]))
                        break

        # STEP 6: Remove owned
        for suffix in self.__step6_suffixes:
            if r1.endswith(suffix):
                if suffix in ("\xE1k\xE9", "\xE1\xE9i"):
                    word = "".join((word[:-3], "a"))
                    r1 = "".join((r1[:-3], "a"))

                elif suffix in ("\xE9k\xE9", "\xE9\xE9i",
                                "\xE9\xE9"):
                    word = "".join((word[:-len(suffix)], "e"))
                    r1 = "".join((r1[:-len(suffix)], "e"))
                else:
                    word = word[:-len(suffix)]
                    r1 = r1[:-len(suffix)]
                break

        # STEP 7: Remove singular owner suffixes
        for suffix in self.__step7_suffixes:
            if word.endswith(suffix):
                if r1.endswith(suffix):
                    if suffix in ("\xE1nk", "\xE1juk", "\xE1m",
                                  "\xE1d", "\xE1"):
                        word = "".join((word[:-len(suffix)], "a"))
                        r1 = "".join((r1[:-len(suffix)], "a"))

                    elif suffix in ("\xE9nk", "\xE9j\xFCk",
                                    "\xE9m", "\xE9d", "\xE9"):
                        word = "".join((word[:-len(suffix)], "e"))
                        r1 = "".join((r1[:-len(suffix)], "e"))
                    else:
                        word = word[:-len(suffix)]
                        r1 = r1[:-len(suffix)]
                break

        # STEP 8: Remove plural owner suffixes
        for suffix in self.__step8_suffixes:
            if word.endswith(suffix):
                if r1.endswith(suffix):
                    if suffix in ("\xE1im", "\xE1id", "\xE1i",
                                  "\xE1ink", "\xE1itok", "\xE1ik"):
                        word = "".join((word[:-len(suffix)], "a"))
                        r1 = "".join((r1[:-len(suffix)], "a"))

                    elif suffix in ("\xE9im", "\xE9id", "\xE9i",
                                    "\xE9ink", "\xE9itek", "\xE9ik"):
                        word = "".join((word[:-len(suffix)], "e"))
                        r1 = "".join((r1[:-len(suffix)], "e"))
                    else:
                        word = word[:-len(suffix)]
                        r1 = r1[:-len(suffix)]
                break

        # STEP 9: Remove plural suffixes
        for suffix in self.__step9_suffixes:
            if word.endswith(suffix):
                if r1.endswith(suffix):
                    if suffix == "\xE1k":
                        word = "".join((word[:-2], "a"))
                    elif suffix == "\xE9k":
                        word = "".join((word[:-2], "e"))
                    else:
                        word = word[:-len(suffix)]
                break


        return word
1157865
def apply_T4(word):
    ''''''
    T4 = ''
    WORD = word.split('.')

    for i, v in enumerate(WORD):

        # i % 2 != 0 prevents this rule from applying to first, third, etc.
        # syllables, which receive stress (WSP)
        if is_consonant(v[-1]) and i % 2 != 0:

            if i + 1 == len(WORD) or is_consonant(WORD[i + 1][0]):

                if contains_Vu_diphthong(v):
                    I = v.rfind('u')
                    WORD[i] = v[:I] + '.' + v[I:]
                    T4 = ' T4'

                elif contains_Vy_diphthong(v):
                    I = v.rfind('y')
                    WORD[i] = v[:I] + '.' + v[I:]
                    T4 = ' T4'

    word = '.'.join(WORD)

    return word, T4
89757
def apply_T12(word):
    ''''''
    WORD = word
    offset = 0

    for vv in new_vv(WORD):
        # import pdb; pdb.set_trace()
        seq = vv.group(1)

        if not is_diphthong(seq) and not is_long(seq):
            i = vv.start(1) + 1 + offset
            WORD = WORD[:i] + '.' + WORD[i:]
            offset += 1

    RULE = ' T2' if word != WORD else ''

    return WORD, RULE
138592
def stem(self, word):
        
        word = word.lower()

        step2_success = False

        # Vowel accents are removed.
        word = (word.replace("\xE4", "a").replace("\xE1", "a")
                    .replace("\xEB", "e").replace("\xE9", "e")
                    .replace("\xED", "i").replace("\xEF", "i")
                    .replace("\xF6", "o").replace("\xF3", "o")
                    .replace("\xFC", "u").replace("\xFA", "u"))

        # An initial 'y', a 'y' after a vowel,
        # and an 'i' between self.__vowels is put into upper case.
        # As from now these are treated as consonants.
        if word.startswith("y"):
            word = "".join(("Y", word[1:]))

        for i in range(1, len(word)):
            if word[i-1] in self.__vowels and word[i] == "y":
                word = "".join((word[:i], "Y", word[i+1:]))

        for i in range(1, len(word)-1):
            if (word[i-1] in self.__vowels and word[i] == "i" and
               word[i+1] in self.__vowels):
                word = "".join((word[:i], "I", word[i+1:]))

        r1, r2 = self._r1r2_standard(word, self.__vowels)

        # R1 is adjusted so that the region before it
        # contains at least 3 letters.
        for i in range(1, len(word)):
            if word[i] not in self.__vowels and word[i-1] in self.__vowels:
                if len(word[:i+1]) < 3 and len(word[:i+1]) > 0:
                    r1 = word[3:]
                elif len(word[:i+1]) == 0:
                    return word
                break

        # STEP 1
        for suffix in self.__step1_suffixes:
            if r1.endswith(suffix):
                if suffix == "heden":
                    word = "".join((word[:-5], "heid"))
                    r1 = "".join((r1[:-5], "heid"))
                    if r2.endswith("heden"):
                        r2 = "".join((r2[:-5], "heid"))

                elif (suffix in ("ene", "en") and
                      not word.endswith("heden") and
                      word[-len(suffix)-1] not in self.__vowels and
                      word[-len(suffix)-3:-len(suffix)] != "gem"):
                    word = word[:-len(suffix)]
                    r1 = r1[:-len(suffix)]
                    r2 = r2[:-len(suffix)]
                    if word.endswith(("kk", "dd", "tt")):
                        word = word[:-1]
                        r1 = r1[:-1]
                        r2 = r2[:-1]

                elif (suffix in ("se", "s") and
                      word[-len(suffix)-1] not in self.__vowels and
                      word[-len(suffix)-1] != "j"):
                    word = word[:-len(suffix)]
                    r1 = r1[:-len(suffix)]
                    r2 = r2[:-len(suffix)]
                break

        # STEP 2
        if r1.endswith("e") and word[-2] not in self.__vowels:
            step2_success = True
            word = word[:-1]
            r1 = r1[:-1]
            r2 = r2[:-1]

            if word.endswith(("kk", "dd", "tt")):
                word = word[:-1]
                r1 = r1[:-1]
                r2 = r2[:-1]

        # STEP 3a
        if r2.endswith("heid") and word[-5] != "c":
            word = word[:-4]
            r1 = r1[:-4]
            r2 = r2[:-4]

            if (r1.endswith("en") and word[-3] not in self.__vowels and
                word[-5:-2] != "gem"):
                word = word[:-2]
                r1 = r1[:-2]
                r2 = r2[:-2]

                if word.endswith(("kk", "dd", "tt")):
                    word = word[:-1]
                    r1 = r1[:-1]
                    r2 = r2[:-1]

        # STEP 3b: Derivational suffixes
        for suffix in self.__step3b_suffixes:
            if r2.endswith(suffix):
                if suffix in ("end", "ing"):
                    word = word[:-3]
                    r2 = r2[:-3]

                    if r2.endswith("ig") and word[-3] != "e":
                        word = word[:-2]
                    else:
                        if word.endswith(("kk", "dd", "tt")):
                            word = word[:-1]

                elif suffix == "ig" and word[-3] != "e":
                    word = word[:-2]

                elif suffix == "lijk":
                    word = word[:-4]
                    r1 = r1[:-4]

                    if r1.endswith("e") and word[-2] not in self.__vowels:
                        word = word[:-1]
                        if word.endswith(("kk", "dd", "tt")):
                            word = word[:-1]

                elif suffix == "baar":
                    word = word[:-4]

                elif suffix == "bar" and step2_success:
                    word = word[:-3]
                break

        # STEP 4: Undouble vowel
        if len(word) >= 4:
            if word[-1] not in self.__vowels and word[-1] != "I":
                if word[-3:-1] in ("aa", "ee", "oo", "uu"):
                    if word[-4] not in self.__vowels:
                        word = "".join((word[:-3], word[-3], word[-1]))

        # All occurrences of 'I' and 'Y' are put back into lower case.
        word = word.replace("I", "i").replace("Y", "y")


        return word
748888
private function step4()
    {
        //If the word ends s, not preceded by a, i, o, u, è or s, delete it.
        if (preg_match('#[^aiouès]s$#', $this->word)) {
            $this->word = Utf8::substr($this->word, 0, -1);
        }

        // In the rest of step 4, all tests are confined to the RV region.
        // ion
        //      delete if in R2 and preceded by s or t
        if ( (($position = $this->searchIfInRv(array('ion'))) !== false) && ($this->inR2($position)) ) {
            $before = $position - 1;
            $letter = Utf8::substr($this->word, $before, 1);
            if ( $this->inRv($before) && (($letter == 's') || ($letter == 't')) ) {
                $this->word = Utf8::substr($this->word, 0, $position);
            }
            return true;
        }

        // ier   ière   Ier   Ière
        //      replace with i
        if ( ($this->searchIfInRv(array('ier', 'ière', 'Ier', 'Ière'))) !== false) {
            $this->word = preg_replace('#(ier|ière|Ier|Ière)$#u', 'i', $this->word);
            return true;
        }

        // e
        //      delete
        if ( ($this->searchIfInRv(array('e'))) !== false) {
            $this->word = Utf8::substr($this->word, 0, -1);
            return true;
        }

        // ë
        //      if preceded by gu, delete
        if ( ($position = $this->searchIfInRv(array('guë'))) !== false) {
            if ($this->inRv($position+2)) {
                $this->word = Utf8::substr($this->word, 0, -1);
                return true;
            }
        }

        return false;
    }
854656
def _v(self, token, previous=None, next=None):
        
        def f(v, s1, s2):
            if s2: 
                v[s1 + " " + s2] = 1
        p, n = previous, next
        p = ("", "") if not p else (p[0] or "", p[1] or "")
        n = ("", "") if not n else (n[0] or "", n[1] or "")
        v = {}
        f(v,  "b", "b")         # Bias.
        f(v,  "h", token[0])    # Capitalization.
        f(v,  "w", token[-6:] if token not in self.known or token in self.unknown else "")
        f(v,  "x", token[-3:])  # Word suffix.
        f(v, "-x", p[0][-3:])   # Word suffix left.
        f(v, "+x", n[0][-3:])   # Word suffix right.
        f(v, "-t", p[1])        # Tag left.
        f(v, "-+", p[1] + n[1]) # Tag left + right.
        f(v, "+t", n[1])        # Tag right.
        return v