diff --git a/README.md b/README.md index 76f0273..f822b62 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,8 @@ const count = stringzy.analyze.wordCount('Hello world'); // 2 ### Analysis - [wordCount](#wordcount) - Counts the number of words in a string +- [contentWordCount](#contentwordcount)- Counts the number of content words (nouns, verbs, adjectives, adverbs, etc.) in a string. +- [functionWordCount](#functionwordcount)- Counts the number of function words (prepositions, pronouns, conjunctions, articles, etc.) in a string. - [readingDuration](#readingduration) - Calculates the reading duration of a given string - [characterCount](#charactercount) - Counts the number of characters in a string - [characterFrequency](#characterfrequency) - Analyzes character frequency in a string @@ -871,6 +873,64 @@ complexity(''); - `uniqueness` (number): Measure of character uniqueness - `length` (number): Length of the input string +feature/content-words + +#### contentWordCount(text) + +Counts the number of content words (nouns, verbs, adjectives, adverbs, etc.) in a string. + +```javascript + +import { contentWordCount } from 'stringzy'; + +contentWordCount("Learning JavaScript improves coding skills!"); +// Returns: { count: 5 } + +contentWordCount("The cat sleeps on the warm windowsill."); +// Returns: { count: 5 } + +contentWordCount("Wow! Such a beautiful day."); +// Returns: { count: 4 } +``` + +| Parameter | Type | Default | Description | +| --------- | ------ | -------- | -------------------------------------- | +| text | string | required | The input string to analyze content words | + +**Returns:** An object containing: + +- `count` (number): Total number of content words in the string + + +#### functionWordCount(text) + +Counts the number of function words (prepositions, pronouns, conjunctions, articles, etc.) in a string. + +```javascript + +import { functionWordCount } from 'stringzy'; + +functionWordCount("She and I are going to the park."); +// Returns: { count: 7 } + +functionWordCount("It is an example of proper grammar usage."); +// Returns: { count: 8 } + +functionWordCount("Can you see the stars tonight?"); +// Returns: { count: 5 } +``` + +| Parameter | Type | Default | Description | +| --------- | ------ | -------- | -------------------------------------- | +| text | string | required | The input string to analyze function words | + +**Returns:** An object containing: + +- `count` (number): Total number of function words in the string + + + + #### `patternCount(text, pattern)` Counts the number of times a substring (pattern) occurs in a string, including overlapping occurrences. @@ -908,6 +968,8 @@ vowelConsonantCount(''); | --------- | ------ | -------- | -------------------------------------------------- | | str | string | required | The input string to count vowels and consonants in | +feature/content-words + #### checkMultiplePatterns(text, patterns) Finds occurrences of multiple patterns within a given text using the Rabin–Karp algorithm.
@@ -931,6 +993,7 @@ checkMultiplePatterns('hello world', ['xyz', '123']); | text | string | required | The text to search within. | | patterns | string\[ ] | required | An array of patterns to search for (each must be a string). | + --- ### 🎨 Formatting diff --git a/package-lock.json b/package-lock.json index 159a654..3bb9a0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "stringzy", "version": "4.0.0", "license": "MIT", + "dependencies": { + "stringzy": "^3.0.0" + }, "devDependencies": { "@types/node": "^24.5.2", "prettier": "^3.6.2", @@ -40,6 +43,12 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/stringzy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stringzy/-/stringzy-3.0.0.tgz", + "integrity": "sha512-bq5FuxrWouAUwIOKTS7mKdRgBxH3mo5RXGmWknWCaH5IXJdTHxuCgnh41u5sgMeScQGXE1RzRXN3NIRt6jW6JQ==", + "license": "MIT" + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", diff --git a/package.json b/package.json index 6888631..4b30c36 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "types": "dist/index.d.ts", "scripts": { "build": "tsc", - "test": "npm run build && node --test", + "test": " npm run build && node --test", "prepublishOnly": "npm run build", "format": "prettier --write ." }, diff --git a/src/analyzing/contentWordCount.ts b/src/analyzing/contentWordCount.ts new file mode 100644 index 0000000..3c3af11 --- /dev/null +++ b/src/analyzing/contentWordCount.ts @@ -0,0 +1,23 @@ +import { functionWordCount } from './functionWordCount'; +import { wordCount } from './wordCount'; + +/** + * Counts the number of content words in a given text. + * + * Content words are words that carry lexical meaning (nouns, verbs, adjectives, adverbs), + * excluding function words such as prepositions, pronouns, and articles. + * + * @param {string} text - The text to analyze. + * @returns {number} The count of content words in the text. + * @throws {TypeError} If the input is not a string. + */ +export function contentWordCount(text: string): number { + if (typeof text !== 'string') { + throw new TypeError('Input must be a string'); + } + + const totalWords = wordCount(text); + const functionWords = functionWordCount(text); + + return totalWords - functionWords; +} diff --git a/src/analyzing/functionWordCount.ts b/src/analyzing/functionWordCount.ts new file mode 100644 index 0000000..de0e383 --- /dev/null +++ b/src/analyzing/functionWordCount.ts @@ -0,0 +1,34 @@ +/** + * Counts the number of function words in a given text. + * + * Function words are common words (e.g., prepositions, pronouns, conjunctions, articles, etc.) + * that carry grammatical meaning rather than lexical meaning. + * + * @param {string} text - The text to analyze. + * @returns {number} The count of function words in the text. + * @throws {TypeError} If the input is not a string. + */ +export function functionWordCount(text: string): number { + if (typeof text !== 'string') { + throw new TypeError('Input must be a string'); + } + + const functionWords = new Set([ + 'a', 'an', 'the', 'and', 'but', 'or', 'nor', 'so', 'yet', + 'for', 'of', 'in', 'on', 'at', 'by', 'to', 'from', 'with', 'about', + 'as', 'into', 'like', 'through', 'after', 'over', 'between', 'out', + 'against', 'during', 'without', 'before', 'under', 'around', 'among', + 'is', 'am', 'are', 'was', 'were', 'be', 'been', 'being', + 'he', 'she', 'it', 'they', 'we', 'you', 'i', 'me', 'him', 'her', + 'them', 'us', 'my', 'your', 'his', 'their', 'our', + 'this', 'that', 'these', 'those', + 'who', 'whom', 'which', 'what', 'when', 'where', 'why', 'how' + ]); + + // ✅ Normalize text: lowercase + remove punctuation + const cleanedText = text.toLowerCase().replace(/[^\w\s]/g, ''); + + const words = cleanedText.trim().split(/\s+/); + + return words.filter(word => functionWords.has(word)).length; +} diff --git a/src/analyzing/index.ts b/src/analyzing/index.ts index 3c2de40..4ed49d5 100644 --- a/src/analyzing/index.ts +++ b/src/analyzing/index.ts @@ -8,6 +8,10 @@ export { patternCount } from './patternCount'; export { vowelConsonantCount } from './vowelConsonantCount'; export { checkMultiplePatterns } from './checkMultiplePatterns'; +export { functionWordCount } from './functionWordCount'; +export { contentWordCount } from './contentWordCount'; + + import { characterCount } from './characterCount'; import { characterFrequency } from './characterFrequency'; import { complexity } from './complexity'; @@ -18,6 +22,8 @@ import { patternCount } from './patternCount'; import { vowelConsonantCount } from './vowelConsonantCount'; import { checkMultiplePatterns } from './checkMultiplePatterns'; + + export const analyzing = { characterCount, characterFrequency, diff --git a/src/tests/analyzing/contentWordCount.test.ts b/src/tests/analyzing/contentWordCount.test.ts new file mode 100644 index 0000000..621b051 --- /dev/null +++ b/src/tests/analyzing/contentWordCount.test.ts @@ -0,0 +1,19 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { contentWordCount } from "../../analyzing/contentWordCount.js"; + +test("counts content words in a normal sentence", () => { + assert.equal(contentWordCount("This is a test of the system"), 2); +}); + +test("returns 0 when there are no content words", () => { + assert.equal(contentWordCount("is the at of"), 0); +}); + +test("ignores case and punctuation", () => { + assert.equal(contentWordCount("Elephants, ELEPHANTS, elephants!"), 3); +}); + +test("returns 0 for empty string", () => { + assert.equal(contentWordCount(""), 0); +}); diff --git a/src/tests/analyzing/functionWordCount.test.ts b/src/tests/analyzing/functionWordCount.test.ts new file mode 100644 index 0000000..ee69264 --- /dev/null +++ b/src/tests/analyzing/functionWordCount.test.ts @@ -0,0 +1,19 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { functionWordCount } from "../../analyzing/functionWordCount.js"; + +test("counts function words in a normal sentence", () => { + assert.equal(functionWordCount("This is a test of the system"), 5); +}); + +test("returns 0 when there are no function words", () => { + assert.equal(functionWordCount("Elephants run fast"), 0); +}); + +test("ignores case and punctuation", () => { + assert.equal(functionWordCount("The, THE, the!"), 3); +}); + +test("returns 0 for empty string", () => { + assert.equal(functionWordCount(""), 0); +});