natural 7.0.2 → 7.0.3

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.
@@ -25,7 +25,7 @@ THE SOFTWARE.
25
25
  const _ = require('underscore')
26
26
 
27
27
  /*
28
- Sentences Analizer Class
28
+ Sentences Analyzer Class
29
29
  From http://www.writingcentre.uottawa.ca/hypergrammar/sntpurps.html
30
30
 
31
31
  Take a POS input and analyse it for
@@ -44,148 +44,150 @@ const _ = require('underscore')
44
44
  - Show Preposition Phrases
45
45
  */
46
46
 
47
- const Sentences = function (pos, callbackFunction) {
48
- this.posObj = pos
49
- this.senType = null
50
- callbackFunction(this)
51
- }
47
+ class SentenceAnalyzer {
48
+ constructor (pos, callbackFunction) {
49
+ this.posObj = pos
50
+ this.senType = null
51
+ callbackFunction(this)
52
+ }
52
53
 
53
- Sentences.prototype.part = function (callbackFunction) {
54
- const subject = []
55
- const predicat = []
56
- let verbFound = false
54
+ part (callbackFunction) {
55
+ const subject = []
56
+ const predicat = []
57
+ let verbFound = false
57
58
 
58
- this.prepositionPhrases()
59
+ this.prepositionPhrases()
59
60
 
60
- for (let i = 0; i < this.posObj.tags.length; i++) {
61
- if (this.posObj.tags[i].pos === 'VB') {
62
- if (i === 0) {
63
- verbFound = true
64
- } else {
65
- // We need to Test for any EX before the VB
66
- if (this.posObj.tags[i - 1].pos !== 'EX') {
61
+ for (let i = 0; i < this.posObj.tags.length; i++) {
62
+ if (this.posObj.tags[i].pos === 'VB') {
63
+ if (i === 0) {
67
64
  verbFound = true
68
65
  } else {
69
- predicat.push(this.posObj.tags[i].token)
66
+ // We need to Test for any EX before the VB
67
+ if (this.posObj.tags[i - 1].pos !== 'EX') {
68
+ verbFound = true
69
+ } else {
70
+ predicat.push(this.posObj.tags[i].token)
71
+ }
70
72
  }
71
73
  }
72
- }
73
74
 
74
- // Add Pronoun Phrase (pp) Or Subject Phrase (sp)
75
- if (!verbFound) {
76
- if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'SP' }
75
+ // Add Pronoun Phrase (pp) Or Subject Phrase (sp)
76
+ if (!verbFound) {
77
+ if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'SP' }
77
78
 
78
- subject.push(this.posObj.tags[i].token)
79
- } else {
80
- if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'PP' }
79
+ subject.push(this.posObj.tags[i].token)
80
+ } else {
81
+ if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'PP' }
81
82
 
82
- predicat.push(this.posObj.tags[i].token)
83
+ predicat.push(this.posObj.tags[i].token)
84
+ }
83
85
  }
84
- }
85
86
 
86
- if (subject.length === 0) {
87
- this.posObj.tags.push({ token: 'You', spos: 'SP', pos: 'PRP', added: true })
88
- }
87
+ if (subject.length === 0) {
88
+ this.posObj.tags.push({ token: 'You', spos: 'SP', pos: 'PRP', added: true })
89
+ }
89
90
 
90
- callbackFunction(this)
91
- }
91
+ callbackFunction(this)
92
+ }
92
93
 
93
- // Takes POS and removes IN to NN or NNS
94
- // Adds a PP for each prepositionPhrases
95
- Sentences.prototype.prepositionPhrases = function () {
96
- let remove = false
94
+ // Takes POS and removes IN to NN or NNS
95
+ // Adds a PP for each prepositionPhrases
96
+ prepositionPhrases () {
97
+ let remove = false
97
98
 
98
- for (let i = 0; i < this.posObj.tags.length; i++) {
99
- if (this.posObj.tags[i].pos.match('IN')) {
100
- remove = true
101
- }
99
+ for (let i = 0; i < this.posObj.tags.length; i++) {
100
+ if (this.posObj.tags[i].pos.match('IN')) {
101
+ remove = true
102
+ }
102
103
 
103
- if (remove) {
104
- this.posObj.tags[i].pp = true
105
- }
104
+ if (remove) {
105
+ this.posObj.tags[i].pp = true
106
+ }
106
107
 
107
- if (this.posObj.tags[i].pos.match('NN')) {
108
- remove = false
108
+ if (this.posObj.tags[i].pos.match('NN')) {
109
+ remove = false
110
+ }
109
111
  }
110
112
  }
111
- }
112
113
 
113
- Sentences.prototype.subjectToString = function () {
114
- return this.posObj.tags.map(function (t) {
115
- if (t.spos === 'SP' || t.spos === 'S') {
116
- return t.token
117
- } else return null
118
- }).join(' ')
119
- }
114
+ subjectToString () {
115
+ return this.posObj.tags.map(function (t) {
116
+ if (t.spos === 'SP' || t.spos === 'S') {
117
+ return t.token
118
+ } else return null
119
+ }).join(' ')
120
+ }
120
121
 
121
- Sentences.prototype.predicateToString = function () {
122
- return this.posObj.tags.map(function (t) {
123
- if (t.spos === 'PP' || t.spos === 'P') {
124
- return t.token
125
- } else return null
126
- }).join(' ')
127
- }
122
+ predicateToString () {
123
+ return this.posObj.tags.map(function (t) {
124
+ if (t.spos === 'PP' || t.spos === 'P') {
125
+ return t.token
126
+ } else return null
127
+ }).join(' ')
128
+ }
128
129
 
129
- Sentences.prototype.implicitYou = function () {
130
- for (let i = 0; i < this.posObj.tags.length; i++) {
131
- if (this.posObj.tags[i].added) {
132
- return true
130
+ implicitYou () {
131
+ for (let i = 0; i < this.posObj.tags.length; i++) {
132
+ if (this.posObj.tags[i].added) {
133
+ return true
134
+ }
133
135
  }
136
+
137
+ return false
134
138
  }
135
139
 
136
- return false
137
- }
140
+ toString () {
141
+ return this.posObj.tags.map(function (t) { return t.token }).join(' ')
142
+ }
138
143
 
139
- Sentences.prototype.toString = function () {
140
- return this.posObj.tags.map(function (t) { return t.token }).join(' ')
141
- }
144
+ // This is quick and incomplete.
145
+ type (cbf) {
146
+ const callbackFunction = cbf || false
142
147
 
143
- // This is quick and incomplete.
144
- Sentences.prototype.type = function (cbf) {
145
- const callbackFunction = cbf || false
146
-
147
- // Check for implicit you before popping a tag.
148
- const implicitYou = this.implicitYou()
149
-
150
- // FIXME - punct seems useless
151
- let lastElement = this.posObj.punct()
152
- // console.log(lastElement)
153
- lastElement = (lastElement.length !== 0) ? lastElement.pop() : this.posObj.tags.pop()
154
- // console.log(lastElement)
155
-
156
- if (lastElement.pos !== '.') {
157
- if (implicitYou) {
158
- this.senType = 'COMMAND'
159
- } else if (_.contains(['WDT', 'WP', 'WP$', 'WRB'], this.posObj.tags[0].pos)) {
160
- // Sentences that start with: who, what where when why and how, then they are questions
161
- this.senType = 'INTERROGATIVE'
162
- } else if (_.contains(['PRP'], lastElement.pos)) {
163
- // Sentences that end in a Personal pronoun are most likely questions
164
- // eg. We should run away, should we [?]
165
- // eg. You want to see that again, do you [?]
166
- this.senType = 'INTERROGATIVE'
167
- } else {
168
- this.senType = 'UNKNOWN'
169
- }
170
- } else {
171
- switch (lastElement.token) {
172
- case '?':
148
+ // Check for implicit you before popping a tag.
149
+ const implicitYou = this.implicitYou()
150
+
151
+ // FIXME - punct seems useless
152
+ let lastElement = this.posObj.punct()
153
+ // console.log(lastElement)
154
+ lastElement = (lastElement.length !== 0) ? lastElement.pop() : this.posObj.tags.pop()
155
+ // console.log(lastElement)
156
+
157
+ if (lastElement.pos !== '.') {
158
+ if (implicitYou) {
159
+ this.senType = 'COMMAND'
160
+ } else if (_.contains(['WDT', 'WP', 'WP$', 'WRB'], this.posObj.tags[0].pos)) {
161
+ // Sentences that start with: who, what where when why and how, then they are questions
162
+ this.senType = 'INTERROGATIVE'
163
+ } else if (_.contains(['PRP'], lastElement.pos)) {
164
+ // Sentences that end in a Personal pronoun are most likely questions
165
+ // eg. We should run away, should we [?]
166
+ // eg. You want to see that again, do you [?]
173
167
  this.senType = 'INTERROGATIVE'
174
- break
175
- case '!':
176
- this.senType = (implicitYou) ? 'COMMAND' : 'EXCLAMATORY'
177
- break
178
- case '.':
179
- this.senType = (implicitYou) ? 'COMMAND' : 'DECLARATIVE'
180
- break
168
+ } else {
169
+ this.senType = 'UNKNOWN'
170
+ }
171
+ } else {
172
+ switch (lastElement.token) {
173
+ case '?':
174
+ this.senType = 'INTERROGATIVE'
175
+ break
176
+ case '!':
177
+ this.senType = (implicitYou) ? 'COMMAND' : 'EXCLAMATORY'
178
+ break
179
+ case '.':
180
+ this.senType = (implicitYou) ? 'COMMAND' : 'DECLARATIVE'
181
+ break
182
+ }
181
183
  }
182
- }
183
184
 
184
- if (callbackFunction && _.isFunction(callbackFunction)) {
185
- callbackFunction(this)
186
- } else {
187
- return this.senType
185
+ if (callbackFunction && _.isFunction(callbackFunction)) {
186
+ callbackFunction(this)
187
+ } else {
188
+ return this.senType
189
+ }
188
190
  }
189
191
  }
190
192
 
191
- module.exports = Sentences
193
+ module.exports = SentenceAnalyzer
@@ -27,79 +27,81 @@ const Trie = require('../trie/trie')
27
27
  // Words that are an edit distance of n away from the mispelled word are considered infinitely more probable than words that are of an edit distance >n
28
28
 
29
29
  // wordlist is a corpus (an array) from which word probabilities are calculated (so something like /usr/share/dict/words (on OSX) will work okay, but real world text will work better)
30
- function Spellcheck (wordlist) {
31
- this.trie = new Trie()
32
- this.trie.addStrings(wordlist)
33
- this.word2frequency = {}
34
- for (const i in wordlist) {
35
- if (!this.word2frequency[wordlist[i]]) {
36
- this.word2frequency[wordlist[i]] = 0
30
+ class Spellcheck {
31
+ constructor (wordlist) {
32
+ this.trie = new Trie()
33
+ this.trie.addStrings(wordlist)
34
+ this.word2frequency = {}
35
+ for (const i in wordlist) {
36
+ if (!this.word2frequency[wordlist[i]]) {
37
+ this.word2frequency[wordlist[i]] = 0
38
+ }
39
+ this.word2frequency[wordlist[i]]++
37
40
  }
38
- this.word2frequency[wordlist[i]]++
39
41
  }
40
- }
41
42
 
42
- Spellcheck.prototype.isCorrect = function (word) {
43
- return this.trie.contains(word)
44
- }
43
+ isCorrect (word) {
44
+ return this.trie.contains(word)
45
+ }
45
46
 
46
- // Returns a list of suggested corrections, from highest to lowest probability
47
- // maxDistance is the maximum edit distance
48
- // According to Norvig, literature suggests that 80% to 95% of spelling errors are an edit distance of 1 away from the correct word. This is good, because there are roughly 54n+25 strings 1 edit distance away from any given string of length n. So after maxDistance = 2, this becomes very slow.
49
- Spellcheck.prototype.getCorrections = function (word, maxDistance) {
50
- const self = this
51
- if (!maxDistance) maxDistance = 1
52
- let edits = this.editsWithMaxDistance(word, maxDistance)
53
- edits = edits.slice(1, edits.length)
54
- edits = edits.map(function (editList) {
55
- return editList.filter(function (word) { return self.isCorrect(word) })
56
- .map(function (word) { return [word, self.word2frequency[word]] })
57
- .sort(function (a, b) { return a[1] > b[1] ? -1 : 1 })
58
- .map(function (wordscore) { return wordscore[0] })
59
- })
60
- let flattened = []
61
- for (const i in edits) {
62
- if (edits[i].length) {
63
- flattened = flattened.concat(edits[i])
47
+ // Returns a list of suggested corrections, from highest to lowest probability
48
+ // maxDistance is the maximum edit distance
49
+ // According to Norvig, literature suggests that 80% to 95% of spelling errors are an edit distance of 1 away from the correct word. This is good, because there are roughly 54n+25 strings 1 edit distance away from any given string of length n. So after maxDistance = 2, this becomes very slow.
50
+ getCorrections (word, maxDistance) {
51
+ const self = this
52
+ if (!maxDistance) maxDistance = 1
53
+ let edits = this.editsWithMaxDistance(word, maxDistance)
54
+ edits = edits.slice(1, edits.length)
55
+ edits = edits.map(function (editList) {
56
+ return editList.filter(function (word) { return self.isCorrect(word) })
57
+ .map(function (word) { return [word, self.word2frequency[word]] })
58
+ .sort(function (a, b) { return a[1] > b[1] ? -1 : 1 })
59
+ .map(function (wordscore) { return wordscore[0] })
60
+ })
61
+ let flattened = []
62
+ for (const i in edits) {
63
+ if (edits[i].length) {
64
+ flattened = flattened.concat(edits[i])
65
+ }
64
66
  }
67
+ return flattened.filter(function (v, i, a) {
68
+ return a.indexOf(v) === i
69
+ })
65
70
  }
66
- return flattened.filter(function (v, i, a) {
67
- return a.indexOf(v) === i
68
- })
69
- }
70
71
 
71
- // Returns all edits that are 1 edit-distance away from the input word
72
- Spellcheck.prototype.edits = function (word) {
73
- const alphabet = 'abcdefghijklmnopqrstuvwxyz'
74
- let edits = []
75
- for (let i = 0; i < word.length + 1; i++) {
76
- if (i > 0) edits.push(word.slice(0, i - 1) + word.slice(i, word.length)) // deletes
77
- if (i > 0 && i < word.length + 1) edits.push(word.slice(0, i - 1) + word.slice(i, i + 1) + word.slice(i - 1, i) + word.slice(i + 1, word.length)) // transposes
78
- for (let k = 0; k < alphabet.length; k++) {
79
- if (i > 0) edits.push(word.slice(0, i - 1) + alphabet[k] + word.slice(i, word.length)) // replaces
80
- edits.push(word.slice(0, i) + alphabet[k] + word.slice(i, word.length)) // inserts
72
+ // Returns all edits that are 1 edit-distance away from the input word
73
+ edits (word) {
74
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz'
75
+ let edits = []
76
+ for (let i = 0; i < word.length + 1; i++) {
77
+ if (i > 0) edits.push(word.slice(0, i - 1) + word.slice(i, word.length)) // deletes
78
+ if (i > 0 && i < word.length + 1) edits.push(word.slice(0, i - 1) + word.slice(i, i + 1) + word.slice(i - 1, i) + word.slice(i + 1, word.length)) // transposes
79
+ for (let k = 0; k < alphabet.length; k++) {
80
+ if (i > 0) edits.push(word.slice(0, i - 1) + alphabet[k] + word.slice(i, word.length)) // replaces
81
+ edits.push(word.slice(0, i) + alphabet[k] + word.slice(i, word.length)) // inserts
82
+ }
81
83
  }
84
+ // Deduplicate edits
85
+ edits = edits.filter(function (v, i, a) { return a.indexOf(v) === i })
86
+ return edits
82
87
  }
83
- // Deduplicate edits
84
- edits = edits.filter(function (v, i, a) { return a.indexOf(v) === i })
85
- return edits
86
- }
87
88
 
88
- // Returns all edits that are up to "distance" edit distance away from the input word
89
- Spellcheck.prototype.editsWithMaxDistance = function (word, distance) {
90
- return this.editsWithMaxDistanceHelper(distance, [[word]])
91
- }
89
+ // Returns all edits that are up to "distance" edit distance away from the input word
90
+ editsWithMaxDistance (word, distance) {
91
+ return this.editsWithMaxDistanceHelper(distance, [[word]])
92
+ }
92
93
 
93
- Spellcheck.prototype.editsWithMaxDistanceHelper = function (distanceCounter, distance2edits) {
94
- if (distanceCounter === 0) return distance2edits
95
- const currentDepth = distance2edits.length - 1
96
- const words = distance2edits[currentDepth]
97
- // const edits = this.edits(words[0])
98
- distance2edits[currentDepth + 1] = []
99
- for (const i in words) {
100
- distance2edits[currentDepth + 1] = distance2edits[currentDepth + 1].concat(this.edits(words[i]))
94
+ editsWithMaxDistanceHelper (distanceCounter, distance2edits) {
95
+ if (distanceCounter === 0) return distance2edits
96
+ const currentDepth = distance2edits.length - 1
97
+ const words = distance2edits[currentDepth]
98
+ // const edits = this.edits(words[0])
99
+ distance2edits[currentDepth + 1] = []
100
+ for (const i in words) {
101
+ distance2edits[currentDepth + 1] = distance2edits[currentDepth + 1].concat(this.edits(words[i]))
102
+ }
103
+ return this.editsWithMaxDistanceHelper(distanceCounter - 1, distance2edits)
101
104
  }
102
- return this.editsWithMaxDistanceHelper(distanceCounter - 1, distance2edits)
103
105
  }
104
106
 
105
107
  module.exports = Spellcheck
@@ -22,31 +22,33 @@ THE SOFTWARE.
22
22
 
23
23
  'use strict'
24
24
 
25
- function Bag () {
26
- this.dictionary = []
27
- this.nElement = 0
28
- };
29
-
30
- Bag.prototype.add = function (element) {
31
- this.dictionary.push(element)
32
- this.nElement++
33
- return this
34
- }
35
-
36
- Bag.prototype.isEmpty = function () {
37
- return this.nElement > 0
38
- }
39
-
40
- Bag.prototype.contains = function (item) {
41
- return this.dictionary.indexOf(item) >= 0
42
- }
43
-
44
- /**
45
- * unpack the bag , and get all items
46
- */
47
- Bag.prototype.unpack = function () {
48
- // return a copy is better than original
49
- return this.dictionary.slice()
25
+ class Bag {
26
+ constructor () {
27
+ this.dictionary = []
28
+ this.nElement = 0
29
+ }
30
+
31
+ add (element) {
32
+ this.dictionary.push(element)
33
+ this.nElement++
34
+ return this
35
+ }
36
+
37
+ isEmpty () {
38
+ return this.nElement > 0
39
+ }
40
+
41
+ contains (item) {
42
+ return this.dictionary.indexOf(item) >= 0
43
+ }
44
+
45
+ /**
46
+ * unpack the bag , and get all items
47
+ */
48
+ unpack () {
49
+ // return a copy is better than original
50
+ return this.dictionary.slice()
51
+ }
50
52
  }
51
53
 
52
54
  module.exports = Bag
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "natural",
3
3
  "description": "General natural language (tokenizing, stemming (English, Russian, Spanish), part-of-speech tagging, sentiment analysis, classification, inflection, phonetics, tfidf, WordNet, jaro-winkler, Levenshtein distance, Dice's Coefficient) facilities for node.",
4
- "version": "7.0.2",
4
+ "version": "7.0.3",
5
5
  "homepage": "https://github.com/NaturalNode/natural",
6
6
  "repository": {
7
7
  "type": "git",