UNPKG

porter2

Version:

Fastest JavaScript implementation of the porter2 stemmer

433 lines (423 loc) 14.6 kB
// AUTOGENERATED, edit src/index.js instead Object.defineProperty(exports, '__esModule', { value: true }) // EQ_BEGIN : (chars : string) -> <code (boolean)> // EQ_END : (offset : number, chars : string) -> <code (boolean)> // All one-character strings in this file are converted to char codes. // This is mostly a rewrite of my ocaml implementation (though not published // at the moment of writing this) function is_v(char) { switch (char) { case 97: case 101: case 105: case 111: case 117: case 121: return true default: return false } } function is_wxy(char) { switch (char) { case 97: case 101: case 105: case 111: case 117: case 121: case 119: case 120: case 89: return true default: return false } } function is_valid_li(char) { switch (char) { case 99: case 100: case 101: case 103: case 104: case 107: case 109: case 110: case 114: case 116: return true default: return false } } function is_double(char) { switch (char) { case 98: case 100: case 102: case 103: case 109: case 110: case 112: case 114: case 116: return true default: return false } } function is_shortv(w, len) { // backwardmode: ( non-v_WXY v non-v ) or ( non-v v atlimit ) return len >= 2 && is_v(w[len - 2]) && ( (len === 2 && !is_v(w[len - 1])) || (len >= 3 && !is_v(w[len - 3]) && !is_wxy(w[len - 1])) ) } exports.stem = function stem(word) { if (word.length < 3) return word // exception1 if (word.length <= 6) { switch (word) { case 'ski': return 'ski' case 'skies': return 'sky' case 'dying': return 'die' case 'lying': return 'lie' case 'tying': return 'tie' // special -LY cases case 'idly': return 'idl' case 'gently': return 'gentl' case 'ugly': return 'ugli' case 'early': return 'earli' case 'only': return 'onli' case 'singly': return 'singl' // invariant forms case 'sky': case 'news': case 'howe': // not plural forms case 'atlas': case 'cosmos': case 'bias': case 'andes': return word } } var initial_offset = word.charCodeAt(0) === 39 /* ' */ ? 1 : 0 var l = word.length - initial_offset var w = new Array(l) var y_found = false for (var i = 0; i < l; ++i) { // var ch = word[i + initial_offset] var ch = word.charCodeAt(i + initial_offset) if (ch === 121 && (i === 0 || is_v(w[i - 1]))) { y_found = true w[i] = 89 continue } w[i] = ch } if (w[l - 1] === 39) --l if (l >= 2 && w[l - 2] === 39 && w[l - 1] === 115) l -= 2 // mark_regions var rv = 0; // rv is the position after the first vowel while (rv < l && !is_v(w[rv])) ++rv if (rv < l) ++rv var r1 = rv if (l >= 5 && ((w[0] === 103 && w[1] === 101 && w[2] === 110 && w[3] === 101 && w[4] === 114) || (w[0] === 97 && w[1] === 114 && w[2] === 115 && w[3] === 101 && w[4] === 110))) r1 = 5 else if (l >= 6 && w[0] === 99 && w[1] === 111 && w[2] === 109 && w[3] === 109 && w[4] === 117 && w[5] === 110) r1 = 6 else { // > R1 is the region after the first non-vowel following a vowel, // > or the end of the word if there is no such non-vowel. while (r1 < l && is_v(w[r1])) ++r1 if (r1 < l) ++r1 } // > R2 is the region after the first non-vowel following a vowel in R1, // > or the end of the word if there is no such non-vowel. var r2 = r1 var found_v = false while (r2 < l && !is_v(w[r2])) ++r2 while (r2 < l && is_v(w[r2])) ++r2 if (r2 < l) ++r2 // Step_1a if (l >= 3) { if (w[l - 1] === 115) { if (l >= 4 && w[l - 2] === 101 && w[l - 3] === 115 && w[l - 4] === 115) l -= 2 // sses -> ss else if (w[l - 2] === 101 && w[l - 3] === 105) l -= (l >= 5 ? 2 : 1) // ies else if (w[l - 2] !== 117 && w[l - 2] !== 115 && rv < l - 1) // us ss -> <nothing>; s -> "delete if the preceding word part // contains a vowel not immediately before the s" l -= 1 } else if (w[l - 1] === 100 && w[l - 2] === 101 && w[l - 3] === 105) l -= (l >= 5 ? 2 : 1) // ied } // exception2 if ( (l === 6 && ( (w[0] === 105 && w[1] === 110 && w[2] === 110 && w[3] === 105 && w[4] === 110 && w[5] === 103) || (w[0] === 111 && w[1] === 117 && w[2] === 116 && w[3] === 105 && w[4] === 110 && w[5] === 103) || (w[0] === 101 && w[1] === 120 && w[2] === 99 && w[3] === 101 && w[4] === 101 && w[5] === 100)) ) || (l === 7 && ( (w[0] === 99 && w[1] === 97 && w[2] === 110 && w[3] === 110 && w[4] === 105 && w[5] === 110 && w[6] === 103) || (w[0] === 104 && w[1] === 101 && w[2] === 114 && w[3] === 114 && w[4] === 105 && w[5] === 110 && w[6] === 103) || (w[0] === 101 && w[1] === 97 && w[2] === 114 && w[3] === 114 && w[4] === 105 && w[5] === 110 && w[6] === 103) || (w[0] === 112 && w[1] === 114 && w[2] === 111 && w[3] === 99 && w[4] === 101 && w[5] === 101 && w[6] === 100) || (w[0] === 115 && w[1] === 117 && w[2] === 99 && w[3] === 99 && w[4] === 101 && w[5] === 101 && w[6] === 100))) ) { var exp2_out = '' for (var i = 0; i < l; ++i) // exp2_out += w[i] exp2_out += String.fromCharCode(w[i]) return exp2_out } // Step_1b var ll = // l (length) without the -ly ending (l >= 2 && w[l - 1] === 121 && w[l - 2] === 108) ? l - 2 : l if (ll >= 3) { if (w[ll - 3] === 101 && w[ll - 2] === 101 && w[ll - 1] === 100) { if (ll >= r1 + 3) l = ll - 1 // eed eedly -> ee (if in R1) } else { // ll without: ed edly ing ingly (-1 if not found) if (w[ll - 2] === 101 && w[ll - 1] === 100) ll -= 2 else if (w[ll - 3] === 105 && w[ll - 2] === 110 && w[ll - 1] === 103) ll -= 3 else ll = -1 if (ll >= 0 && rv <= ll) { l = ll if (l >= 2) { if ((w[l - 1] === 116 && w[l - 2] === 97) || (w[l - 1] === 108 && w[l - 2] === 98) || (w[l - 1] === 122 && w[l - 2] === 105)) { // at -> ate bl -> ble iz -> ize w[l] = 101 ++l } else if (w[l - 2] === w[l - 1] && is_double(w[l - 1])) { --l } else if (r1 >= l && is_shortv(w, l)) { // <shortv> -> e w[l] = 101 ++l } } } } } // Step_1c if (l >= 3 && (w[l - 1] === 89 || w[l - 1] === 121) && !is_v(w[l - 2])) w[l - 1] = 105 // Step_2 if (l >= r1 + 2) { switch (w[l - 1]) { case 108: if (l >= r1 + 6 && w[l - 2] === 97 && w[l - 3] === 110 && w[l - 4] === 111 && w[l - 5] === 105 && w[l - 6] === 116) { if (l >= 7 && w[l - 7] === 97) { if (l >= r1 + 7) { // ational -> ate l -= 4 w[l - 1] = 101 } } else { l -= 2 // tional -> tion } } break case 110: if (l >= r1 + 5 && w[l - 2] === 111 && w[l - 3] === 105 && w[l - 4] === 116 && w[l - 5] === 97) { if (l >= 7 && w[l - 6] === 122 && w[l - 7] === 105) { if (l >= r1 + 7) { // ization -> ize l -= 4 w[l - 1] = 101 } } else { // ation -> ate l -= 2 w[l - 1] = 101 } } break case 114: if (l >= r1 + 4) { if (w[l - 2] === 101) { if (w[l - 3] === 122 && w[l - 4] === 105) --l // izer -> ize } else if (w[l - 2] === 111) { if (w[l - 3] === 116 && w[l - 4] === 97) { --l w[l - 1] = 101 } } } break case 115: if (l >= r1 + 7 && w[l - 2] === 115 && w[l - 3] === 101 && w[l - 4] === 110 && ( (w[l - 5] === 108 && w[l - 6] === 117 && w[l - 7] === 102) || (w[l - 5] === 115 && w[l - 6] === 117 && w[l - 7] === 111) || (w[l - 5] === 101 && w[l - 6] === 118 && w[l - 7] === 105) )) { l -= 4 // fulness -> ful ousness -> ous iveness -> ive } break case 109: if (l >= r1 + 5 && w[l - 2] === 115 && w[l - 3] === 105 && w[l - 4] === 108 && w[l - 5] === 97) l -= 3 // alism -> al break case 105: if (w[l - 2] === 99) { if (l >= r1 + 4 && (w[l - 4] === 101 || w[l - 4] === 97) && w[l - 3] === 110) { w[l - 1] = 101 // enci -> ence anci -> ance } } else if (w[l - 2] === 103) { if (l >= r1 + 3 && l >= 4 && w[l - 2] === 103 && w[l - 3] === 111 && w[l - 4] === 108) --l // ogi -> og (if preceded by l) } else if (w[l - 2] === 116) { if (l >= r1 + 5 && w[l - 3] === 105) { if (w[l - 4] === 108) { if (l >= 6 && w[l - 5] === 105 && w[l - 6] === 98) { if (l >= r1 + 6) { // biliti -> ble l -= 3 w[l - 2] = 108 w[l - 1] = 101 } } else if (w[l - 4] === 108 && w[l - 5] === 97) { l -= 3 // aliti -> al } } else if (w[l - 4] === 118 && w[l - 5] === 105) { // iviti -> ive l -= 2 w[l - 1] = 101 } } } else if (w[l - 2] === 108 && l >= 3) { if (w[l - 3] === 98) { if (l >= 4 && w[l - 4] === 97) { if (l >= r1 + 4) w[l - 1] = 101 // abli -> able } else if (l >= r1 + 3) { w[l - 1] = 101 // bli -> ble } } else { // Remove li if (w[l - 3] === 108) { if (l >= 5 && w[l - 4] === 117 && w[l - 5] === 102) { if (l >= r1 + 5) l -= 2 // fulli -> ful } else if (l >= r1 + 4 && w[l - 4] === 97) { l -= 2 // alli -> al } } else if (w[l - 3] === 115) { if (l >= 6 && w[l - 4] === 115 && w[l - 5] === 101 && w[l - 6] === 108) { if (l >= r1 + 6) l -= 2 // lessli -> less } else if (l >= r1 + 5 && w[l - 4] === 117 && w[l - 5] === 111) { l -= 2 // ousli -> ous } } else if (l >= 5 && w[l - 3] === 116 && w[l - 4] === 110 && w[l - 5] === 101) { if (l >= r1 + 5) l -= 2 // entli -> ent } else if (is_valid_li(w[l - 3])) { l -= 2 } } } } } // Step_3 if (l >= r1 + 3) { switch (w[l - 1]) { case 108: if (w[l - 3] === 99) { if (l >= r1 + 4 && w[l - 4] === 105 && w[l - 2] === 97) l -= 2 // ical -> ic } else if (w[l - 3] === 102) { if (w[l - 2] === 117) l -= 3 // ful -> <delete> } else if (w[l - 3] === 110) { if (l >= r1 + 6 && w[l - 2] === 97 && w[l - 4] === 111 && w[l - 5] === 105 && w[l - 6] === 116) { if (l >= 7 && w[l - 7] === 97) { if (l >= r1 + 7) { // ational -> ate l -= 4 w[l - 1] = 101 } } else { l -= 2 // tional -> tion } } } break case 101: if (w[l - 2] === 122) { if (l >= r1 + 5 && w[l - 3] === 105 && w[l - 4] === 108 && w[l - 5] === 97) l -= 3 // alize -> al } else if (w[l - 2] === 116) { if (l >= r1 + 5 && w[l - 3] === 97 && w[l - 4] === 99 && w[l - 5] === 105) l -= 3 // icate -> ic } else if (w[l - 2] === 118) { if (l >= r2 + 5 && w[l - 3] === 105 && w[l - 4] === 116 && w[l - 5] === 97) l -= 5 // ative -> <delete> (if in R2) } break case 105: if (l >= r1 + 5 && w[l - 2] === 116 && w[l - 3] === 105 && w[l - 4] === 99 && w[l - 5] === 105) l -= 3 // iciti -> ic break case 115: if (l >= r1 + 4 && w[l - 2] === 115 && w[l - 3] === 101 && w[l - 4] === 110) l -= 4 // ness -> <delete> } } // Step_4 if (l >= r2 + 2) { switch (w[l - 1]) { case 110: if (l >= r2 + 3 && w[l - 2] === 111 && w[l - 3] === 105 && (w[l - 4] === 115 || w[l - 4] === 116)) l -= 3 // ion -> <delete> (if preceded by s or t) break case 108: if (w[l - 2] === 97) l -= 2 // al break case 114: if (w[l - 2] === 101) l -= 2 // er break case 99: if (w[l - 2] === 105) l -= 2 // ic break case 109: if (l >= r2 + 3 && w[l - 2] === 115 && w[l - 3] === 105) l -= 3 // ism break case 105: if (l >= r2 + 3 && w[l - 2] === 116 && w[l - 3] === 105) l -= 3 // iti break case 115: if (l >= r2 + 3 && w[l - 2] === 117 && w[l - 3] === 111) l -= 3 // ous break case 116: if (l >= r2 + 3 && w[l - 2] === 110) { if (w[l - 3] === 97) { l -= 3 // ant } else if (w[l - 3] === 101) { if (l >= 4 && w[l - 4] === 109) { if (l >= 5 && w[l - 5] === 101) { if (l >= r2 + 5) l -= 5 // ement } else if (l >= r2 + 4) { l -= 4 // ment } } else { l -= 3 // ent } } } break case 101: if (w[l - 2] === 99) { if (l >= r2 + 4 && w[l - 3] === 110 && (w[l - 4] === 97 || w[l - 4] === 101)) l -= 4 // ance ence } else if (w[l - 2] === 108) { if (l >= r2 + 4 && w[l - 3] === 98 && (w[l - 4] === 97 || w[l - 4] === 105)) l -= 4 // able ible } else if (w[l - 2] === 116) { if (l >= r2 + 3 && w[l - 3] === 97) l -= 3 // ate } else if (l >= r2 + 3 && (w[l - 2] === 118 || w[l - 2] === 122) && w[l - 3] === 105) { l -= 3 // ive ize } } } // Step_5 if ( l >= r1 + 1 && // r1 is >= 1 ((l >= r2 + 1 && w[l - 1] === 108 && w[l - 2] === 108) || w[l - 1] === 101 && (l >= r2 + 1 || !is_shortv(w, l - 1))) ) --l var out = '' if (y_found) { for (var i = 0; i < l; ++i) { out += String.fromCharCode(w[i] === 89 ? 121 : w[i]) } } else { for (var i = 0; i < l; ++i) // out += w[i] out += String.fromCharCode(w[i]) } return out }