natural 0.1.27 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/.editorconfig +7 -0
  2. package/LICENSE.txt +0 -0
  3. package/Makefile +0 -0
  4. package/README.md +237 -24
  5. package/benchmarks/index.js +1 -1
  6. package/benchmarks/metaphone.js +0 -0
  7. package/benchmarks/soundex.js +0 -0
  8. package/examples/classification/basic.js +0 -0
  9. package/examples/classification/recall.js +0 -0
  10. package/examples/classification/store.js +0 -0
  11. package/examples/inflection/count.js +0 -0
  12. package/examples/inflection/noun.js +0 -0
  13. package/examples/inflection/noun_attach.js +0 -0
  14. package/examples/phonetics/compare.js +0 -0
  15. package/examples/phonetics/sounds_like.js +0 -0
  16. package/examples/phonetics/tokenize_and_phoneticize.js +0 -0
  17. package/examples/stemming/stem_corpus.js +0 -0
  18. package/examples/stemming/stem_word.js +0 -0
  19. package/examples/tfidf/array_example.js +0 -0
  20. package/examples/tfidf/multiple_terms.js +0 -0
  21. package/examples/tfidf/tfidf_example.js +0 -0
  22. package/index.js +0 -0
  23. package/io_spec/test_data/tfidf/one +0 -0
  24. package/io_spec/test_data/tfidf/two +0 -0
  25. package/io_spec/tfidf_spec.js +0 -0
  26. package/io_spec/wordnet_spec.js +0 -0
  27. package/lib/natural/analyzers/sentence_analyzer.js +16 -13
  28. package/lib/natural/classifiers/bayes_classifier.js +6 -2
  29. package/lib/natural/classifiers/classifier.js +0 -0
  30. package/lib/natural/classifiers/logistic_regression_classifier.js +0 -0
  31. package/lib/natural/distance/dice_coefficient.js +0 -0
  32. package/lib/natural/distance/jaro-winkler_distance.js +13 -8
  33. package/lib/natural/distance/levenshtein_distance.js +0 -0
  34. package/lib/natural/index.js +8 -0
  35. package/lib/natural/inflectors/count_inflector.js +0 -0
  36. package/lib/natural/inflectors/form_set.js +0 -0
  37. package/lib/natural/inflectors/fr/count_inflector.js +0 -0
  38. package/lib/natural/inflectors/fr/noun_inflector.js +0 -0
  39. package/lib/natural/inflectors/ja/noun_inflector.js +0 -0
  40. package/lib/natural/inflectors/noun_inflector.js +0 -0
  41. package/lib/natural/inflectors/present_verb_inflector.js +1 -0
  42. package/lib/natural/inflectors/singular_plural_inflector.js +1 -2
  43. package/lib/natural/ngrams/ngrams.js +45 -8
  44. package/lib/natural/ngrams/ngrams_zh.js +83 -0
  45. package/lib/natural/normalizers/normalizer.js +30 -38
  46. package/lib/natural/normalizers/normalizer_ja.js +26 -8
  47. package/lib/natural/normalizers/normalizer_no.js +59 -0
  48. package/lib/natural/phonetics/double_metaphone.js +9 -4
  49. package/lib/natural/phonetics/metaphone.js +6 -1
  50. package/lib/natural/phonetics/phonetic.js +0 -0
  51. package/lib/natural/phonetics/soundex.js +11 -7
  52. package/lib/natural/spellcheck/spellcheck.js +80 -0
  53. package/lib/natural/stemmers/lancaster_rules.js +4 -4
  54. package/lib/natural/stemmers/lancaster_stemmer.js +0 -0
  55. package/lib/natural/stemmers/porter_stemmer.js +90 -63
  56. package/lib/natural/stemmers/porter_stemmer_es.js +22 -23
  57. package/lib/natural/stemmers/porter_stemmer_fr.js +377 -0
  58. package/lib/natural/stemmers/porter_stemmer_no.js +155 -0
  59. package/lib/natural/stemmers/porter_stemmer_pt.js +302 -0
  60. package/lib/natural/stemmers/stemmer.js +0 -0
  61. package/lib/natural/stemmers/stemmer_fr.js +58 -0
  62. package/lib/natural/stemmers/stemmer_no.js +61 -0
  63. package/lib/natural/stemmers/stemmer_pt.js +65 -0
  64. package/lib/natural/stemmers/token.js +163 -0
  65. package/lib/natural/tfidf/tfidf.js +50 -19
  66. package/lib/natural/tokenizers/aggressive_tokenizer.js +0 -0
  67. package/lib/natural/tokenizers/aggressive_tokenizer_es.js +0 -0
  68. package/lib/natural/tokenizers/aggressive_tokenizer_fr.js +36 -0
  69. package/lib/natural/tokenizers/aggressive_tokenizer_nl.js +0 -0
  70. package/lib/natural/tokenizers/aggressive_tokenizer_no.js +39 -0
  71. package/lib/natural/tokenizers/aggressive_tokenizer_pt.js +0 -0
  72. package/lib/natural/tokenizers/regexp_tokenizer.js +0 -0
  73. package/lib/natural/tokenizers/tokenizer.js +2 -2
  74. package/lib/natural/tokenizers/treebank_word_tokenizer.js +0 -0
  75. package/lib/natural/trie/trie.js +47 -0
  76. package/lib/natural/util/bag.js +50 -0
  77. package/lib/natural/util/edge_weighted_digraph.js +112 -0
  78. package/lib/natural/util/longest_path_tree.js +99 -0
  79. package/lib/natural/util/shortest_path_tree.js +100 -0
  80. package/lib/natural/util/stopwords.js +0 -0
  81. package/lib/natural/util/stopwords_fr.js +194 -0
  82. package/lib/natural/util/stopwords_nl.js +43 -0
  83. package/lib/natural/util/stopwords_no.js +42 -0
  84. package/lib/natural/util/stopwords_pt.js +136 -0
  85. package/lib/natural/util/topological.js +98 -0
  86. package/lib/natural/wordnet/data_file.js +0 -0
  87. package/lib/natural/wordnet/index_file.js +0 -0
  88. package/lib/natural/wordnet/wordnet.js +0 -0
  89. package/lib/natural/wordnet/wordnet_file.js +0 -0
  90. package/package.json +2 -2
  91. package/spec/aggressive_tokenizer_fr_spec.js +101 -0
  92. package/spec/aggressive_tokenizer_pt_spec.js +0 -0
  93. package/spec/aggressive_tokenizer_spec.js +0 -0
  94. package/spec/bayes_classifier_spec.js +12 -0
  95. package/spec/classifier_spec.js +84 -0
  96. package/spec/count_inflector_fr_spec.js +0 -0
  97. package/spec/count_inflector_spec.js +0 -0
  98. package/spec/dice_coefficient_spec.js +0 -0
  99. package/spec/double_metaphone_spec.js +10 -1
  100. package/spec/jaro-winkler_spec.js +0 -0
  101. package/spec/lancaster_stemmer_spec.js +10 -1
  102. package/spec/levenshtein_spec.js +0 -0
  103. package/spec/logistic_regression_classifier_spec.js +0 -0
  104. package/spec/longest_path_tree_spec.js +102 -0
  105. package/spec/metaphone_spec.js +10 -0
  106. package/spec/ngram_spec.js +61 -0
  107. package/spec/ngram_zh_spec.js +122 -0
  108. package/spec/normalizer_ja_spec.js +9 -3
  109. package/spec/normalizer_no_spec.js +111 -0
  110. package/spec/normalizer_spec.js +26 -5
  111. package/spec/noun_inflector_fr_spec.js +0 -0
  112. package/spec/noun_inflector_ja_spec.js +0 -0
  113. package/spec/noun_inflector_spec.js +0 -0
  114. package/spec/porter_stemmer_fr_spec.js +101 -0
  115. package/spec/porter_stemmer_no_spec.js +143 -0
  116. package/spec/porter_stemmer_pt_spec.js +50 -0
  117. package/spec/porter_stemmer_spec.js +49 -0
  118. package/spec/present_verb_inflector_spec.js +3 -0
  119. package/spec/remove_diacritics_spec.js +31 -0
  120. package/spec/sentence_analyzer_spec.js +248 -0
  121. package/spec/shortest_path_tree_spec.js +132 -0
  122. package/spec/soundex_spec.js +13 -9
  123. package/spec/spellcheck_spec.js +92 -0
  124. package/spec/stemmer_token_spec.js +161 -0
  125. package/spec/test_data/snowball_fr.txt +20402 -0
  126. package/spec/test_data/snowball_no.txt +20628 -0
  127. package/spec/test_data/snowball_pt.txt +32016 -0
  128. package/spec/test_data/tfdif_testcorpus.txt +0 -0
  129. package/spec/test_data/tfidf_teststopwords.txt +0 -0
  130. package/spec/test_data/wordnet_mini.sql +0 -0
  131. package/spec/tfidf_spec.js +153 -28
  132. package/spec/tokenizer_ja_spec.js +0 -0
  133. package/spec/treebank_word_tokenizer_spec.js +0 -0
  134. package/spec/trie_spec.js +27 -3
@@ -25,19 +25,19 @@ var Stemmer = require('./stemmer');
25
25
  // denote groups of consecutive consonants with a C and consecutive vowels
26
26
  // with a V.
27
27
  function categorizeGroups(token) {
28
- return token.replace(/[^aeiou]+/g, 'C').replace(/[aeiouy]+/g, 'V');
28
+ return token.replace(/[^aeiouy]+y/g, 'CV').replace(/[aeiou]+/g, 'V').replace(/[^V]+/g, 'C');
29
29
  }
30
30
 
31
31
  // denote single consonants with a C and single vowels with a V
32
32
  function categorizeChars(token) {
33
- return token.replace(/[^aeiou]/g, 'C').replace(/[aeiouy]/g, 'V');
33
+ return token.replace(/[^aeiouy]y/g, 'CV').replace(/[aeiou]/g, 'V').replace(/[^V]/g, 'C');
34
34
  }
35
35
 
36
36
  // calculate the "measure" M of a word. M is the count of VC sequences dropping
37
37
  // an initial C if it exists and a trailing V if it exists.
38
38
  function measure(token) {
39
39
  if(!token)
40
- return -1;
40
+ return -1;
41
41
 
42
42
  return categorizeGroups(token).replace(/^C/, '').replace(/V$/, '').length / 2;
43
43
  }
@@ -67,14 +67,12 @@ function attemptReplace(token, pattern, replacement, callback) {
67
67
  // attempt to replace a list of patterns/replacements on a token for a minimum
68
68
  // measure M.
69
69
  function attemptReplacePatterns(token, replacements, measureThreshold) {
70
- var replacement = null;
70
+ var replacement = token;
71
71
 
72
- for(var i = 0; i < replacements.length; i++) {
73
- if(measureThreshold == null || measure(attemptReplace(token, replacements[i][0], '')) > measureThreshold)
74
- replacement = attemptReplace(token, replacements[i][0], replacements[i][1]);
75
-
76
- if(replacement)
77
- break;
72
+ for(var i = 0; i < replacements.length; i++) {
73
+ if(measureThreshold == null || measure(attemptReplace(token, replacements[i][0], replacements[i][1])) > measureThreshold) {
74
+ replacement = attemptReplace(replacement, replacements[i][0], replacements[i][2]) || replacement;
75
+ }
78
76
  }
79
77
 
80
78
  return replacement;
@@ -83,51 +81,73 @@ function attemptReplacePatterns(token, replacements, measureThreshold) {
83
81
  // replace a list of patterns/replacements on a word. if no match is made return
84
82
  // the original token.
85
83
  function replacePatterns(token, replacements, measureThreshold) {
86
- var result = attemptReplacePatterns(token, replacements, measureThreshold);
87
- token = result == null ? token : result;
88
-
89
- return token;
84
+ return attemptReplacePatterns(token, replacements, measureThreshold) || token;
85
+ }
86
+
87
+ // TODO: this should replace all of the messy replacement stuff above
88
+ function replaceRegex(token, regex, includeParts, minimumMeasure) {
89
+ var parts;
90
+ var result = '';
91
+
92
+ if(regex.test(token)) {
93
+ parts = regex.exec(token);
94
+
95
+ includeParts.forEach(function(i) {
96
+ result += parts[i];
97
+ });
98
+ }
99
+
100
+ if(measure(result) > minimumMeasure) {
101
+ return result;
102
+ }
103
+
104
+ return null;
90
105
  }
91
106
 
92
107
  // step 1a as defined for the porter stemmer algorithm.
93
108
  function step1a(token) {
94
- if(token.match(/(ss|i)es$/))
109
+ if(token.match(/(ss|i)es$/)) {
95
110
  return token.replace(/(ss|i)es$/, '$1');
96
-
97
- if(token.substr(-1) == 's' && token.substr(-2, 1) != 's' && token.length > 3)
111
+ }
112
+
113
+ if(token.substr(-1) == 's' && token.substr(-2, 1) != 's' && token.length > 2) {
98
114
  return token.replace(/s?$/, '');
99
-
115
+ }
116
+
100
117
  return token;
101
118
  }
102
119
 
103
120
  // step 1b as defined for the porter stemmer algorithm.
104
121
  function step1b(token) {
105
122
  if(token.substr(-3) == 'eed') {
106
- if(measure(token.substr(0, token.length - 3)) > 0)
123
+ if(measure(token.substr(0, token.length - 3)) > 0)
107
124
  return token.replace(/eed$/, 'ee');
108
125
  } else {
109
- var result = attemptReplace(token, /ed|ing$/, '', function(token) {
110
- if(categorizeGroups(token).indexOf('V') > 0) {
111
- var result = attemptReplacePatterns(token, [['at', 'ate'], ['bl', 'ble'], ['iz', 'ize']]);
112
-
113
- if(result)
114
- return result;
115
- else {
116
- if(endsWithDoublCons(token) && token.match(/[^lsz]$/))
117
- return token.replace(/([^aeiou])\1$/, '$1');
118
-
119
- if(measure(token) == 1 && categorizeChars(token).substr(-3) == 'CVC' && token.match(/[^wxy]$/))
120
- return token + 'e';
121
- }
122
-
123
- return token;
124
- }
125
-
126
- return null;
127
- });
128
-
129
- if(result)
130
- return result;
126
+ var result = attemptReplace(token, /(ed|ing)$/, '', function(token) {
127
+ if(categorizeGroups(token).indexOf('V') >= 0) {
128
+ result = attemptReplacePatterns(token, [['at', '', 'ate'], ['bl', '', 'ble'], ['iz', '', 'ize']]);
129
+
130
+ if(result != token) {
131
+ return result;
132
+ } else {
133
+ if(endsWithDoublCons(token) && token.match(/[^lsz]$/)) {
134
+ return token.replace(/([^aeiou])\1$/, '$1');
135
+ }
136
+
137
+ if(measure(token) == 1 && categorizeChars(token).substr(-3) == 'CVC' && token.match(/[^wxy]$/)) {
138
+ return token + 'e';
139
+ }
140
+ }
141
+
142
+ return token;
143
+ }
144
+
145
+ return null;
146
+ });
147
+
148
+ if(result) {
149
+ return result;
150
+ }
131
151
  }
132
152
 
133
153
  return token;
@@ -135,44 +155,48 @@ function step1b(token) {
135
155
 
136
156
  // step 1c as defined for the porter stemmer algorithm.
137
157
  function step1c(token) {
138
- if(categorizeGroups(token).substr(-2, 1) == 'V') {
139
- if(token.substr(-1) == 'y')
140
- return token.replace(/y$/, 'i');
158
+ var categorizedGroups = categorizeGroups(token);
159
+
160
+ if(token.substr(-1) == 'y' && categorizedGroups.substr(0, categorizedGroups.length - 1).indexOf('V') > -1) {
161
+ return token.replace(/y$/, 'i');
141
162
  }
142
-
163
+
143
164
  return token;
144
165
  }
145
166
 
146
167
  // step 2 as defined for the porter stemmer algorithm.
147
168
  function step2(token) {
148
- return replacePatterns(token, [['ational', 'ate'], ['tional', 'tion'], ['enci', 'ence'], ['anci', 'ance'],
149
- ['izer', 'ize'], ['abli', 'able'], ['alli', 'al'], ['entli', 'ent'], ['eli', 'e'],
150
- ['ousli', 'ous'], ['ization', 'ize'], ['ation', 'ate'], ['ator', 'ate'],['alism', 'al'],
151
- ['iveness', 'ive'], ['fulness', 'ful'], ['ousness', 'ous'], ['aliti', 'al'],
152
- ['iviti', 'ive'], ['biliti', 'ble']], 0);
169
+ token = replacePatterns(token, [['ational', '', 'ate'], ['tional', '', 'tion'], ['enci', '', 'ence'], ['anci', '', 'ance'],
170
+ ['izer', '', 'ize'], ['abli', '', 'able'], ['bli', '', 'ble'], ['alli', '', 'al'], ['entli', '', 'ent'], ['eli', '', 'e'],
171
+ ['ousli', '', 'ous'], ['ization', '', 'ize'], ['ation', '', 'ate'], ['ator', '', 'ate'],['alism', '', 'al'],
172
+ ['iveness', '', 'ive'], ['fulness', '', 'ful'], ['ousness', '', 'ous'], ['aliti', '', 'al'],
173
+ ['iviti', '', 'ive'], ['biliti', '', 'ble'], ['logi', '', 'log']], 0);
174
+
175
+ return token;
153
176
  }
154
177
 
155
178
  // step 3 as defined for the porter stemmer algorithm.
156
179
  function step3(token) {
157
- return replacePatterns(token, [['icate', 'ic'], ['ative', ''], ['alize', 'al'],
158
- ['iciti', 'ic'], ['ical', 'ic'], ['ful', ''], ['ness', '']], 0);
180
+ return replacePatterns(token, [['icate', '', 'ic'], ['ative', '', ''], ['alize', '', 'al'],
181
+ ['iciti', '', 'ic'], ['ical', '', 'ic'], ['ful', '', ''], ['ness', '', '']], 0);
159
182
  }
160
183
 
161
184
  // step 4 as defined for the porter stemmer algorithm.
162
185
  function step4(token) {
163
- return replacePatterns(token, [['al', ''], ['ance', ''], ['ence', ''], ['er', ''],
164
- ['ic', ''], ['able', ''], ['ible', ''], ['ant', ''],
165
- ['ement', ''], ['ment', ''], ['ent', ''], [/([st])ion/, '$1'], ['ou', ''], ['ism', ''],
166
- ['ate', ''], ['iti', ''], ['ous', ''], ['ive', ''],
167
- ['ize', '']], 1);
186
+ return replaceRegex(token, /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/, [1], 1) ||
187
+ replaceRegex(token, /^(.+?)(s|t)(ion)$/, [1, 2], 1) ||
188
+ token;
168
189
  }
169
190
 
170
191
  // step 5a as defined for the porter stemmer algorithm.
171
192
  function step5a(token) {
172
- var m = measure(token);
173
-
174
- if(token.length > 3 && ((m > 1 && token.substr(-1) == 'e') || (m == 1 && !(categorizeChars(token).substr(-4, 3) == 'CVC' && token.match(/[^wxy].$/)))))
175
- return token.replace(/e$/, '');
193
+ var m = measure(token.replace(/e$/, ''));
194
+
195
+
196
+
197
+ if(m > 1 || (m == 1 && !(categorizeChars(token).substr(-4, 3) == 'CVC' && token.match(/[^wxy].$/)))) {
198
+ token = token.replace(/e$/, '');
199
+ }
176
200
 
177
201
  return token;
178
202
  }
@@ -180,8 +204,7 @@ function step5a(token) {
180
204
  // step 5b as defined for the porter stemmer algorithm.
181
205
  function step5b(token) {
182
206
  if(measure(token) > 1) {
183
- if(endsWithDoublCons(token) && token.substr(-2) == 'll')
184
- return token.replace(/ll$/, 'l');
207
+ return token.replace(/ll$/, 'l');
185
208
  }
186
209
 
187
210
  return token;
@@ -190,12 +213,16 @@ function step5b(token) {
190
213
  var PorterStemmer = new Stemmer();
191
214
  module.exports = PorterStemmer;
192
215
 
216
+
193
217
  // perform full stemming algorithm on a single word
194
218
  PorterStemmer.stem = function(token) {
219
+ if(token.length < 3) return token;
195
220
  return step5b(step5a(step4(step3(step2(step1c(step1b(step1a(token.toLowerCase())))))))).toString();
196
221
  };
197
222
 
198
223
  //exports for tests
224
+ PorterStemmer.categorizeGroups = categorizeGroups;
225
+ PorterStemmer.measure = measure;
199
226
  PorterStemmer.step1a = step1a;
200
227
  PorterStemmer.step1b = step1b;
201
228
  PorterStemmer.step1c = step1c;
@@ -67,7 +67,6 @@ function removeAccent(token) {
67
67
  return str;
68
68
  };
69
69
 
70
-
71
70
  // perform full stemming algorithm on a single word
72
71
  PorterStemmer.stem = function(token) {
73
72
  token = token.toLowerCase();
@@ -96,7 +95,7 @@ PorterStemmer.stem = function(token) {
96
95
  if(isVowel(token[1])) {
97
96
  // If the second letter is a consonant, RV is the region after the next following vowel
98
97
  rv = getNextVowelPos(token, 2) +1;
99
- } else if (isVowel(token[0]) && isVowel(token[1])) {
98
+ } else if (isVowel(token[0]) && isVowel(token[1])) {
100
99
  // or if the first two letters are vowels, RV is the region after the next consonant
101
100
  rv = getNextConsonantPos(token, 2) + 1;
102
101
  } else {
@@ -113,41 +112,41 @@ PorterStemmer.stem = function(token) {
113
112
  var token_orig = token;
114
113
 
115
114
  // Step 0: Attached pronoun
116
- var pronoun_suf = new Array('me', 'se', 'sela', 'selo', 'selas', 'selos', 'la', 'le', 'lo', 'las', 'les', 'los', 'nos');
117
- var pronoun_suf_pre1 = new Array('éndo', 'ándo', 'ár', 'ér', 'ír');
115
+ var pronoun_suf = new Array('me', 'se', 'sela', 'selo', 'selas', 'selos', 'la', 'le', 'lo', 'las', 'les', 'los', 'nos');
116
+ var pronoun_suf_pre1 = new Array('éndo', 'ándo', 'ár', 'ér', 'ír');
118
117
  var pronoun_suf_pre2 = new Array('ando', 'iendo', 'ar', 'er', 'ir');
119
118
  var suf = endsinArr(token, pronoun_suf);
120
119
 
121
-
120
+
122
121
  if (suf!='') {
123
122
 
124
123
  var pre_suff = endsinArr(rv_txt.slice(0,-suf.length),pronoun_suf_pre1);
125
-
124
+
126
125
  if (pre_suff != '') {
127
-
126
+
128
127
  token = removeAccent(token.slice(0,-suf.length));
129
128
  } else {
130
129
  var pre_suff = endsinArr(rv_txt.slice(0,-suf.length),pronoun_suf_pre2);
131
-
130
+
132
131
  if (pre_suff != '' ||
133
- (endsin(token, 'yendo' ) &&
132
+ (endsin(token, 'yendo' ) &&
134
133
  (token.slice(-suf.length-6,1) == 'u'))) {
135
134
  token = token.slice(0,-suf.length);
136
135
  }
137
136
  }
138
137
  }
139
-
138
+
140
139
  if (token != token_orig) {
141
140
  r1_txt = token.substring(r1-1);
142
141
  r2_txt = token.substring(r2-1);
143
142
  rv_txt = token.substring(rv-1);
144
143
  }
145
144
  var token_after0 = token;
146
-
145
+
147
146
  if ((suf = endsinArr(r2_txt, new Array('anza', 'anzas', 'ico', 'ica', 'icos', 'icas', 'ismo', 'ismos', 'able', 'ables', 'ible', 'ibles', 'ista', 'istas', 'oso', 'osa', 'osos', 'osas', 'amiento', 'amientos', 'imiento', 'imientos'))) != '') {
148
- token = token.slice(0, -suf.length);
147
+ token = token.slice(0, -suf.length);
149
148
  } else if ((suf = endsinArr(r2_txt, new Array('icadora', 'icador', 'icación', 'icadoras', 'icadores', 'icaciones', 'icante', 'icantes', 'icancia', 'icancias', 'adora', 'ador', 'ación', 'adoras', 'adores', 'aciones', 'ante', 'antes', 'ancia', 'ancias'))) != '') {
150
- token = token.slice(0, -suf.length);
149
+ token = token.slice(0, -suf.length);
151
150
  } else if ((suf = endsinArr(r2_txt, new Array('logía', 'logías'))) != '') {
152
151
  token = token.slice(0, -suf.length)+ 'log';
153
152
  } else if ((suf =endsinArr(r2_txt, new Array('ución', 'uciones'))) != '') {
@@ -172,37 +171,37 @@ PorterStemmer.stem = function(token) {
172
171
  rv_txt = token.substring(rv-1);
173
172
  }
174
173
  var token_after1 = token;
175
-
174
+
176
175
  if (token_after0 == token_after1) {
177
- // Do step 2a if no ending was removed by step 1.
176
+ // Do step 2a if no ending was removed by step 1.
178
177
  if ((suf = endsinArr(rv_txt, new Array('ya', 'ye', 'yan', 'yen', 'yeron', 'yendo', 'yo', 'yó', 'yas', 'yes', 'yais', 'yamos'))) != '' && (token.substring(suf.length-1,1) == 'u')) {
179
178
  token = token.slice(0, -suf.length);
180
179
  }
181
-
180
+
182
181
  if (token != token_after1) {
183
182
  r1_txt = token.substring(r1-1);
184
183
  r2_txt = token.substring(r2-1);
185
184
  rv_txt = token.substring(rv-1);
186
185
  }
187
186
  var token_after2a = token;
188
-
189
- // Do Step 2b if step 2a was done, but failed to remove a suffix.
187
+
188
+ // Do Step 2b if step 2a was done, but failed to remove a suffix.
190
189
  if (token_after2a == token_after1) {
191
-
190
+
192
191
  if ((suf = endsinArr(rv_txt,new Array('en', 'es', 'éis', 'emos'))) != '') {
193
192
  token = token.slice(0,-suf.length);
194
193
  if (endsin(token, 'gu')) {
195
194
  token = token.slice(0,-1);
196
195
  }
197
196
  } else if ((suf = endsinArr(rv_txt, new Array('arían', 'arías', 'arán', 'arás', 'aríais', 'aría', 'aréis', 'aríamos', 'aremos', 'ará', 'aré', 'erían', 'erías', 'erán', 'erás', 'eríais', 'ería', 'eréis', 'eríamos', 'eremos', 'erá', 'eré', 'irían', 'irías', 'irán', 'irás', 'iríais', 'iría', 'iréis', 'iríamos', 'iremos', 'irá', 'iré', 'aba', 'ada', 'ida', 'ía', 'ara', 'iera', 'ad', 'ed', 'id', 'ase', 'iese', 'aste', 'iste', 'an', 'aban', 'ían', 'aran', 'ieran', 'asen', 'iesen', 'aron', 'ieron', 'ado', 'ido', 'ando', 'iendo', 'ió', 'ar', 'er', 'ir', 'as', 'abas', 'adas', 'idas', 'ías', 'aras', 'ieras', 'ases', 'ieses', 'ís', 'áis', 'abais', 'íais', 'arais', 'ierais', ' aseis', 'ieseis', 'asteis', 'isteis', 'ados', 'idos', 'amos', 'ábamos', 'íamos', 'imos', 'áramos', 'iéramos', 'iésemos', 'ásemos'))) != '') {
198
-
197
+
199
198
  token = token.slice(0, -suf.length);
200
-
199
+
201
200
  }
202
201
  }
203
202
  }
204
203
 
205
- // Always do step 3.
204
+ // Always do step 3.
206
205
  r1_txt = token.substring(r1-1);
207
206
  r2_txt = token.substring(r2-1);
208
207
  rv_txt = token.substring(rv-1);
@@ -216,7 +215,7 @@ PorterStemmer.stem = function(token) {
216
215
  token = token.slice(0,-1);
217
216
  }
218
217
  }
219
-
218
+
220
219
  return removeAccent(token);
221
220
 
222
221
  };