{"id":13426523,"url":"https://github.com/spencermountain/compromise","last_synced_at":"2025-12-12T03:43:28.916Z","repository":{"id":37733482,"uuid":"1999522","full_name":"spencermountain/compromise","owner":"spencermountain","description":"modest natural-language processing","archived":false,"fork":false,"pushed_at":"2025-04-26T18:19:39.000Z","size":58495,"stargazers_count":11712,"open_issues_count":114,"forks_count":656,"subscribers_count":161,"default_branch":"master","last_synced_at":"2025-05-05T20:27:37.051Z","etag":null,"topics":["named-entity-recognition","nlp","part-of-speech"],"latest_commit_sha":null,"homepage":"http://compromise.cool","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spencermountain.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2011-07-05T09:04:38.000Z","updated_at":"2025-05-05T18:06:10.000Z","dependencies_parsed_at":"2023-07-19T09:01:18.136Z","dependency_job_id":"7fcfcc70-5008-45d1-9d4b-0eb61cddc92e","html_url":"https://github.com/spencermountain/compromise","commit_stats":{"total_commits":5654,"total_committers":122,"mean_commits":46.34426229508197,"dds":0.07994340290060131,"last_synced_commit":"634de9ffea4d720878245a4846b2e403cf91b0df"},"previous_names":["spencermountain/nlp_compromise","nlp-compromise/nlp_compromise","nlp-compromise/compromise"],"tags_count":250,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spencermountain%2Fcompromise","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spencermountain%2Fcompromise/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spencermountain%2Fcompromise/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spencermountain%2Fcompromise/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spencermountain","download_url":"https://codeload.github.com/spencermountain/compromise/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252570211,"owners_count":21769607,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["named-entity-recognition","nlp","part-of-speech"],"created_at":"2024-07-31T00:01:36.918Z","updated_at":"2025-12-12T03:43:28.873Z","avatar_url":"https://github.com/spencermountain.png","language":"JavaScript","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"15px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n  \u003cdiv\u003e\u003cb\u003ecompromise\u003c/b\u003e\u003c/div\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/399657/68222691-6597f180-ffb9-11e9-8a32-a7f38aa8bded.png\"/\u003e\n  \u003cdiv\u003emodest natural language processing\u003c/div\u003e\n  \u003cdiv\u003e\u003ccode\u003enpm install compromise\u003c/code\u003e\u003c/div\u003e\n  \u003cdiv align=\"center\"\u003e\n    \u003csub\u003e\n      by\n      \u003ca href=\"https://spencermounta.in/\"\u003eSpencer Kelly\u003c/a\u003e and\n      \u003ca href=\"https://github.com/spencermountain/compromise/graphs/contributors\"\u003e\n        many contributors\n      \u003c/a\u003e\n    \u003c/sub\u003e\n  \u003c/div\u003e\n  \u003cimg height=\"22px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cdiv\u003e\n    \u003ca href=\"https://npmjs.org/package/compromise\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/compromise.svg?style=flat-square\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/spencermountain/compromise\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/spencermountain/compromise/branch/master/graph/badge.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=compromise\"\u003e\n    \u003cimg src=\"https://img.shields.io/bundlephobia/min/compromise\"/\u003e\n    \u003c!-- \u003cimg src=\"https://badge-size.herokuapp.com/spencermountain/compromise/master/builds/compromise.min.js\" /\u003e --\u003e\n  \u003c/a\u003e\n  \u003c/div\u003e\n  \u003cdiv align=\"center\"\u003e\n    \u003csub\u003e\n     \u003ca href=\"https://github.com/nlp-compromise/fr-compromise\"\u003efrench\u003c/a\u003e • \u003ca href=\"https://github.com/nlp-compromise/de-compromise\"\u003egerman\u003c/a\u003e  • \u003ca href=\"https://github.com/nlp-compromise/it-compromise\"\u003eitalian\u003c/a\u003e • \u003ca href=\"https://github.com/nlp-compromise/es-compromise\"\u003espanish\u003c/a\u003e\n    \u003c/sub\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003cdiv align=\"left\"\u003e\ndon't you find it strange,\n\u003cbr/\u003e\n\u003cul\u003e\n  \u003cimg height=\"2px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n  \u003csub\u003ehow easy \u003cb\u003etext\u003c/b\u003e is to \u003cb\u003emake\u003c/b\u003e,\u003c/sub\u003e\n  \u003cbr/\u003e\n  \u003cimg height=\"2px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u0026nbsp;\u003ci\u003e↬\u003csub\u003eᔐᖜ\u003c/sub\u003e\u003cb\u003e↬\u003c/b\u003e\u003c/i\u003e \u0026nbsp; \u003csub\u003e\u003c/sub\u003e\nand how hard it is to actually \u003cb\u003eparse\u003c/b\u003e and \u003ci\u003euse\u003c/i\u003e?\n\n\u003c/ul\u003e\n\u003c/div\u003e\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"45px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003cdiv align=\"left\"\u003e\n  \u003cimg height=\"10px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003ecompromise \u003ci\u003e\u003ca href=\"https://observablehq.com/@spencermountain/compromise-justification\"\u003etries its best\u003c/a\u003e\u003c/i\u003e to turn text into data.\n  \u003cbr/\u003e\n  \u003cimg height=\"30px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003eit makes limited and sensible decisions.\n  \u003cbr/\u003e\n  \u003csub \u003e\n   \u003cimg height=\"15px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e it's not as smart as you'd think.\n  \u003c/sub\u003e\n\n\u003cimg height=\"45px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n \u003c!--\n  it is\n  \u003ca href=\"https://docs.compromise.cool/compromise-filesize\"\u003esmall,\n  \u003ca href=\"https://docs.compromise.cool/compromise-performance\"\u003equick\u003c/a\u003e,\n  and often \u003ci\u003e\u003ca href=\"https://docs.compromise.cool/compromise-accuracy\"\u003egood-enough\u003c/a\u003e\u003c/i\u003e.\n  \u003cbr/\u003e --\u003e\n\u003c/div\u003e\n\u003cimg height=\"30px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n```js\nimport nlp from 'compromise'\n\nlet doc = nlp('she sells seashells by the seashore.')\ndoc.verbs().toPastTense()\ndoc.text()\n// 'she sold seashells by the seashore.'\n```\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003cdiv align=\"left\"\u003e\n\u003ci\u003edon't be fancy, at all:\u003c/i\u003e\n\u003c/div\u003e\n\n```js\nif (doc.has('simon says #Verb')) {\n  return true\n}\n```\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png\"/\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"left\"\u003e\n\u003ci\u003egrab parts of the text:\u003c/i\u003e\n\u003c/div\u003e\n\n```js\nlet doc = nlp(entireNovel)\ndoc.match('the #Adjective of times').text()\n// \"the blurst of times?\"\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-match\"\u003ematch docs\u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221837-0d142480-ffb8-11e9-9d30-90669f1b897c.png\"/\u003e\n\u003c/div\u003e\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003ci\u003eand get data:\u003c/i\u003e\n\n```js\nimport plg from 'compromise-speech'\nnlp.extend(plg)\n\nlet doc = nlp('Milwaukee has certainly had its share of visitors..')\ndoc.compute('syllables')\ndoc.places().json()\n/*\n[{\n  \"text\": \"Milwaukee\",\n  \"terms\": [{\n    \"normal\": \"milwaukee\",\n    \"syllables\": [\"mil\", \"wau\", \"kee\"]\n  }]\n}]\n*/\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-json\"\u003ejson docs\u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png\"/\u003e\n\u003c/div\u003e\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\navoid the problems of brittle parsers:\n\n```js\nlet doc = nlp(\"we're not gonna take it..\")\n\ndoc.has('gonna') // true\ndoc.has('going to') // true (implicit)\n\n// transform\ndoc.contractions().expand()\ndoc.text()\n// 'we are not going to take it..'\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-contractions\"\u003econtraction docs\u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png\"/\u003e\n\u003c/div\u003e\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\nand whip stuff around like it's data:\n\n```js\nlet doc = nlp('ninety five thousand and fifty two')\ndoc.numbers().add(20)\ndoc.text()\n// 'ninety five thousand and seventy two'\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-values\"\u003enumber docs\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221837-0d142480-ffb8-11e9-9d30-90669f1b897c.png\"/\u003e\n\u003c/div\u003e\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003csub\u003e-because it actually is-\u003c/sub\u003e\n\n```js\nlet doc = nlp('the purple dinosaur')\ndoc.nouns().toPlural()\ndoc.text()\n// 'the purple dinosaurs'\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/nouns\"\u003enoun docs\u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221731-e8b84800-ffb7-11e9-8453-6395e0e903fa.png\"/\u003e\n\u003c/div\u003e\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\nUse it on the client-side:\n\n```html\n\u003cscript src=\"https://unpkg.com/compromise\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  var doc = nlp('two bottles of beer')\n  doc.numbers().minus(1)\n  document.body.innerHTML = doc.text()\n  // 'one bottle of beer'\n\u003c/script\u003e\n```\n\nor likewise:\n\n```typescript\nimport nlp from 'compromise'\n\nvar doc = nlp('London is calling')\ndoc.verbs().toNegative()\n// 'London is not calling'\n```\n\n\u003cimg height=\"75px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003c!--\n  bragging graphs\n --\u003e\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\ncompromise is **~250kb** (minified):\n\n\u003cdiv align=\"center\"\u003e\n  \u003c!-- filesize --\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=compromise\"\u003e\n    \u003cimg width=\"600\" src=\"https://user-images.githubusercontent.com/399657/68234819-14dfc300-ffd0-11e9-8b30-cb8545707b29.png\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\nit's pretty fast. It can run on keypress:\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://observablehq.com/@spencermountain/compromise-performance\"\u003e\n    \u003cimg width=\"600\" src=\"https://user-images.githubusercontent.com/399657/159795115-ed62440a-be41-424c-baa4-8dd15c48377d.png\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\nit works mainly by \u003ca href=\"https://observablehq.com/@spencermountain/verbs\"\u003econjugating all forms\u003c/a\u003e of a basic word list.\n\nThe final lexicon is \u003ca href=\"https://observablehq.com/@spencermountain/compromise-lexicon\"\u003e~14,000 words\u003c/a\u003e:\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg width=\"600\" src=\"https://user-images.githubusercontent.com/399657/68234805-0d201e80-ffd0-11e9-8dc6-f7a600352555.png\"/\u003e\n\u003c/div\u003e\n\nyou can read more about how it works, [here](https://observablehq.com/@spencermountain/compromise-internals). it's weird.\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"75px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003c!--\n  one/two/three parts\n --\u003e\n\u003cp align=\"left\"\u003e\n  \u003csub\u003eokay -\u003c/sub\u003e\n  \u003ch1\u003e\n    \u003ccode\u003ecompromise/one\u003c/code\u003e\n  \u003c/h1\u003e\n  \u003cp align=\"center\"\u003eA \u003ccode\u003etokenizer\u003c/code\u003e of words, sentences, and punctuation.\u003c/p\u003e\n  \u003cimg height=\"15px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003cp\u003e\n\n```js\nimport nlp from 'compromise/one'\n\nlet doc = nlp(\"Wayne's World, party time\")\nlet data = doc.json()\n/* [{\n  normal:\"wayne's world party time\",\n    terms:[{ text: \"Wayne's\", normal: \"wayne\" },\n      ...\n      ]\n  }]\n*/\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-tokenization\"\u003etokenizer docs\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cb\u003ecompromise/one\u003c/b\u003e splits your text up, wraps it in a handy API,\n\n\u003cul\u003e\n  \u003csub\u003eand does nothing else -\u003c/sub\u003e\n\u003c/ul\u003e\n\n\u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003cb\u003e/one\u003c/b\u003e is quick - most sentences take a 10th of a millisecond.\n\nIt can do \u003cb\u003e~1mb\u003c/b\u003e of text a second - or 10 wikipedia pages.\n\n\u003ci\u003eInfinite jest\u003c/i\u003e takes 3s.\n\n\u003cdiv align=\"right\"\u003e\n  You can also parallelize, or stream text to it with \u003ca href=\"https://github.com/spencermountain/compromise/tree/master/plugins/speed\"\u003ecompromise-speed\u003c/a\u003e.\n\u003c/div\u003e\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"60px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003c!-- two --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"left\"\u003e\n   \u003ccode\u003ecompromise/two\u003c/code\u003e\n  \u003c/h1\u003e\n  \u003cp align=\"center\"\u003eA \u003ccode\u003epart-of-speech\u003c/code\u003e tagger, and grammar-interpreter.\u003c/p\u003e\n  \u003cimg height=\"15px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n  \u003cp\u003e\n\n```js\nimport nlp from 'compromise/two'\n\nlet doc = nlp(\"Wayne's World, party time\")\nlet str = doc.match('#Possessive #Noun').text()\n// \"Wayne's World\"\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-tagger\"\u003etagger docs\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\n  \u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003c/p\u003e\n\u003cb\u003ecompromise/two\u003c/b\u003e automatically calculates the very basic grammar of each word.\n\n\u003csub\u003ethis is more useful than people sometimes realize.\u003c/sub\u003e\n\nLight grammar helps you write cleaner templates, and get closer to the information.\n\n\u003c!-- Part-of-speech tagging is profoundly-difficult task to get 100% on. It is also a profoundly easy task to get 85% on. --\u003e\n\n\u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\ncompromise has \u003cb\u003e83 tags\u003c/b\u003e, arranged in \u003ca href=\"https://observablehq.com/@spencermountain/compromise-tags\"\u003ea handsome graph\u003c/a\u003e.\n\n\u003cb\u003e#FirstName\u003c/b\u003e → \u003cb\u003e#Person\u003c/b\u003e → \u003cb\u003e#ProperNoun\u003c/b\u003e → \u003cb\u003e#Noun\u003c/b\u003e\n\nyou can see the grammar of each word by running `doc.debug()`\n\nyou can see the reasoning for each tag with `nlp.verbose('tagger')`.\n\nif you prefer \u003ca href=\"https://www.ling.upenn.edu/courses/Fall_2003/ling001/penn_treebank_pos.html\"\u003e\u003ci\u003ePenn tags\u003c/i\u003e\u003c/a\u003e, you can derive them with:\n\n```js\nlet doc = nlp('welcome thrillho')\ndoc.compute('penn')\ndoc.json()\n```\n\n\u003cimg height=\"60px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003c!-- three --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"left\"\u003e\n   \u003ccode\u003ecompromise/three\u003c/code\u003e\n  \u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\u003ccode\u003ePhrase\u003c/code\u003e and sentence tooling.\u003c/p\u003e\n  \u003cimg height=\"15px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n  \u003cp\u003e\n\n```js\nimport nlp from 'compromise/three'\n\nlet doc = nlp(\"Wayne's World, party time\")\nlet str = doc.people().normalize().text()\n// \"wayne\"\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-selections\"\u003eselection docs\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cb\u003ecompromise/three\u003c/b\u003e is a set of tooling to \u003ci\u003ezoom into\u003c/i\u003e and operate on parts of a text.\n\n`.numbers()` grabs all the numbers in a document, for example - and extends it with new methods, like `.subtract()`.\n\nWhen you have a phrase, or group of words, you can see additional metadata about it with `.json()`\n\n```js\nlet doc = nlp('four out of five dentists')\nconsole.log(doc.fractions().json())\n/*[{\n    text: 'four out of five',\n    terms: [ [Object], [Object], [Object], [Object] ],\n    fraction: { numerator: 4, denominator: 5, decimal: 0.8 }\n  }\n]*/\n```\n\n```js\nlet doc = nlp('$4.09CAD')\ndoc.money().json()\n/*[{\n    text: '$4.09CAD',\n    terms: [ [Object] ],\n    number: { prefix: '$', num: 4.09, suffix: 'cad'}\n  }\n]*/\n```\n\n\u003cimg height=\"80px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n## API\n\n### Compromise/one\n\n##### Output\n\n- **[.text()](https://observablehq.com/@spencermountain/compromise-text)** - return the document as text\n- **[.json()](https://observablehq.com/@spencermountain/compromise-json)** - return the document as data\n- **[.debug()](https://observablehq.com/@spencermountain/compromise-output)** - pretty-print the interpreted document\n- **[.out()](https://observablehq.com/@spencermountain/compromise-output)** - a named or custom output\n- **[.html({})](https://observablehq.com/@spencermountain/compromise-html)** - output custom html tags for matches\n- **[.wrap({})](https://observablehq.com/@spencermountain/compromise-output)** - produce custom output for document matches\n\n##### Utils\n\n- **[.found](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ - is this document empty?\n- **[.docs](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ get term objects as json\n- **[.length](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ - count the # of characters in the document (string length)\n- **[.isView](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ - identify a compromise object\n- **[.compute()](https://observablehq.com/@spencermountain/compromise-compute)** - run a named analysis on the document\n- **[.clone()](https://observablehq.com/@spencermountain/compromise-utils)** - deep-copy the document, so that no references remain\n- **[.termList()](https://observablehq.com/@spencermountain/compromise-accessors)** - return a flat list of all Term objects in match\n- **[.cache({})](https://observablehq.com/@spencermountain/compromise-cache)** - freeze the current state of the document, for speed-purposes\n- **[.uncache()](https://observablehq.com/@spencermountain/compromise-cache)** - un-freezes the current state of the document, so it may be transformed\n- **[.freeze({})](https://observablehq.com/@spencermountain/compromise-freeze)** - prevent any tags from being removed, in these terms\n- **[.unfreeze({})](https://observablehq.com/@spencermountain/compromise-freeze)** - allow tags to change again, as default\n\n##### Accessors\n\n- **[.all()](https://observablehq.com/@spencermountain/compromise-utils)** - return the whole original document ('zoom out')\n- **[.terms()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up results by each individual term\n- **[.first(n)](https://observablehq.com/@spencermountain/compromise-accessors)** - use only the first result(s)\n- **[.last(n)](https://observablehq.com/@spencermountain/compromise-accessors)** - use only the last result(s)\n- **[.slice(n,n)](https://observablehq.com/@spencermountain/compromise-accessors)** - grab a subset of the results\n- **[.eq(n)](https://observablehq.com/@spencermountain/compromise-accessors)** - use only the nth result\n- **[.firstTerms()](https://observablehq.com/@spencermountain/compromise-accessors)** - get the first word in each match\n- **[.lastTerms()](https://observablehq.com/@spencermountain/compromise-accessors)** - get the end word in each match\n- **[.fullSentences()](https://observablehq.com/@spencermountain/compromise-accessors)** - get the whole sentence for each match\n- **[.groups()](https://observablehq.com/@spencermountain/compromise-accessors)** - grab any named capture-groups from a match\n- **[.wordCount()](https://observablehq.com/@spencermountain/compromise-utils)** - count the # of terms in the document\n- **[.confidence()](https://observablehq.com/@spencermountain/compromise-utils)** - an average score for pos tag interpretations\n\n##### Match\n\n_(match methods use the [match-syntax](https://docs.compromise.cool/compromise-match-syntax).)_\n\n- **[.match('')](https://observablehq.com/@spencermountain/compromise-match)** - return a new Doc, with this one as a parent\n- **[.not('')](https://observablehq.com/@spencermountain/compromise-match)** - return all results except for this\n- **[.matchOne('')](https://observablehq.com/@spencermountain/compromise-match)** - return only the first match\n- **[.if('')](https://observablehq.com/@spencermountain/compromise-match)** - return each current phrase, only if it contains this match ('only')\n- **[.ifNo('')](https://observablehq.com/@spencermountain/compromise-match)** - Filter-out any current phrases that have this match ('notIf')\n- **[.has('')](https://observablehq.com/@spencermountain/compromise-match)** - Return a boolean if this match exists\n- **[.before('')](https://observablehq.com/@spencermountain/compromise-match)** - return all terms before a match, in each phrase\n- **[.after('')](https://observablehq.com/@spencermountain/compromise-match)** - return all terms after a match, in each phrase\n- **[.union()](https://observablehq.com/@spencermountain/compromise-set)** - return combined matches without duplicates\n- **[.intersection()](https://observablehq.com/@spencermountain/compromise-set)** - return only duplicate matches\n- **[.complement()](https://observablehq.com/@spencermountain/compromise-set)** - get everything not in another match\n- **[.settle()](https://observablehq.com/@spencermountain/compromise-set)** - remove overlaps from matches\n- **[.growRight('')](https://observablehq.com/@spencermountain/compromise-match)** - add any matching terms immediately after each match\n- **[.growLeft('')](https://observablehq.com/@spencermountain/compromise-match)** - add any matching terms immediately before each match\n- **[.grow('')](https://observablehq.com/@spencermountain/compromise-match)** - add any matching terms before or after each match\n- **[.sweep(net)](https://observablehq.com/@spencermountain/compromise-sweep)** - apply a series of match objects to the document\n- **[.splitOn('')](https://observablehq.com/@spencermountain/compromise-split)** - return a Document with three parts for every match ('splitOn')\n- **[.splitBefore('')](https://observablehq.com/@spencermountain/compromise-split)** - partition a phrase before each matching segment\n- **[.splitAfter('')](https://observablehq.com/@spencermountain/compromise-split)** - partition a phrase after each matching segment\n- **[.join()](https://observablehq.com/@spencermountain/compromise-split)** - merge any neighbouring terms in each match\n- **[.joinIf(leftMatch, rightMatch)](https://observablehq.com/@spencermountain/compromise-split)** - merge any neighbouring terms under given conditions\n- **[.lookup([])](https://observablehq.com/@spencermountain/compromise-match)** - quick find for an array of string matches\n- **[.autoFill()](https://observablehq.com/@spencermountain/compromise-typeahead)** - create type-ahead assumptions on the document\n\n##### Tag\n\n- **[.tag('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Give all terms the given tag\n- **[.tagSafe('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Only apply tag to terms if it is consistent with current tags\n- **[.unTag('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Remove this term from the given terms\n- **[.canBe('')](https://observablehq.com/@spencermountain/compromise-tagger)** - return only the terms that can be this tag\n\n##### Case\n\n- **[.toLowerCase()](https://observablehq.com/@spencermountain/compromise-case)** - turn every letter of every term to lower-cse\n- **[.toUpperCase()](https://observablehq.com/@spencermountain/compromise-case)** - turn every letter of every term to upper case\n- **[.toTitleCase()](https://observablehq.com/@spencermountain/compromise-case)** - upper-case the first letter of each term\n- **[.toCamelCase()](https://observablehq.com/@spencermountain/compromise-case)** - remove whitespace and title-case each term\n\n##### Whitespace\n\n- **[.pre('')](https://observablehq.com/@spencermountain/compromise-whitespace)** - add this punctuation or whitespace before each match\n- **[.post('')](https://observablehq.com/@spencermountain/compromise-whitespace)** - add this punctuation or whitespace after each match\n- **[.trim()](https://observablehq.com/@spencermountain/compromise-whitespace)** - remove start and end whitespace\n- **[.hyphenate()](https://observablehq.com/@spencermountain/compromise-whitespace)** - connect words with hyphen, and remove whitespace\n- **[.dehyphenate()](https://observablehq.com/@spencermountain/compromise-whitespace)** - remove hyphens between words, and set whitespace\n- **[.toQuotations()](https://observablehq.com/@spencermountain/compromise-whitespace)** - add quotation marks around these matches\n- **[.toParentheses()](https://observablehq.com/@spencermountain/compromise-whitespace)** - add brackets around these matches\n\n##### Loops\n\n- **[.map(fn)](https://observablehq.com/@spencermountain/compromise-loops)** - run each phrase through a function, and create a new document\n- **[.forEach(fn)](https://observablehq.com/@spencermountain/compromise-loops)** - run a function on each phrase, as an individual document\n- **[.filter(fn)](https://observablehq.com/@spencermountain/compromise-loops)** - return only the phrases that return true\n- **[.find(fn)](https://observablehq.com/@spencermountain/compromise-loops)** - return a document with only the first phrase that matches\n- **[.some(fn)](https://observablehq.com/@spencermountain/compromise-loops)** - return true or false if there is one matching phrase\n- **[.random(fn)](https://observablehq.com/@spencermountain/compromise-loops)** - sample a subset of the results\n\n##### Insert\n\n- **[.replace(match, replace)](https://observablehq.com/@spencermountain/compromise-insert)** - search and replace match with new content\n- **[.replaceWith(replace)](https://observablehq.com/@spencermountain/compromise-insert)** - substitute-in new text\n- **[.remove()](https://observablehq.com/@spencermountain/compromise-insert)** - fully remove these terms from the document\n- **[.insertBefore(str)](https://observablehq.com/@spencermountain/compromise-insert)** - add these new terms to the front of each match (prepend)\n- **[.insertAfter(str)](https://observablehq.com/@spencermountain/compromise-insert)** - add these new terms to the end of each match (append)\n- **[.concat()](https://observablehq.com/@spencermountain/compromise-insert)** - add these new things to the end\n- **[.swap(fromLemma, toLemma)](https://observablehq.com/@spencermountain/compromise-root)** - smart replace of root-words,using proper conjugation\n\n##### Transform\n\n- **[.sort('method')](https://observablehq.com/@spencermountain/compromise-sorting)** - re-arrange the order of the matches (in place)\n- **[.reverse()](https://observablehq.com/@spencermountain/compromise-sorting)** - reverse the order of the matches, but not the words\n- **[.normalize({})](https://observablehq.com/@spencermountain/compromise-normalization)** - clean-up the text in various ways\n- **[.unique()](https://observablehq.com/@spencermountain/compromise-sorting)** - remove any duplicate matches\n\n##### Lib\n\n_(these methods are on the main `nlp` object)_\n\n- **[nlp.tokenize(str)](https://observablehq.com/@spencermountain/compromise-tokenization)** - parse text without running POS-tagging\n- **[nlp.lazy(str, match)](https://observablehq.com/@spencermountain/compromise-performance)** - scan through a text with minimal analysis\n- **[nlp.plugin({})](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - mix in a compromise-plugin\n- **[nlp.parseMatch(str)](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - pre-parse any match statements into json\n- **[nlp.world()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - grab or change library internals\n- **[nlp.model()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - grab all current linguistic data\n- **[nlp.methods()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - grab or change internal methods\n- **[nlp.hooks()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - see which compute methods run automatically\n- **[nlp.verbose(mode)](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - log our decision-making for debugging\n- **[nlp.version](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - current semver version of the library\n\n- **[nlp.addWords(obj, isFrozen?)](https://observablehq.com/@spencermountain/compromise-plugin)** - add new words to the lexicon\n- **[nlp.addTags(obj)](https://observablehq.com/@spencermountain/compromise-plugin)** - add new tags to the tagSet\n- **[nlp.typeahead(arr)](https://observablehq.com/@spencermountain/compromise-typeahead)** - add words to the auto-fill dictionary\n- **[nlp.buildTrie(arr)](https://observablehq.com/@spencermountain/compromise-lookup)** - compile a list of words into a fast lookup form\n- **[nlp.buildNet(arr)](https://observablehq.com/@spencermountain/compromise-sweep)** - compile a list of matches into a fast match form\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n### compromise/two:\n\n##### Contractions\n\n- **[.contractions()](https://observablehq.com/@spencermountain/compromise-contractions)** - things like \"didn't\"\n- **[.contractions().expand()](https://observablehq.com/@spencermountain/compromise-contractions)** - things like \"didn't\"\n- **[.contract()](https://observablehq.com/@spencermountain/compromise-contractions)** - things like \"didn't\"\n\n\u003c!-- spacer --\u003e\n\u003cimg height=\"30px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n### compromise/three:\n\n##### Nouns\n\n- **[.nouns()](https://observablehq.com/@spencermountain/nouns)** - return any subsequent terms tagged as a Noun\n  - **[.nouns().json()](https://observablehq.com/@spencermountain/nouns)** - overloaded output with noun metadata\n  - **[.nouns().parse()](https://observablehq.com/@spencermountain/nouns)** - get tokenized noun-phrase\n  - **[.nouns().isPlural()](https://observablehq.com/@spencermountain/nouns)** - return only plural nouns\n  - **[.nouns().isSingular()](https://observablehq.com/@spencermountain/nouns)** - return only singular nouns\n  - **[.nouns().toPlural()](https://observablehq.com/@spencermountain/nouns)** - `'football captain' → 'football captains'`\n  - **[.nouns().toSingular()](https://observablehq.com/@spencermountain/nouns)** - `'turnovers' → 'turnover'`\n  - **[.nouns().adjectives()](https://observablehq.com/@spencermountain/nouns)** - get any adjectives describing this noun\n\n##### Verbs\n\n- **[.verbs()](https://observablehq.com/@spencermountain/verbs)** - return any subsequent terms tagged as a Verb\n  - **[.verbs().json()](https://observablehq.com/@spencermountain/verbs)** - overloaded output with verb metadata\n  - **[.verbs().parse()](https://observablehq.com/@spencermountain/verbs)** - get tokenized verb-phrase\n  - **[.verbs().subjects()](https://observablehq.com/@spencermountain/verbs)** - what is doing the verb action\n  - **[.verbs().adverbs()](https://observablehq.com/@spencermountain/verbs)** - return the adverbs describing this verb.\n  - **[.verbs().isSingular()](https://observablehq.com/@spencermountain/verbs)** - return singular verbs like 'spencer walks'\n  - **[.verbs().isPlural()](https://observablehq.com/@spencermountain/verbs)** - return plural verbs like 'we walk'\n  - **[.verbs().isImperative()](https://observablehq.com/@spencermountain/verbs)** - only instruction verbs like 'eat it!'\n  - **[.verbs().toPastTense()](https://observablehq.com/@spencermountain/verbs)** - `'will go' → 'went'`\n  - **[.verbs().toPresentTense()](https://observablehq.com/@spencermountain/verbs)** - `'walked' → 'walks'`\n  - **[.verbs().toFutureTense()](https://observablehq.com/@spencermountain/verbs)** - `'walked' → 'will walk'`\n  - **[.verbs().toInfinitive()](https://observablehq.com/@spencermountain/verbs)** - `'walks' → 'walk'`\n  - **[.verbs().toGerund()](https://observablehq.com/@spencermountain/verbs)** - `'walks' → 'walking'`\n  - **[.verbs().toPastParticiple()](https://observablehq.com/@spencermountain/verbs)** - `'drive' → 'had driven'`\n  - **[.verbs().conjugate()](https://observablehq.com/@spencermountain/verbs)** - return all conjugations of these verbs\n  - **[.verbs().isNegative()](https://observablehq.com/@spencermountain/verbs)** - return verbs with 'not', 'never' or 'no'\n  - **[.verbs().isPositive()](https://observablehq.com/@spencermountain/verbs)** - only verbs without 'not', 'never' or 'no'\n  - **[.verbs().toNegative()](https://observablehq.com/@spencermountain/verbs)** - `'went' → 'did not go'`\n  - **[.verbs().toPositive()](https://observablehq.com/@spencermountain/verbs)** - `\"didn't study\" → 'studied'`\n\n##### Numbers\n\n- **[.numbers()](https://observablehq.com/@spencermountain/compromise-values)** - grab all written and numeric values\n  - **[.numbers().parse()](https://observablehq.com/@spencermountain/compromise-values)** - get tokenized number phrase\n  - **[.numbers().get()](https://observablehq.com/@spencermountain/compromise-values)** - get a simple javascript number\n  - **[.numbers().json()](https://observablehq.com/@spencermountain/compromise-values)** - overloaded output with number metadata\n  - **[.numbers().toNumber()](https://observablehq.com/@spencermountain/compromise-values)** - convert 'five' to `5`\n  - **[.numbers().toLocaleString()](https://observablehq.com/@spencermountain/compromise-values)** - add commas, or nicer formatting for numbers\n  - **[.numbers().toText()](https://observablehq.com/@spencermountain/compromise-values)** - convert '5' to `five`\n  - **[.numbers().toOrdinal()](https://observablehq.com/@spencermountain/compromise-values)** - convert 'five' to `fifth` or `5th`\n  - **[.numbers().toCardinal()](https://observablehq.com/@spencermountain/compromise-values)** - convert 'fifth' to `five` or `5`\n  - **[.numbers().isOrdinal()](https://observablehq.com/@spencermountain/compromise-values)** - return only ordinal numbers\n  - **[.numbers().isCardinal()](https://observablehq.com/@spencermountain/compromise-values)** - return only cardinal numbers\n  - **[.numbers().isEqual(n)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers with this value\n  - **[.numbers().greaterThan(min)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers bigger than n\n  - **[.numbers().lessThan(max)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers smaller than n\n  - **[.numbers().between(min, max)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers between min and max\n  - **[.numbers().isUnit(unit)](https://observablehq.com/@spencermountain/compromise-values)** - return only numbers in the given unit, like 'km'\n  - **[.numbers().set(n)](https://observablehq.com/@spencermountain/compromise-values)** - set number to n\n  - **[.numbers().add(n)](https://observablehq.com/@spencermountain/compromise-values)** - increase number by n\n  - **[.numbers().subtract(n)](https://observablehq.com/@spencermountain/compromise-values)** - decrease number by n\n  - **[.numbers().increment()](https://observablehq.com/@spencermountain/compromise-values)** - increase number by 1\n  - **[.numbers().decrement()](https://observablehq.com/@spencermountain/compromise-values)** - decrease number by 1\n- **[.money()](https://observablehq.com/@spencermountain/compromise-values)** - things like `'$2.50'`\n  - **[.money().get()](https://observablehq.com/@spencermountain/compromise-values)** - retrieve the parsed amount(s) of money\n  - **[.money().json()](https://observablehq.com/@spencermountain/compromise-values)** - currency + number info\n  - **[.money().currency()](https://observablehq.com/@spencermountain/compromise-values)** - which currency the money is in\n- **[.fractions()](https://observablehq.com/@spencermountain/compromise-values)** - like '2/3rds' or 'one out of five'\n  - **[.fractions().parse()](https://observablehq.com/@spencermountain/compromise-values)** - get tokenized fraction\n  - **[.fractions().get()](https://observablehq.com/@spencermountain/compromise-values)** - simple numerator, denominator data\n  - **[.fractions().json()](https://observablehq.com/@spencermountain/compromise-values)** - json method overloaded with fractions data\n  - **[.fractions().toDecimal()](https://observablehq.com/@spencermountain/compromise-values)** - '2/3' -\u003e '0.66'\n  - **[.fractions().normalize()](https://observablehq.com/@spencermountain/compromise-values)** - 'four out of 10' -\u003e '4/10'\n  - **[.fractions().toText()](https://observablehq.com/@spencermountain/compromise-values)** - '4/10' -\u003e 'four tenths'\n  - **[.fractions().toPercentage()](https://observablehq.com/@spencermountain/compromise-values)** - '4/10' -\u003e '40%'\n- **[.percentages()](https://observablehq.com/@spencermountain/compromise-values)** - like '2.5%'\n  - **[.percentages().get()](https://observablehq.com/@spencermountain/compromise-values)** - return the percentage number / 100\n  - **[.percentages().json()](https://observablehq.com/@spencermountain/compromise-values)** - json overloaded with percentage information\n  - **[.percentages().toFraction()](https://observablehq.com/@spencermountain/compromise-values)** - '80%' -\u003e '8/10'\n\n##### Sentences\n\n- **[.sentences()](https://observablehq.com/@spencermountain/compromise-sentences)** - return a sentence class with additional methods\n  - **[.sentences().json()](https://observablehq.com/@spencermountain/compromise-sentences)** - overloaded output with sentence metadata\n  \u003c!-- - **[.sentences().subjects()](https://observablehq.com/@spencermountain/compromise-sentences)** - return the main noun of each sentence --\u003e\n  - **[.sentences().toPastTense()](https://observablehq.com/@spencermountain/compromise-sentences)** - `he walks` -\u003e `he walked`\n  - **[.sentences().toPresentTense()](https://observablehq.com/@spencermountain/compromise-sentences)** - `he walked` -\u003e `he walks`\n  - **[.sentences().toFutureTense()](https://observablehq.com/@spencermountain/compromise-sentences)** -- `he walks` -\u003e `he will walk`\n  - **[.sentences().toInfinitive()](https://observablehq.com/@spencermountain/compromise-sentences)** -- verb root-form `he walks` -\u003e `he walk`\n  - **[.sentences().toNegative()](https://observablehq.com/@spencermountain/compromise-sentences)** - - `he walks` -\u003e `he didn't walk`\n  - **[.sentences().isQuestion()](https://observablehq.com/@spencermountain/compromise-sentences)** - return questions with a `?`\n  - **[.sentences().isExclamation()](https://observablehq.com/@spencermountain/compromise-sentences)** - return sentences with a `!`\n  - **[.sentences().isStatement()](https://observablehq.com/@spencermountain/compromise-sentences)** - return sentences without `?` or `!`\n\n##### Adjectives\n\n- **[.adjectives()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'quick'`\n  - **[.adjectives().json()](https://observablehq.com/@spencermountain/compromise-selections)** - get adjective metadata\n  - **[.adjectives().conjugate()](https://observablehq.com/@spencermountain/compromise-selections)** - return all inflections of these adjectives\n  - **[.adjectives().adverbs()](https://observablehq.com/@spencermountain/compromise-selections)** - get adverbs describing this adjective\n  - **[.adjectives().toComparative()](https://observablehq.com/@spencermountain/compromise-selections)** - 'quick' -\u003e 'quicker'\n  - **[.adjectives().toSuperlative()](https://observablehq.com/@spencermountain/compromise-selections)** - 'quick' -\u003e 'quickest'\n  - **[.adjectives().toAdverb()](https://observablehq.com/@spencermountain/compromise-selections)** - 'quick' -\u003e 'quickly'\n  - **[.adjectives().toNoun()](https://observablehq.com/@spencermountain/compromise-selections)** - 'quick' -\u003e 'quickness'\n\n##### Misc selections\n\n- **[.clauses()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up sentences into multi-term phrases\n- **[.chunks()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up sentences noun-phrases and verb-phrases\n- **[.hyphenated()](https://observablehq.com/@spencermountain/compromise-selections)** - all terms connected with a hyphen or dash like `'wash-out'`\n- **[.phoneNumbers()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'(939) 555-0113'`\n- **[.hashTags()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'#nlp'`\n- **[.emails()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'hi@compromise.cool'`\n- **[.emoticons()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `:)`\n- **[.emojis()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `💋`\n- **[.atMentions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'@nlp_compromise'`\n- **[.urls()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'compromise.cool'`\n- **[.pronouns()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'he'`\n- **[.conjunctions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'but'`\n- **[.prepositions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'of'`\n- **[.abbreviations()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'Mrs.'`\n- **[.people()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - names like 'John F. Kennedy'\n  - **[.people().json()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - get person-name metadata\n  - **[.people().parse()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - get person-name interpretation\n- **[.places()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - like 'Paris, France'\n- **[.organizations()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - like 'Google, Inc'\n- **[.topics()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - `people()` + `places()` + `organizations()`\n- **[.adverbs()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'quickly'`\n  - **[.adverbs().json()](https://observablehq.com/@spencermountain/compromise-selections)** - get adverb metadata\n- **[.acronyms()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'FBI'`\n  - **[.acronyms().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - remove periods from acronyms\n  - **[.acronyms().addPeriods()](https://observablehq.com/@spencermountain/compromise-selections)** - add periods to acronyms\n- **[.parentheses()](https://observablehq.com/@spencermountain/compromise-selections)** - return anything inside (parentheses)\n  - **[.parentheses().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - remove brackets\n- **[.possessives()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `\"Spencer's\"`\n  - **[.possessives().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - \"Spencer's\" -\u003e \"Spencer\"\n- **[.quotations()](https://observablehq.com/@spencermountain/compromise-selections)** - return any terms inside paired quotation marks\n  - **[.quotations().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - remove quotation marks\n- **[.slashes()](https://observablehq.com/@spencermountain/compromise-selections)** - return any terms grouped by slashes\n  - **[.slashes().split()](https://observablehq.com/@spencermountain/compromise-selections)** - turn 'love/hate' into 'love hate'\n\n\u003cp\u003e\n\u003cimg height=\"85px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png\"/\u003e\n\u003c/div\u003e\n\n### .extend():\n\nThis library comes with a considerate, common-sense baseline for english grammar.\n\nYou're free to change, or lay-waste to any settings - which is the fun part actually.\n\nthe easiest part is just to suggest tags for any given words:\n\n```js\nlet myWords = {\n  kermit: 'FirstName',\n  fozzie: 'FirstName',\n}\nlet doc = nlp(muppetText, myWords)\n```\n\nor make heavier changes with a [compromise-plugin](https://observablehq.com/@spencermountain/compromise-plugins).\n\n```js\nimport nlp from 'compromise'\nnlp.extend({\n  // add new tags\n  tags: {\n    Character: {\n      isA: 'Person',\n      notA: 'Adjective',\n    },\n  },\n  // add or change words in the lexicon\n  words: {\n    kermit: 'Character',\n    gonzo: 'Character',\n  },\n  // change inflections\n  irregulars: {\n    get: {\n      pastTense: 'gotten',\n      gerund: 'gettin',\n    },\n  },\n  // add new methods to compromise\n  api: View =\u003e {\n    View.prototype.kermitVoice = function () {\n      this.sentences().prepend('well,')\n      this.match('i [(am|was)]').prepend('um,')\n      return this\n    }\n  },\n})\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-plugins\"\u003e.plugin() docs\u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221848-11404200-ffb8-11e9-90cd-3adee8d8564f.png\"/\u003e\n\u003c/div\u003e\n\n\u003c!-- spacer --\u003e\n\u003cdiv \u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003c/div\u003e\n\n### Docs:\n\n##### gentle introduction:\n\n- **[#1) Input → output](https://docs.compromise.cool/tutorial-1)**\n- **[#2) Match \u0026 transform](https://docs.compromise.cool/compromise-tutorial-2)**\n- **[#3) Making a chat-bot](https://docs.compromise.cool/compromise-making-a-bot)**\n  \u003c!-- * **[Tutorial #4]()**  -  Making a plugin --\u003e\n\n\u003cdiv \u003e\n  \u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003c/div\u003e\n\n##### Documentation:\n\n| Concepts                                                                                    |                                               API                                               |                                                                                Plugins |\n| ------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------: | -------------------------------------------------------------------------------------: |\n| [Accuracy](https://observablehq.com/@spencermountain/compromise-accuracy)                   |           [Accessors](https://observablehq.com/@spencermountain/compromise-accessors)           |          [Adjectives](https://observablehq.com/@spencermountain/compromise-adjectives) |\n| [Caching](https://observablehq.com/@spencermountain/compromise-cache)                       | [Constructor-methods](https://observablehq.com/@spencermountain/compromise-constructor-methods) |                    [Dates](https://observablehq.com/@spencermountain/compromise-dates) |\n| [Case](https://observablehq.com/@spencermountain/compromise-case)                           |        [Contractions](https://observablehq.com/@spencermountain/compromise-contractions)        |                  [Export](https://observablehq.com/@spencermountain/compromise-export) |\n| [Filesize](https://observablehq.com/@spencermountain/compromise-filesize)                   |              [Insert](https://observablehq.com/@spencermountain/compromise-insert)              |                      [Hash](https://observablehq.com/@spencermountain/compromise-hash) |\n| [Internals](https://observablehq.com/@spencermountain/compromise-internals)                 |                [Json](https://observablehq.com/@spencermountain/compromise-json)                |                      [Html](https://observablehq.com/@spencermountain/compromise-html) |\n| [Justification](https://observablehq.com/@spencermountain/compromise-justification)         |        [Character Offsets](https://observablehq.com/@spencermountain/compromise-offsets)        |              [Keypress](https://observablehq.com/@spencermountain/compromise-keypress) |\n| [Lexicon](https://observablehq.com/@spencermountain/compromise-lexicon)                     |               [Loops](https://observablehq.com/@spencermountain/compromise-loops)               |                   [Ngrams](https://observablehq.com/@spencermountain/compromise-ngram) |\n| [Match-syntax](https://observablehq.com/@spencermountain/compromise-match-syntax)           |               [Match](https://observablehq.com/@spencermountain/compromise-match)               |                 [Numbers](https://observablehq.com/@spencermountain/compromise-values) |\n| [Performance](https://observablehq.com/@spencermountain/compromise-performance)             |                    [Nouns](https://observablehq.com/@spencermountain/nouns)                     |          [Paragraphs](https://observablehq.com/@spencermountain/compromise-paragraphs) |\n| [Plugins](https://observablehq.com/@spencermountain/compromise-plugins)                     |              [Output](https://observablehq.com/@spencermountain/compromise-output)              |                      [Scan](https://observablehq.com/@spencermountain/compromise-scan) |\n| [Projects](https://observablehq.com/@spencermountain/compromise-projects)                   |          [Selections](https://observablehq.com/@spencermountain/compromise-selections)          |            [Sentences](https://observablehq.com/@spencermountain/compromise-sentences) |\n| [Tagger](https://observablehq.com/@spencermountain/compromise-tagger)                       |             [Sorting](https://observablehq.com/@spencermountain/compromise-sorting)             |            [Syllables](https://observablehq.com/@spencermountain/compromise-syllables) |\n| [Tags](https://observablehq.com/@spencermountain/compromise-tags)                           |               [Split](https://observablehq.com/@spencermountain/compromise-split)               |            [Pronounce](https://observablehq.com/@spencermountain/compromise-pronounce) |\n| [Tokenization](https://observablehq.com/@spencermountain/compromise-tokenization)           |                [Text](https://observablehq.com/@spencermountain/compromise-text)                |                  [Strict](https://observablehq.com/@spencermountain/compromise-strict) |\n| [Named-Entities](https://observablehq.com/@spencermountain/topics-named-entity-recognition) |               [Utils](https://observablehq.com/@spencermountain/compromise-utils)               |            [Penn-tags](https://observablehq.com/@spencermountain/compromise-penn-tags) |\n| [Whitespace](https://observablehq.com/@spencermountain/compromise-whitespace)               |                    [Verbs](https://observablehq.com/@spencermountain/verbs)                     | [Typeahead](https://observablehq.com/@spencermountain/compromise/compromise-typeahead) |\n| [World data](https://observablehq.com/@spencermountain/compromise-world)                    |       [Normalization](https://observablehq.com/@spencermountain/compromise-normalization)       |                    [Sweep](https://observablehq.com/@spencermountain/compromise-sweep) |\n| [Fuzzy-matching](https://observablehq.com/@spencermountain/compromise-fuzzy-matching)       |          [Typescript](https://observablehq.com/@spencermountain/compromise-typescript)          |              [Mutation](https://observablehq.com/@spencermountain/compromise-mutation) |\n| [Root-forms](https://observablehq.com/@spencermountain/compromise-root)                     |\n\n\u003cdiv \u003e\n  \u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003c/div\u003e\n\n##### Talks:\n\n- **[Language as an Interface](https://www.youtube.com/watch?v=WuPVS2tCg8s)** - by Spencer Kelly\n- **[Coding Chat Bots](https://www.youtube.com/watch?v=c_hmwFwvO0U)** - by KahWee Teng\n- **[On Typing and data](https://vimeo.com/496095722)** - by Spencer Kelly\n\n##### Articles:\n\n- **[Geocoding Social Conversations with NLP and JavaScript](http://compromise.cool)** - by Microsoft\n- **[Microservice Recipe](https://eventn.com/recipes/text-parsing-with-nlp-compromise)** - by Eventn\n- **[Adventure Game Sentence Parsing with Compromise](https://killalldefects.com/2020/02/20/adventure-game-sentence-parsing-with-compromise/)**\n- **[Building Text-Based Games](https://killalldefects.com/2019/09/24/building-text-based-games-with-compromise-nlp/)** - by Matt Eland\n- **[Fun with javascript in BigQuery](https://medium.com/@hoffa/new-in-bigquery-persistent-udfs-c9ea4100fd83#6e09)** - by Felipe Hoffa\n- **[Natural Language Processing... in the Browser?](https://dev.to/charlesdlandau/natural-language-processing-in-the-browser-52hj)** - by Charles Landau\n\n##### Some fun Applications:\n\n- **[Automated Bechdel Test](https://github.com/guardian/bechdel-test)** - by The Guardian\n- **[Story generation framework](https://perchance.org/welcome)** - by Jose Phrocca\n- **[Tumbler blog of lists](https://leanstooneside.tumblr.com/)** - horse-ebooks-like lists - by Michael Paulukonis\n- **[Video Editing from Transcription](https://newtheory.io/)** - by New Theory\n- **[Browser extension Fact-checking](https://github.com/AlexanderKidd/FactoidL)** - by Alexander Kidd\n- **[Siri shortcut](https://routinehub.co/shortcut/3260)** - by Michael Byrns\n- **[Amazon skill](https://github.com/tajddin/voiceplay)** - by Tajddin Maghni\n- **[Tasking Slack-bot](https://github.com/kevinsuh/toki)** - by Kevin Suh\n  [[see more]](https://observablehq.com/@spencermountain/compromise-projects)\n\n##### Comparisons\n\n- [Compromise and Spacy](https://observablehq.com/@spencermountain/compromise-and-spacy)\n- [Compromise and NLTK](https://observablehq.com/@spencermountain/compromise-and-nltk)\n\n\u003c!-- spacer --\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n  \u003chr/\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221632-b9094000-ffb7-11e9-99e0-b48edd6cdf8a.png\"/\u003e\n\u003c/div\u003e\n\n\u003c!-- \u003cdiv align=\"center\"\u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221824-09809d80-ffb8-11e9-9ef0-6ed3574b0ce8.png\"/\u003e\n\u003c/div\u003e --\u003e\n\n### Plugins:\n\nThese are some helpful extensions:\n\n##### Dates\n\n`npm install compromise-dates`\n\n- **[.dates()](https://observablehq.com/@spencermountain/compromise-dates)** - find dates like `June 8th` or `03/03/18`\n  - **[.dates().get()](https://observablehq.com/@spencermountain/compromise-dates)** - simple start/end json result\n  - **[.dates().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with date metadata\n  - **[.dates().format('')](https://observablehq.com/@spencermountain/compromise-dates)** - convert the dates to specific formats\n  - **[.dates().toShortForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Wednesday' to 'Wed', etc\n  - **[.dates().toLongForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Feb' to 'February', etc\n- **[.durations()](https://observablehq.com/@spencermountain/compromise-dates)** - `2 weeks` or `5mins`\n  - **[.durations().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for duration\n  - **[.durations().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with duration metadata\n- **[.times()](https://observablehq.com/@spencermountain/compromise-dates)** - `4:30pm` or `half past five`\n  - **[.times().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for times\n  - **[.times().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with time metadata\n\n##### Stats\n\n`npm install compromise-stats`\n\n- **[.tfidf({})](https://observablehq.com/@spencermountain/compromise-tfidf)** - rank words by frequency and uniqueness\n\n- **[.ngrams({})](https://observablehq.com/@spencermountain/compromise-ngram)** - list all repeating sub-phrases, by word-count\n- **[.unigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with one word\n- **[.bigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with two words\n- **[.trigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with three words\n- **[.startgrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the first term of a phrase\n- **[.endgrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the last term of a phrase\n- **[.edgegrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the first or last term of a phrase\n\n##### Speech\n\n`npm install compromise-syllables`\n\n- **[.syllables()](https://observablehq.com/@spencermountain/compromise-syllables)** - split each term by its typical pronunciation\n- **[.soundsLike()](https://observablehq.com/@spencermountain/compromise-soundsLike)** - produce a estimated pronunciation\n\n##### Wikipedia\n\n`npm install compromise-wikipedia`\n\n- **[.wikipedia()](https://observablehq.com/@spencermountain/compromise-wikipedia)** - compressed article reconciliation\n\n\u003c!-- spacer --\u003e\n\u003cdiv \u003e\n  \u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n  \u003chr/\u003e\n\u003c/div\u003e\n\n### Typescript\n\nwe're committed to typescript/deno support, both in main and in the official-plugins:\n\n```ts\nimport nlp from 'compromise'\nimport stats from 'compromise-stats'\n\nconst nlpEx = nlp.extend(stats)\n\nnlpEx('This is type safe!').ngrams({ min: 1 })\n```\n\n\u003cdiv align=\"right\"\u003e\n  \u003ca href=\"https://docs.compromise.cool/compromise-typescript\"\u003etypescript docs\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv \u003e\n  \u003cimg height=\"50px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\u003c/div\u003e\n\n#### Limitations:\n\n- **slash-support:**\n  We currently split slashes up as different words, like we do for hyphens. so things like this don't work:\n  \u003ccode\u003enlp('the koala eats/shoots/leaves').has('koala leaves') //false\u003c/code\u003e\n\n- **inter-sentence match:**\n  By default, sentences are the top-level abstraction.\n  Inter-sentence, or multi-sentence matches aren't supported without \u003ca href=\"https://github.com/spencermountain/compromise/tree/master/plugins/paragraphs\"\u003ea plugin\u003c/a\u003e:\n  \u003ccode\u003enlp(\"that's it. Back to Winnipeg!\").has('it back')//false\u003c/code\u003e\n\n- **nested match syntax:**\n  the \u003cs\u003edanger\u003c/s\u003e beauty of regex is that you can recurse indefinitely.\n  Our match syntax is much weaker. Things like this are not \u003ci\u003e(yet)\u003c/i\u003e possible:\n  \u003ccode\u003edoc.match('(modern (major|minor))? general')\u003c/code\u003e\n  complex matches must be achieved with successive **.match()** statements.\n\n- **dependency parsing:**\n  Proper sentence transformation requires understanding the [syntax tree](https://en.wikipedia.org/wiki/Parse_tree) of a sentence, which we don't currently do.\n  We should! Help wanted with this.\n\n##### FAQ\n\n\u003cul align=\"left\"\u003e\n  \u003cp\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e☂️ Isn't javascript too...\u003c/summary\u003e\n      \u003cp\u003e\u003c/p\u003e\n      \u003cul\u003e\n        yeah it is!\n        \u003cbr/\u003e\n        it wasn't built to compete with NLTK, and may not fit every project.\n        \u003cbr/\u003e\n        string processing is synchronous too, and parallelizing node processes is weird.\n        \u003cbr/\u003e\n        See \u003ca href=\"https://observablehq.com/@spencermountain/compromise-performance\"\u003ehere\u003c/a\u003e for information about speed \u0026 performance, and\n        \u003ca href=\"https://observablehq.com/@spencermountain/compromise-justification\"\u003ehere\u003c/a\u003e for project motivations\n      \u003c/ul\u003e\n      \u003cp\u003e\u003c/p\u003e\n    \u003c/details\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e💃 Can it run on my arduino-watch?\u003c/summary\u003e\n      \u003cp\u003e\u003c/p\u003e\n      \u003cul\u003e\n        Only if it's water-proof!\n        \u003cbr/\u003e\n        Read \u003ca href=\"https://observablehq.com/@spencermountain/compromise-quickstart\"\u003equick start\u003c/a\u003e for running compromise in workers, mobile apps, and all sorts of funny environments.\n      \u003c/ul\u003e\n      \u003cp\u003e\u003c/p\u003e\n    \u003c/details\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e🌎 Compromise in other Languages?\u003c/summary\u003e\n      \u003cp\u003e\u003c/p\u003e\n      \u003cul\u003e\n        we've got work-in-progress forks for \u003ca href=\"https://github.com/nlp-compromise/de-compromise\"\u003eGerman\u003c/a\u003e, \u003ca href=\"https://github.com/nlp-compromise/fr-compromise\"\u003eFrench\u003c/a\u003e, \u003ca href=\"https://github.com/nlp-compromise/es-compromise\"\u003eSpanish\u003c/a\u003e, and \u003ca href=\"https://github.com/nlp-compromise/it-compromise\"\u003eItalian\u003c/a\u003e in the same philosophy.\n        \u003cbr/\u003e\n        and need some help.\n      \u003c/ul\u003e\n      \u003cp\u003e\u003c/p\u003e\n    \u003c/details\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e✨ Partial builds?\u003c/summary\u003e\n      \u003cp\u003e\u003c/p\u003e\n      \u003cul\u003e\n        we do offer a \u003ca href=\"https://observablehq.com/@spencermountain/compromise-filesize\"\u003etokenize-only\u003c/a\u003e build, which has the POS-tagger pulled-out.\n        \u003cbr/\u003e\n        but otherwise, compromise isn't easily tree-shaken.\n        \u003cbr/\u003e\n        the tagging methods are competitive, and greedy, so it's not recommended to pull things out.\n        \u003cbr/\u003e\n        Note that without a full POS-tagging, the contraction-parser won't work perfectly. (\u003ci\u003e(spencer's cool)\u003c/i\u003e vs. \u003ci\u003e(spencer's house)\u003c/i\u003e)\n        \u003cbr/\u003e\n        It's recommended to run the library fully.\n      \u003c/ul\u003e\n      \u003cp\u003e\u003c/p\u003e\n    \u003c/details\u003e\n  \u003c/p\u003e\n\u003c/ul\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/399657/68221731-e8b84800-ffb7-11e9-8453-6395e0e903fa.png\"/\u003e\n\u003c/div\u003e\n\n#### See Also:\n\n- \u0026nbsp; **[en-pos](https://github.com/finnlp/en-pos)** - very clever javascript pos-tagger _by [Alex Corvi](https://github.com/alexcorvi)_\n- \u0026nbsp; **[naturalNode](https://github.com/NaturalNode/natural)** - fancier statistical nlp in javascript\n- \u0026nbsp; **[winkJS](https://winkjs.org/)** - POS-tagger, tokenizer, machine-learning in javascript\n- \u0026nbsp; **[dariusk/pos-js ](https://github.com/dariusk/pos-js)** - fastTag fork in javascript\n- \u0026nbsp; **[compendium-js](https://github.com/Ulflander/compendium-js)** - POS and sentiment analysis in javascript\n- \u0026nbsp; **[nodeBox linguistics](https://www.nodebox.net/code/index.php/Linguistics)** - conjugation, inflection in javascript\n- \u0026nbsp; **[reText](https://github.com/wooorm/retext)** - very impressive [text utilities](https://github.com/wooorm/retext/blob/master/doc/plugins.md) in javascript\n- \u0026nbsp; **[superScript](https://github.com/superscriptjs/superscript)** - conversation engine in js\n- \u0026nbsp; **[jsPos](https://code.google.com/archive/p/jspos/)** - javascript build of the time-tested Brill-tagger\n\n- \u0026nbsp; **[spaCy](https://spacy.io/)** - speedy, multilingual tagger in C/python\n- \u0026nbsp; **[Prose](https://github.com/jdkato/prose/)** - quick tagger in Go by Joseph Kato\n- \u0026nbsp; **[TextBlob](https://github.com/sloria/TextBlob)** - python tagger\n\n\u003cimg height=\"25px\" src=\"https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png\"/\u003e\n\n\u003cb\u003eMIT\u003c/b\u003e\n","funding_links":[],"categories":["Uncategorized","JavaScript","Repository","函式庫","nlp","Javascript","Natural Language Processing"],"sub_categories":["Uncategorized","Natural language processing","書籍","Tools","[Tools](#tools-1)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspencermountain%2Fcompromise","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspencermountain%2Fcompromise","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspencermountain%2Fcompromise/lists"}