natural 0.1.28 → 0.4.0

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 (117) hide show
  1. package/.editorconfig +7 -0
  2. package/.npmignore +4 -11
  3. package/README.md +190 -50
  4. package/bayes_classifier.json +1 -0
  5. package/lib/natural/analyzers/sentence_analyzer.js +8 -5
  6. package/lib/natural/brill_pos_tagger/data/Dutch/README.txt +2 -0
  7. package/lib/natural/brill_pos_tagger/data/Dutch/brill_CONTEXTRULES.jg +285 -0
  8. package/lib/natural/brill_pos_tagger/data/Dutch/brill_LEXICON.jg +11699 -0
  9. package/lib/natural/brill_pos_tagger/data/English/README.txt +8 -0
  10. package/lib/natural/brill_pos_tagger/data/English/lexicon_from_posjs.json +297827 -0
  11. package/lib/natural/brill_pos_tagger/data/English/tr_from_brill_paper.txt +10 -0
  12. package/lib/natural/brill_pos_tagger/data/English/tr_from_posjs.txt +18 -0
  13. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tagger.js +136 -0
  14. package/lib/natural/brill_pos_tagger/lib/Predicate.js +410 -0
  15. package/lib/natural/brill_pos_tagger/lib/TF_Parser.js +717 -0
  16. package/lib/natural/brill_pos_tagger/lib/TF_Parser.pegjs +55 -0
  17. package/lib/natural/brill_pos_tagger/lib/TransformationRule.js +49 -0
  18. package/lib/natural/classifiers/bayes_classifier.js +6 -5
  19. package/lib/natural/classifiers/classifier.js +3 -2
  20. package/lib/natural/classifiers/logistic_regression_classifier.js +9 -5
  21. package/lib/natural/distance/dice_coefficient.js +22 -12
  22. package/lib/natural/distance/jaro-winkler_distance.js +13 -8
  23. package/lib/natural/index.js +6 -0
  24. package/lib/natural/inflectors/present_verb_inflector.js +1 -0
  25. package/lib/natural/ngrams/ngrams.js +6 -0
  26. package/lib/natural/normalizers/normalizer_ja.js +26 -8
  27. package/lib/natural/phonetics/double_metaphone.js +9 -4
  28. package/lib/natural/phonetics/metaphone.js +4 -0
  29. package/lib/natural/phonetics/soundex.js +11 -7
  30. package/lib/natural/spellcheck/spellcheck.js +80 -0
  31. package/lib/natural/stemmers/porter_stemmer.js +90 -62
  32. package/lib/natural/stemmers/porter_stemmer_fr.js +8 -3
  33. package/lib/natural/stemmers/porter_stemmer_pt.js +302 -0
  34. package/lib/natural/stemmers/stemmer.js +31 -6
  35. package/lib/natural/stemmers/stemmer_pt.js +65 -0
  36. package/lib/natural/stemmers/token.js +163 -0
  37. package/lib/natural/tfidf/tfidf.js +49 -18
  38. package/lib/natural/tokenizers/regexp_tokenizer.js +3 -3
  39. package/{examples/inflection/noun.js → lib/natural/tokenizers/sentence_tokenizer.js} +14 -10
  40. package/lib/natural/tokenizers/tokenizer_case.js +58 -0
  41. package/lib/natural/util/bag.js +1 -0
  42. package/lib/natural/util/stopwords_pt.js +136 -0
  43. package/lib/natural/wordnet/wordnet.js +2 -2
  44. package/lib/natural/wordnet/wordnet_file.js +1 -1
  45. package/lr_classifier.json +1 -0
  46. package/package.json +7 -4
  47. package/package.json~ +66 -0
  48. package/benchmarks/index.js +0 -32
  49. package/benchmarks/metaphone.js +0 -27
  50. package/benchmarks/soundex.js +0 -27
  51. package/examples/classification/basic.js +0 -35
  52. package/examples/classification/recall.js +0 -28
  53. package/examples/classification/store.js +0 -37
  54. package/examples/inflection/count.js +0 -35
  55. package/examples/inflection/noun_attach.js +0 -33
  56. package/examples/phonetics/compare.js +0 -39
  57. package/examples/phonetics/sounds_like.js +0 -40
  58. package/examples/phonetics/tokenize_and_phoneticize.js +0 -54
  59. package/examples/stemming/stem_corpus.js +0 -29
  60. package/examples/stemming/stem_word.js +0 -26
  61. package/examples/tfidf/array_example.js +0 -34
  62. package/examples/tfidf/multiple_terms.js +0 -33
  63. package/examples/tfidf/tfidf_example.js +0 -44
  64. package/io_spec/test_data/tfidf/one +0 -1
  65. package/io_spec/test_data/tfidf/two +0 -1
  66. package/io_spec/tfidf_spec.js +0 -50
  67. package/io_spec/wordnet_spec.js +0 -81
  68. package/spec/aggressive_tokenizer_es_spec.js +0 -36
  69. package/spec/aggressive_tokenizer_fr_spec.js +0 -101
  70. package/spec/aggressive_tokenizer_nl_spec.js +0 -36
  71. package/spec/aggressive_tokenizer_pt_spec.js +0 -56
  72. package/spec/aggressive_tokenizer_spec.js +0 -56
  73. package/spec/bayes_classifier_spec.js +0 -173
  74. package/spec/classifier_spec.js +0 -91
  75. package/spec/count_inflector_fr_spec.js +0 -44
  76. package/spec/count_inflector_spec.js +0 -73
  77. package/spec/dice_coefficient_spec.js +0 -26
  78. package/spec/double_metaphone_spec.js +0 -743
  79. package/spec/jaro-winkler_spec.js +0 -53
  80. package/spec/lancaster_stemmer_spec.js +0 -73
  81. package/spec/levenshtein_spec.js +0 -66
  82. package/spec/logistic_regression_classifier_spec.js +0 -122
  83. package/spec/longest_path_tree_spec.js +0 -102
  84. package/spec/metaphone_spec.js +0 -247
  85. package/spec/ngram_spec.js +0 -130
  86. package/spec/ngram_zh_spec.js +0 -122
  87. package/spec/normalizer_ja_spec.js +0 -154
  88. package/spec/normalizer_no_spec.js +0 -111
  89. package/spec/normalizer_spec.js +0 -118
  90. package/spec/noun_inflector_fr_spec.js +0 -476
  91. package/spec/noun_inflector_ja_spec.js +0 -112
  92. package/spec/noun_inflector_spec.js +0 -270
  93. package/spec/porter_stemmer_fr_spec.js +0 -101
  94. package/spec/porter_stemmer_it_spec.js +0 -44
  95. package/spec/porter_stemmer_no_spec.js +0 -143
  96. package/spec/porter_stemmer_ru_spec.js +0 -63
  97. package/spec/porter_stemmer_spec.js +0 -137
  98. package/spec/present_verb_inflector_spec.js +0 -125
  99. package/spec/sentence_analyzer_spec.js +0 -29
  100. package/spec/shortest_path_tree_spec.js +0 -132
  101. package/spec/soundex_spec.js +0 -154
  102. package/spec/stemmer_ja_spec.js +0 -66
  103. package/spec/test_data/snowball_fr.txt +0 -20402
  104. package/spec/test_data/snowball_it.txt +0 -35482
  105. package/spec/test_data/snowball_no.txt +0 -20628
  106. package/spec/test_data/tfdif_testcorpus.txt +0 -7
  107. package/spec/test_data/tfidf_document1.txt +0 -1
  108. package/spec/test_data/tfidf_document2.txt +0 -1
  109. package/spec/test_data/tfidf_document3.txt +0 -1
  110. package/spec/test_data/tfidf_document4.txt +0 -1
  111. package/spec/test_data/tfidf_teststopwords.txt +0 -1
  112. package/spec/test_data/wordnet_mini.sql +0 -95
  113. package/spec/tfidf_spec.js +0 -198
  114. package/spec/tokenizer_ja_spec.js +0 -58
  115. package/spec/transliterator_ja_spec.js +0 -103
  116. package/spec/treebank_word_tokenizer_spec.js +0 -36
  117. package/spec/trie_spec.js +0 -206
@@ -0,0 +1,10 @@
1
+ TO IN NEXT-TAG AT
2
+ VBN VBD PREV-WORD-IS-CAP YES
3
+ VBD VBN PREV-1-OR-2-OR-3-TAG HVD
4
+ VB NN PREV-1-OR-2-TAG AT
5
+ NN VB PREV-TAG TO
6
+ TO IN NEXT-WORD-IS-CAP YES
7
+ NN VB PREV-TAG MD
8
+ PPS PPO NEXT-TAG .
9
+ VBN VBD PREV-TAG PPS
10
+ NP NN CURRENT-WORD-IS-CAP NO
@@ -0,0 +1,18 @@
1
+ VBD NN PREV-TAG DT
2
+ VBP NN PREV-TAG DT
3
+ VB NN PREV-TAG DT
4
+ NN CD CURRENT-WORD-IS-NUMBER YES
5
+ NNP CD CURRENT-WORD-IS-NUMBER YES
6
+ NNS CD CURRENT-WORD-IS-NUMBER YES
7
+ NNPS CD CURRENT-WORD-IS-NUMBER YES
8
+ NN URL CURRENT-WORD-IS-URL YES
9
+ NNS URL CURRENT-WORD-IS-URL YES
10
+ NNP URL CURRENT-WORD-IS-URL YES
11
+ NNPS URL CURRENT-WORD-IS-URL YES
12
+ NN VBN CURRENT-WORD-ENDS-WITH ed
13
+ * RB CURRENT-WORD-ENDS-WITH ly
14
+ NN JJ CURRENT-WORD-ENDS-WITH al
15
+ NNS JJ CURRENT-WORD-ENDS-WITH al
16
+ NN VB PREV-WORD-IS would
17
+ NN NNS CURRENT-WORD-ENDS-WITH s
18
+ NN VBG CURRENT-WORD-ENDS-WITH ing
@@ -0,0 +1,136 @@
1
+ /*
2
+ Brill's POS Tagger
3
+ Copyright (C) 2015 Hugo W.L. ter Doest
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ var log4js = require('log4js');
20
+ var logger = log4js.getLogger();
21
+
22
+ var fs = require("fs");
23
+
24
+ var TF_Parser = require('./TF_Parser');
25
+
26
+ logger.setLevel('WARN');
27
+
28
+ // Tags a sentence, sentence is an array of words
29
+ // Returns an array of tagged words; a tagged words is an array consisting of
30
+ // the word itself followed by its lexical category
31
+ Brill_POS_Tagger.prototype.tag = function(sentence) {
32
+ var tagged_sentence = new Array(sentence.length);
33
+
34
+ // Initialise result
35
+ for (var i = 0, size = sentence.length; i < size; i++) {
36
+ var ss = this.lexicon[sentence[i]];
37
+ if (!ss) {
38
+ ss = this.lexicon[sentence[i].toLowerCase()];
39
+ }
40
+ tagged_sentence[i] = [];
41
+ tagged_sentence[i][0] = sentence[i];
42
+ if (!ss) { // If not found assign default_category
43
+ tagged_sentence[i][1] = this.default_category;
44
+ }
45
+ else {
46
+ tagged_sentence[i][1] = ss[0];
47
+ }
48
+ }
49
+ // Apply transformation rules
50
+ for (var i = 0, size = sentence.length; i < size; i++) {
51
+ this.transformation_rules.forEach(function(rule) {
52
+ rule.apply(tagged_sentence, i);
53
+ });
54
+ }
55
+ return(tagged_sentence);
56
+ };
57
+
58
+ Brill_POS_Tagger.prototype.parse_lexicon = function(data) {
59
+ var that = this;
60
+ // Split into an array of non-empty lines
61
+ var arrayOfLines = data.match(/[^\r\n]+/g);
62
+ this.lexicon = {};
63
+ arrayOfLines.forEach(function(line) {
64
+ // Split line by whitespace
65
+ var elements = line.trim().split(/\s+/);
66
+ if (elements.length > 0) {
67
+ that.lexicon[elements[0]] = elements.slice(1);
68
+ }
69
+ });
70
+ };
71
+
72
+ Brill_POS_Tagger.prototype.read_lexicon = function(lexicon_file,callback) {
73
+ var that = this;
74
+
75
+ // Read lexicon
76
+ fs.readFile(lexicon_file, 'utf8', function (error, data) {
77
+ if (error) {
78
+ logger.error(error);
79
+ callback(error);
80
+ }
81
+ else {
82
+ if (data[0] === "{") {
83
+ // Lexicon is in JSON format
84
+ that.lexicon = JSON.parse(data);
85
+ callback();
86
+ }
87
+ else {
88
+ // Lexicon is plain text
89
+ that.parse_lexicon(data);
90
+ callback();
91
+ }
92
+ logger.debug('Brill_POS_Tagger.read_lexicon: number of lexicon entries read: ' + Object.keys(that.lexicon).length);
93
+ }
94
+ });
95
+ };
96
+
97
+ Brill_POS_Tagger.prototype.read_transformation_rules = function(rules_file, callback) {
98
+ var that = this;
99
+
100
+ // Read transformation rules
101
+ fs.readFile(rules_file, 'utf8', function (err, data) {
102
+ if (err) {
103
+ logger.error(error);
104
+ callback(err);
105
+ }
106
+ else {
107
+ that.transformation_rules = TF_Parser.parse(data);
108
+ logger.debug(that.transformation_rules);
109
+ logger.debug('Brill_POS_Tagger.read_transformation_rules: number of transformation rules read: ' + that.transformation_rules.length);
110
+ callback();
111
+ }
112
+ });
113
+ };
114
+
115
+ function Brill_POS_Tagger(lexicon_file, rules_file, default_category, callback) {
116
+ var that = this;
117
+
118
+ this.default_category = default_category;
119
+ this.read_lexicon(lexicon_file, function(error) {
120
+ if (error) {
121
+ callback(error);
122
+ }
123
+ else {
124
+ that.read_transformation_rules(rules_file, function(error) {
125
+ if (error) {
126
+ callback(error);
127
+ }
128
+ else {
129
+ callback();
130
+ }
131
+ });
132
+ }
133
+ });
134
+ }
135
+
136
+ module.exports = Brill_POS_Tagger;
@@ -0,0 +1,410 @@
1
+ /*
2
+ Predicates for the Brill tagger
3
+ Copyright (C) 2015 Hugo W.L. ter Doest
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ var log4js = require('log4js');
20
+ var logger = log4js.getLogger();
21
+ logger.setLevel('WARN');
22
+
23
+ var predicates = {
24
+ // Predicates as used in the English rules in data/English/tr_from_posjs.txt
25
+ "NEXT-TAG": next_tag_is,
26
+ "NEXT-WORD-IS-CAP": next_word_is_cap,
27
+ "PREV-1-OR-2-OR-3-TAG": prev_1_or_2_or_3_tag,
28
+ "PREV-1-OR-2-TAG": prev_1_or_2_tag,
29
+ "NEXT-WORD-IS-TAG": next_tag_is,
30
+ "PREV-TAG": prev_tag_is,
31
+ "CURRENT-WORD-IS-TAG": current_word_is_tag,
32
+ "PREV-WORD-IS-CAP": prev_word_is_cap,
33
+ "CURRENT-WORD-IS-CAP": current_word_is_cap,
34
+ "CURRENT-WORD-IS-NUMBER": current_word_is_number,
35
+ "CURRENT-WORD-IS-URL": current_word_is_url,
36
+ "CURRENT-WORD-ENDS-WITH": current_word_ends_with,
37
+ "PREV-WORD-IS": prev_word_is,
38
+ // Predicates as used in the Dutch rules in data/Dutch/brill_CONTEXTRULES.jg
39
+ "PREVTAG": prev_tag_is,
40
+ "NEXT1OR2TAG": next_1_or_2_tag_is,
41
+ "NEXTTAG": next_tag_is,
42
+ "PREV1OR2TAG": prev_1_or_2_tag,
43
+ "WDAND2TAGAFT": current_word_and_2_tag_after_are,
44
+ "NEXT1OR2OR3TAG": next_1_or_2_or_3_tag,
45
+ "CURWD": current_word_is,
46
+ "SURROUNDTAG": surrounded_by_tags,
47
+ "PREV1OR2OR3TAG": prev_1_or_2_or_3_tag,
48
+ "WDNEXTTAG": current_word_and_next_tag_are,
49
+ "PREV1OR2WD": prev_1_or_2_word_is,
50
+ "NEXTWD": next_word_is,
51
+ "PREVWD": prev_word_is,
52
+ "NEXT2TAG": next_2_tag_is,
53
+ "WDAND2TAGBFR": current_word_and_2_tag_before_are,
54
+ "WDAND2AFT": current_word_and_2_after_are,
55
+ "WDPREVTAG": current_word_and_prev_tag_are,
56
+ "RBIGRAM": right_bigram_is,
57
+ "LBIGRAM": left_bigram_is,
58
+ "NEXTBIGRAM": next_bigram_is,
59
+ "PREVBIGRAM": prev_bigram_is,
60
+ "PREV2TAG": prev_2_tag_is,
61
+ "NEXT1OR2WD": next_1_or_2_word_is
62
+ };
63
+
64
+ // ==================================
65
+ // Predicates that start with words
66
+ // ==================================
67
+ function next_word_is_cap(tagged_sentence, i, parameter) {
68
+ if (i < tagged_sentence.length - 1) {
69
+ var next_word = tagged_sentence[i+1][0];
70
+ return(next_word[0] === next_word[0].toUpperCase());
71
+ }
72
+ else {
73
+ return(false);
74
+ }
75
+ }
76
+
77
+ function next_word_is(tagged_sentence, i, parameter) {
78
+ if (i < tagged_sentence.length - 1) {
79
+ return(tagged_sentence[i+1][0] === parameter);
80
+ }
81
+ }
82
+
83
+ function prev_word_is_cap(tagged_sentence, i, parameter) {
84
+ var prev_word = null;
85
+ if (i > 0) {
86
+ prev_word = tagged_sentence[i-1][0];
87
+ return(prev_word[0] === prev_word[0].toUpperCase());
88
+ }
89
+ return(false);
90
+ }
91
+
92
+ function current_word_is_cap(tagged_sentence, i, parameter) {
93
+ var current_word = tagged_sentence[i][0];
94
+ return(current_word[0] === current_word[0].toUpperCase());
95
+ }
96
+
97
+ function current_word_is(tagged_sentence, i, parameter) {
98
+ return(tagged_sentence[i][0] === parameter);
99
+ }
100
+
101
+ function isNumeric(num) {
102
+ return (!isNaN(num));
103
+ }
104
+
105
+ function current_word_is_number(tagged_sentence, i, parameter) {
106
+ var is_number = isNumeric(tagged_sentence[i][0]);
107
+ // Attempt to parse it as a float
108
+ if (!is_number) {
109
+ is_number = parseFloat(tagged_sentence[i][0]);
110
+ }
111
+ return((parameter === "YES") ? is_number : !is_number);
112
+ }
113
+
114
+ // Checks if the current word is a url
115
+ // Adapted from the original Javascript Brill tagger
116
+ function current_word_is_url(tagged_sentence, i, parameter) {
117
+ var is_url = false;
118
+ if (tagged_sentence[i][0].indexOf(".") > -1) {
119
+ // url if there are two contiguous alpha characters
120
+ if (/[a-zA-Z]{2}/.test(tagged_sentence[i][0])) {
121
+ is_url = true;
122
+ }
123
+ }
124
+ return((parameter === "YES") ? is_url : !is_url);
125
+ };
126
+
127
+ function current_word_and_2_tag_after_are(tagged_sentence, i, parameter1, parameter2) {
128
+ if (i < tagged_sentence.length - 2) {
129
+ if (tagged_sentence[i+2][1] === parameter2) {
130
+ return(tagged_sentence[i][0] === parameter1);
131
+ }
132
+ else {
133
+ return(false);
134
+ }
135
+ }
136
+ else {
137
+ return(false);
138
+ }
139
+ }
140
+
141
+ function current_word_and_next_tag_are(tagged_sentence, i, parameter1, parameter2) {
142
+ var next_tag = false;
143
+ // check current word
144
+ var current_word = (tagged_sentence[i][0] === parameter1);
145
+ // check next tag
146
+ if (i < tagged_sentence.length - 1) {
147
+ next_tag = (tagged_sentence[i+1][1] === parameter2);
148
+ }
149
+ return(current_word && next_tag);
150
+ }
151
+
152
+ function current_word_and_prev_tag_are(tagged_sentence, i, parameter1, parameter2) {
153
+ var prev_tag = false;
154
+ // check current word
155
+ var current_word = (tagged_sentence[i][0] === parameter2);
156
+ // check prev tag
157
+ if (i > 0) {
158
+ prev_tag = (tagged_sentence[i-1][1] === parameter1);
159
+ }
160
+ return(current_word && prev_tag);
161
+ }
162
+
163
+ function current_word_and_2_tag_before_are(tagged_sentence, i, parameter1, parameter2) {
164
+ var two_tags_before = false;
165
+ // check current word
166
+ var current_word = (tagged_sentence[i][0] === parameter2);
167
+ if (i > 1) {
168
+ // check two tags before
169
+ two_tags_before = (tagged_sentence[i-2][1] === parameter1);
170
+ }
171
+ return(current_word && two_tags_before);
172
+ }
173
+
174
+ function current_word_and_2_after_are(tagged_sentence, i, parameter1, parameter2) {
175
+ var two_words_after = false;
176
+ // check current word
177
+ var current_word = (tagged_sentence[i][0] === parameter1);
178
+ if (i < tagged_sentence - 2) {
179
+ two_words_after = (tagged_sentence[i+2][0] === parameter2);
180
+ }
181
+ return(current_word && two_words_after);
182
+ }
183
+
184
+ function prev_word_is(tagged_sentence, i, parameter) {
185
+ if (i > 0) {
186
+ return(tagged_sentence[i-1][0].toLowerCase() === parameter.toLowerCase());
187
+ }
188
+ else {
189
+ return(false);
190
+ }
191
+ };
192
+
193
+ function prev_1_or_2_word_is(tagged_sentence, i, parameter) {
194
+ var prev_1 = false;
195
+ var prev_2 = false;
196
+ if (i > 0) {
197
+ prev_1 = (tagged_sentence[i-1][0].toLowerCase() === parameter.toLowerCase());
198
+ }
199
+ if (i > 1) {
200
+ prev_2 = (tagged_sentence[i-2][0].toLowerCase() === parameter.toLowerCase());
201
+ }
202
+ return(prev_1 || prev_2);
203
+ };
204
+
205
+ // Indicates whether or not this string ends with the specified string.
206
+ // Adapted from the original Javascript Brill tagger
207
+ function current_word_ends_with(tagged_sentence, i, parameter) {
208
+ var word = tagged_sentence[i][0];
209
+ if (!parameter || (parameter.length > word.length)) {
210
+ return false;
211
+ }
212
+ return(word.indexOf(parameter) === (word.length - parameter.length));
213
+ }
214
+
215
+ function right_bigram_is(tagged_sentence, i, parameter1, parameter2) {
216
+ var word_1 = (tagged_sentence[i][0] === parameter1);
217
+ var word_2 = false;
218
+ if (i < tagged_sentence.length - 1) {
219
+ word_2 = (tagged_sentence[i+1][0] === parameter2);
220
+ }
221
+ return(word_1 && word_2);
222
+ }
223
+
224
+ function left_bigram_is(tagged_sentence, i, parameter1, parameter2) {
225
+ var word_1 = false;
226
+ var word_2 = (tagged_sentence[i][0] === parameter2);
227
+ if (i > 0) {
228
+ word_1 = (tagged_sentence[i-1][0] === parameter1);
229
+ }
230
+ return(word_1 && word_2);
231
+ }
232
+
233
+ function next_bigram_is(tagged_sentence, i, parameter1, parameter2) {
234
+ var word_1 = false;
235
+ var word_2 = false;
236
+ if (i < tagged_sentence.length - 1) {
237
+ word_1 = (tagged_sentence[i+1][0] === parameter1);
238
+ }
239
+ if (i < tagged_sentence.length - 2) {
240
+ word_2 = (tagged_sentence[i+2][0] === parameter2);
241
+ }
242
+ return(word_1 && word_2);
243
+ }
244
+
245
+ function prev_bigram_is(tagged_sentence, i, parameter1, parameter2) {
246
+ var word_1 = false;
247
+ var word_2 = false;
248
+ if (i > 1) {
249
+ word_1 = (tagged_sentence[i-2][0] === parameter1);
250
+ }
251
+ if (i > 0) {
252
+ word_2 = (tagged_sentence[i-1][0] === parameter2);
253
+ }
254
+ return(word_1 && word_2);
255
+ }
256
+
257
+ function next_1_or_2_word_is(tagged_sentence, i, parameter1, parameter2) {
258
+ next_1 = false;
259
+ next_2 = false;
260
+ if (i < tagged_sentence.length - 1) {
261
+ next_1 = (tagged_sentence[i+1][0] === parameter1);
262
+ }
263
+ if (i < tagged_sentence.length - 2) {
264
+ next_2 = (tagged_sentence[i+2][0] === parameter2);
265
+ }
266
+ return(next_1 || next_2);
267
+ }
268
+
269
+ // ==================================
270
+ // Predicates about tags
271
+ // ==================================
272
+ function next_tag_is(tagged_sentence, i, parameter) {
273
+ if (i < tagged_sentence.length - 1) {
274
+ return(tagged_sentence[i+1][1] === parameter);
275
+ }
276
+ else {
277
+ return(false);
278
+ }
279
+ }
280
+
281
+ function next_2_tag_is(tagged_sentence, i, parameter) {
282
+ if (i < tagged_sentence.length - 2) {
283
+ return(tagged_sentence[i+2][1] === parameter);
284
+ }
285
+ else {
286
+ return(false);
287
+ }
288
+ }
289
+
290
+ function next_1_or_2_tag_is(tagged_sentence, i, parameter) {
291
+ var next_1 = false;
292
+ var next_2 = false;
293
+ if (i < tagged_sentence.length - 1) {
294
+ next_1 = (tagged_sentence[i+1][1] === parameter);
295
+ }
296
+ if (i < tagged_sentence.length - 2) {
297
+ next_2 = (tagged_sentence[i+2][1] === parameter);
298
+ }
299
+ return(next_1 || next_2);
300
+ }
301
+
302
+ function next_1_or_2_or_3_tag(tagged_sentence, i, parameter) {
303
+ var next_1 = false;
304
+ var next_2 = false;
305
+ var next_3 = false;
306
+ if (i < tagged_sentence.length - 1) {
307
+ next_1 = (tagged_sentence[i+1][1] === parameter);
308
+ }
309
+ if (i < tagged_sentence.length - 2) {
310
+ next_2 = (tagged_sentence[i+2][1] === parameter);
311
+ }
312
+ if (i < tagged_sentence.length - 3) {
313
+ next_3 = (tagged_sentence[i+3][1] === parameter);
314
+ }
315
+ return(next_1 || next_2 || next_3);
316
+ }
317
+
318
+ function surrounded_by_tags(tagged_sentence, i, parameter1, parameter2) {
319
+ if (i < tagged_sentence.length - 1) {
320
+ // check next tag
321
+ if (tagged_sentence[i+1][1] === parameter2) {
322
+ // check previous tag
323
+ if (i > 0) {
324
+ return(tagged_sentence[i-1][1] === parameter1)
325
+ }
326
+ else {
327
+ return(false);
328
+ }
329
+ }
330
+ else {
331
+ return(false);
332
+ }
333
+ }
334
+ else {
335
+ return(false);
336
+ }
337
+ }
338
+
339
+ function prev_1_or_2_or_3_tag(tagged_sentence, i, parameter) {
340
+ var prev_1 = null;
341
+ if (i > 0) {
342
+ prev_1 = tagged_sentence[i-1][1];
343
+ }
344
+ var prev_2 = null;
345
+ if (i > 1) {
346
+ prev_2 = tagged_sentence[i-2][1];
347
+ }
348
+ var prev_3 = null;
349
+ if (i > 2) {
350
+ prev_3 = tagged_sentence[i-2][1];
351
+ }
352
+ return((prev_1 === parameter) || (prev_2 === parameter) || (prev_3 === parameter));
353
+ }
354
+
355
+ function prev_1_or_2_tag(tagged_sentence, i, parameter) {
356
+ var prev_1 = null;
357
+ if (i > 0) {
358
+ prev_1 = tagged_sentence[i-1][1];
359
+ }
360
+ var prev_2 = null;
361
+ if (i > 1) {
362
+ prev_2 = tagged_sentence[i-2][1];
363
+ }
364
+ return((prev_1 === parameter) || (prev_2 === parameter));
365
+ }
366
+
367
+ function prev_tag_is(tagged_sentence, i, parameter) {
368
+ var prev = false;
369
+ if (i > 0) {
370
+ prev = (tagged_sentence[i-1][1] === parameter);
371
+ }
372
+ return(prev);
373
+ }
374
+
375
+ function current_word_is_tag(tagged_sentence, i, parameter) {
376
+ return(tagged_sentence[i][0] === parameter);
377
+ }
378
+
379
+ function prev_2_tag_is(tagged_sentence, i, parameter) {
380
+ var prev_2 = false;
381
+ if (i > 1) {
382
+ prev_2 = (tagged_sentence[i-2][1] === parameter);
383
+ }
384
+ return(prev_2);
385
+ }
386
+
387
+ function default_transformation_rule (tagged_sentence, i, parameter) {
388
+ return(false);
389
+ }
390
+
391
+ function Predicate(name, parameter1, parameter2) {
392
+ this.name = name;
393
+ this.parameter1 = parameter1;
394
+ if (parameter2) {
395
+ this.parameter2 = parameter2;
396
+ }
397
+ this.function = predicates[name];
398
+ if (!this.function) {
399
+ this.predicate = default_transformation_rule;
400
+ logger.warn('Predicate constructor: predicate not found: ' + name + '; using default');
401
+ }
402
+ logger.debug(this.name);
403
+ logger.debug(this.function);
404
+ }
405
+
406
+ Predicate.prototype.evaluate = function(tagged_sentence, position) {
407
+ return(this.function(tagged_sentence, position, this.parameter1, this.parameter2));
408
+ };
409
+
410
+ module.exports = Predicate;