diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000..69bab37 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,25 @@ +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +name: Create Release + +jobs: + build: + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false \ No newline at end of file diff --git a/README.md b/README.md index 1f8efd4..d70ac1c 100644 --- a/README.md +++ b/README.md @@ -1 +1,94 @@ -![Tests](https://github.com/asar-studio/natural-abh/workflows/Tests/badge.svg?branch=develop) ![Release Package to npm](https://github.com/asar-studio/natural-abh/workflows/Release%20Package%20to%20npm/badge.svg) +# natural-abh + +======= + +![Tests](https://github.com/asar-studio/natural-abh/workflows/Tests/badge.svg?branch=develop) +![Release Package to npm](https://github.com/asar-studio/natural-abh/workflows/Release%20Package%20to%20npm/badge.svg) +[![NPM version](https://img.shields.io/npm/v/natural-abh.svg)](https://www.npmjs.com/package/natural-abh) + +"natural-abh" is a general natural language facility for nodejs. В настоящее время поддерживается: Tokenizing, normalizing and N-grams are currently supported. + +It's still in the early stages, so we're very interested in bug reports, contributions and the like. + +### TABLE OF CONTENTS + +- [Installation](#installation) +- [Tokenizers](#tokenizers) +- [Normalizer](#normalizer) +- [N-Grams](#n-grams) + +## Installation + +You can install natural-abh via NPM like so: + + npm install natural-abh + +or using yarn: + + yarn add natural-abh + +If you're interested in contributing to natural, or just hacking on it, then by all means fork away! + +## Tokenizers + +Word anf RegExp are provided for breaking text up into arrays of tokens: + +```javascript +const nabh = require('natural-abh'); +const tokenizer = new nabh.WordTokenizer(); +console.log(nabh.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] +``` + +The other tokenizers follow a similar pattern: + +```javascript +tokenizer = new nabh.AggressiveTokenizer(); +console.log(tokenizer.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] + +tokenizer = new nabh.RegexpTokenizer({ pattern: /\-/ }); +console.log(tokenizer.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] + +tokenizer = new nabh.WordPunctTokenizer(); +console.log(tokenizer.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] +``` + +## Normalizer + +Replaces obsolete characters in a string with modern counterparts: + +```javascript +const { normalize } = require('natural-abh'); +console.log(normalize('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// "Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла" +``` + +## N-Grams + +n-grams can be obtained for strings (which will be tokenized for you): + +```javascript +const { bigrams, trigrams, ngrams } = nabh; +``` + +### bigrams + +```javascript +console.log(bigrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +console.log(ngrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла', 2)); +// [ [ 'Аҧсны', 'Аҳәынҭқарра' ], [ 'Аҳәынҭқарра', 'Ашьаустә' ], [ 'Ашьаустә', 'закәанеидкыла' ] ] +``` + +### trigrams + +```javascript +console.log(trigrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +console.log(ngrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла', 3)); +// [ [ 'Аҧсны', 'Аҳәынҭқарра', 'Ашьаустә' ], [ 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] ] +``` + +More use cases u can find reading tests + diff --git a/README.ru.md b/README.ru.md new file mode 100644 index 0000000..a3cb8e7 --- /dev/null +++ b/README.ru.md @@ -0,0 +1,94 @@ +# natural-abh + +======= + +[![NPM version](https://img.shields.io/npm/v/natural-abh.svg)](https://www.npmjs.com/package/natural-abh) +![Tests](https://github.com/asar-studio/natural-abh/workflows/Tests/badge.svg?branch=develop) +![Release Package to npm](https://github.com/asar-studio/natural-abh/workflows/Release%20Package%20to%20npm/badge.svg) + +"Natural" is a general natural language facility for nodejs. В настоящее время поддерживается: токенизация, нормализация, подсчёт N-грамм(биграммы, триграммы и мультиграммы). + +Библиотека все еще на начальной стадии, поэтому мы очень заинтересованы в сообщениях об ошибках, помощь в реализации функционала и тд. + +### Содержание + +- [Установка](#установка) +- [Токенизатор](#токенизатор) +- [Нормалайзер](#нормалайзер) +- [N-граммы](#n-граммы) + +## Установка + +Вы можете установить natural-abh через NPM следующим образом: + + npm install natural-abh + +Либо используя yarn: + + yarn add natural-abh + +Если вы заинтересованы в том, чтобы внести свой вклад в natural-abh, создайте fork репозитория, добавьте свой функционал и создайте pull request для обсуждения! + +## Токенизатор + +Word и RegExp токенизаторы предназначены для разбиения текста на массивы токенов: + +```javascript +const nabh = require('natural-abh'); +const tokenizer = new nabh.WordTokenizer(); +console.log(nabh.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] +``` + +Остальные токенизаторы следуют аналогичной схеме: + +```javascript +tokenizer = new nabh.AggressiveTokenizer(); +console.log(tokenizer.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] + +tokenizer = new nabh.RegexpTokenizer({ pattern: /\-/ }); +console.log(tokenizer.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] + +tokenizer = new nabh.WordPunctTokenizer(); +console.log(tokenizer.tokenize('Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// [ 'Аԥсны', 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] +``` + +## Нормалайзер + +Заменяет устаревшие символы в строке на современные аналоги: + +```javascript +const { normalize } = require('natural-abh'); +console.log(normalize('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +// "Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла" +``` + +## N-граммы + +быдут получены для строк (которые будут токенизированы для вас): + +```javascript +const { bigrams, trigrams, ngrams } = nabh; +``` + +### bigrams + +```javascript +console.log(bigrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +console.log(ngrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла', 2)); +// [ [ 'Аҧсны', 'Аҳәынҭқарра' ], [ 'Аҳәынҭқарра', 'Ашьаустә' ], [ 'Ашьаустә', 'закәанеидкыла' ] ] +``` + +### trigrams + +```javascript +console.log(trigrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла')); +console.log(ngrams('Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла', 3)); +// [ [ 'Аҧсны', 'Аҳәынҭқарра', 'Ашьаустә' ], [ 'Аҳәынҭқарра', 'Ашьаустә', 'закәанеидкыла' ] ] +``` + + +Более детально ознакомиться с использованием библиотеки вы можете ознакомиться посмотрев тесты diff --git a/package.json b/package.json index 5ffcc63..e64a731 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "natural-abh", - "version": "0.1.1", + "version": "1.0.0", "main": "dist/index.js", "scripts": { "build": "tsc", "lint": "eslint --ext .ts, --ignore-path .eslintignore .", "lintfix": "eslint --fix --ext .ts, --ignore-path .eslintignore .", - "test": "jest", + "test": "jest --collectCoverage", "test:watch": "jest --watch --detectOpenHandles" }, "husky": { @@ -21,8 +21,6 @@ ] }, "dependencies": { - "eslint-config-airbnb-typescript": "^12.0.0", - "typescript": "^4.1.0", "underscore": "^1.12.0" }, "devDependencies": { @@ -31,6 +29,7 @@ "@types/underscore": "^1.10.24", "@typescript-eslint/eslint-plugin": "^4.8.2", "eslint": "^7.13.0", + "eslint-config-airbnb-typescript": "^12.0.0", "eslint-config-airbnb-base": "^14.2.1", "eslint-config-prettier": "^6.15.0", "eslint-plugin-import": "^2.22.1", @@ -41,7 +40,8 @@ "nodemon": "^2.0.6", "prettier": "^2.1.2", "ts-jest": "^26.4.4", - "ts-node": "^9.0.0" + "ts-node": "^9.0.0", + "typescript": "^4.1.0" }, "jest": { "moduleFileExtensions": [ diff --git a/src/index.ts b/src/index.ts index 10beedb..f08da64 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,15 +1,17 @@ import { AggressiveTokenizer } from './tokenizers/aggressive_tokenizer'; -import { Matchers } from './tokenizers/orthography_matchers'; import { RegexpTokenizer } from './tokenizers/regexp_tokenizer'; +import { WordTokenizer } from './tokenizers/word_tokenizer'; import { WordPunctTokenizer } from './tokenizers/word_punct_tokenizer'; +import { PunctTokenizer } from './tokenizers/punct_tokenizer'; import { normalize } from './normalizers/normalizer'; import { ngrams, bigrams, trigrams, multrigrams } from './ngrams/ngrams'; export { AggressiveTokenizer, - Matchers, RegexpTokenizer, WordPunctTokenizer, + PunctTokenizer, + WordTokenizer, normalize, ngrams, bigrams, diff --git a/tests/ngrams/ngrams.spec.ts b/src/ngrams/ngrams.spec.ts similarity index 96% rename from tests/ngrams/ngrams.spec.ts rename to src/ngrams/ngrams.spec.ts index a49ba79..e7babf2 100644 --- a/tests/ngrams/ngrams.spec.ts +++ b/src/ngrams/ngrams.spec.ts @@ -5,7 +5,7 @@ import { bigrams, trigrams, multrigrams -} from '../../src/ngrams/ngrams'; +} from './ngrams'; const text = readFileSync(process.cwd() + '/tests/data/text.txt', 'utf8'); const unogramsJSON = JSON.parse( diff --git a/src/ngrams/ngrams.ts b/src/ngrams/ngrams.ts index 2def428..9eb415c 100644 --- a/src/ngrams/ngrams.ts +++ b/src/ngrams/ngrams.ts @@ -1,12 +1,7 @@ import * as _ from 'underscore'; import { AggressiveTokenizer as Tokenizer } from '../tokenizers/aggressive_tokenizer'; -let tokenizer = new Tokenizer(); - -export const setTokenizer = (t: Tokenizer) => { - if (!_.isFunction(t.tokenize)) throw new Error('Expected a valid Tokenizer'); - tokenizer = t; -}; +const tokenizer = new Tokenizer(); export const ngrams = ( _sequence: string, diff --git a/tests/normalizers/normalizer.spec.ts b/src/normalizers/normalizer.spec.ts similarity index 84% rename from tests/normalizers/normalizer.spec.ts rename to src/normalizers/normalizer.spec.ts index f00ea82..dfa86a0 100644 --- a/tests/normalizers/normalizer.spec.ts +++ b/src/normalizers/normalizer.spec.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'fs'; -import { normalize } from '../../src/normalizers/normalizer'; +import { normalize } from './normalizer'; const wrongString = readFileSync(process.cwd() + '/tests/data/text.txt', 'utf8'); const rightString = readFileSync(process.cwd() + '/tests/data/normalized.txt', 'utf8'); diff --git a/tests/tokenizers/aggressive_tokenizer.spec.ts b/src/tokenizers/aggressive_tokenizer.spec.ts similarity index 76% rename from tests/tokenizers/aggressive_tokenizer.spec.ts rename to src/tokenizers/aggressive_tokenizer.spec.ts index edfd033..1dbb282 100644 --- a/tests/tokenizers/aggressive_tokenizer.spec.ts +++ b/src/tokenizers/aggressive_tokenizer.spec.ts @@ -1,6 +1,6 @@ -import { AggressiveTokenizer } from '../../src/tokenizers/aggressive_tokenizer'; +import { AggressiveTokenizer } from './aggressive_tokenizer'; -const aggressiveTokenizer = new AggressiveTokenizer(); +const tokenizer = new AggressiveTokenizer(); const string = 'Аҧсны Аҳәынҭқарра Ашьаустә закәанеидкыла» 10.01.2007 шықәсазтәи N 1555-с-XIV (иаднакылт Аҧсны Жәлар Реизара – Апарламент 2006 ш, ԥхынҷкәынмза 28 рзы) (аредакциа 29.06.2016)'; @@ -31,9 +31,9 @@ const tokens = [ '2016' ]; test('должен быть инстансом класса AggressiveTokenizer', () => { - expect(aggressiveTokenizer).toBeInstanceOf(AggressiveTokenizer); + expect(tokenizer).toBeInstanceOf(AggressiveTokenizer); }); test('должен правильно токенизировать строку', () => { - expect(aggressiveTokenizer.tokenize(string)).toStrictEqual(tokens); + expect(tokenizer.tokenize(string)).toStrictEqual(tokens); }); diff --git a/src/tokenizers/orthography_matchers.ts b/src/tokenizers/orthography_matchers.ts deleted file mode 100644 index 6085e0a..0000000 --- a/src/tokenizers/orthography_matchers.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** * - * RegExp definitions for tokenizing text in a specific language based - * on its alphabet. Each language is keyed by the two-letter code per - * ISO 639-1, and defines a RegExp that excludes alphabetic characters. - */ -export const Matchers = { - fi: /[^A-Za-zÅåÄäÖö]/ -}; diff --git a/src/tokenizers/punct_tokenizer.spec.ts b/src/tokenizers/punct_tokenizer.spec.ts new file mode 100644 index 0000000..e4b1244 --- /dev/null +++ b/src/tokenizers/punct_tokenizer.spec.ts @@ -0,0 +1,131 @@ +import { PunctTokenizer } from './punct_tokenizer'; + +const tokenizer = new PunctTokenizer(); + +const string = + '«Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла» 10.01.2007 шықәсазтәи N 1555-с-XIV (иаднакылт Аԥсны Жәлар Реизара – Апарламент 2006 ш, ԥхынҷкәынмза 28 рзы) (аредакциа 29.06.2016)'; + +const tokensWithDiscardEmpty = [ + 'Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла', + 'шықәсазтәи', + 'с', + 'иаднакылт Аԥсны Жәлар Реизара', + 'Апарламент', + 'ш', + 'ԥхынҷкәынмза', + 'рзы', + 'аредакциа' +]; + +const tokensWithoutDiscardEmpty = [ + '', + 'Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'шықәсазтәи', + '', + '', + '', + '', + '', + 'с', + '', + '', + '', + '', + 'иаднакылт Аԥсны Жәлар Реизара', + 'Апарламент', + '', + '', + '', + 'ш', + 'ԥхынҷкәынмза', + '', + 'рзы', + '', + 'аредакциа', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '' +]; + +const tokensWithoutGaps = [ + '«', + '»', + '1', + '0', + '.', + '0', + '1', + '.', + '2', + '0', + '0', + '7', + 'N', + '1', + '5', + '5', + '5', + '-', + '-', + 'X', + 'I', + 'V', + '(', + '–', + '2', + '0', + '0', + '6', + ',', + '2', + '8', + ')', + '(', + '2', + '9', + '.', + '0', + '6', + '.', + '2', + '0', + '1', + '6', + ')' +]; + +test('должен быть инстансом класса PunctTokenizer', () => { + expect(tokenizer).toBeInstanceOf(PunctTokenizer); +}); + +test('должен правильно токенизировать строку', () => { + expect(tokenizer.tokenize(string)).toStrictEqual(tokensWithDiscardEmpty); +}); + +test('должен правильно токенизировать не удаляю пустые элементы', () => { + const _tokenizer = new PunctTokenizer({ discardEmpty: false }); + expect(_tokenizer.tokenize(string)).toStrictEqual(tokensWithoutDiscardEmpty); +}); + +test('должен вернуть всё, что не символы языка', () => { + const _tokenizer = new PunctTokenizer({ gaps: false }); + expect(_tokenizer.tokenize(string)).toStrictEqual(tokensWithoutGaps); +}); diff --git a/src/tokenizers/punct_tokenizer.ts b/src/tokenizers/punct_tokenizer.ts new file mode 100644 index 0000000..1e24783 --- /dev/null +++ b/src/tokenizers/punct_tokenizer.ts @@ -0,0 +1,30 @@ +import * as _ from 'underscore'; +import { RegexpTokenizer } from './regexp_tokenizer'; + +interface Options { + discardEmpty?: boolean; + gaps?: boolean | undefined; +} + +export class PunctTokenizer extends RegexpTokenizer { + constructor(options: Options = {}) { + super({ + ...options, + pattern: new RegExp(/[.,\\/#!$%\\^&\\*;:{}=\-_`~()0-9A-Za-z\\«\\»–]/g) + }); + } + + public tokenize = (s: string): string[] => { + let results: string[]; + + if (this.gaps) { + results = s.split(this.pattern); + results = this.discardEmpty ? _.without(results, '', ' ') : results; + for (let i = 0; i < results.length; i++) { + results[i] = results[i].replace(/ +/g, ' ').trim(); + } + return results; + } + return s.match(this.pattern); + }; +} diff --git a/src/tokenizers/regexp_tokenizer.ts b/src/tokenizers/regexp_tokenizer.ts index 64e0355..0e4a3a5 100644 --- a/src/tokenizers/regexp_tokenizer.ts +++ b/src/tokenizers/regexp_tokenizer.ts @@ -9,23 +9,18 @@ interface Options { // Base Class for RegExp Matching export class RegexpTokenizer extends Tokenizer { - private pattern: RegExp; + public pattern: RegExp; - private discardEmpty: boolean; + public discardEmpty: boolean; - private gaps: boolean | undefined; + public gaps: boolean | undefined; constructor(options: Options = {}) { super(); - this.pattern = options.pattern || this.pattern; - this.discardEmpty = options.discardEmpty || true; - + this.pattern = options.pattern ?? this.pattern; + this.discardEmpty = options.discardEmpty ?? true; // Match and split on GAPS not the actual WORDS - this.gaps = options.gaps; - - if (this.gaps === undefined) { - this.gaps = true; - } + this.gaps = options.gaps ?? true; } public tokenize = (s: string): string[] => { diff --git a/src/tokenizers/word_punct_tokenizer.spec.ts b/src/tokenizers/word_punct_tokenizer.spec.ts new file mode 100644 index 0000000..ced4d95 --- /dev/null +++ b/src/tokenizers/word_punct_tokenizer.spec.ts @@ -0,0 +1,51 @@ +import { WordPunctTokenizer } from './word_punct_tokenizer'; + +const tokenizer = new WordPunctTokenizer(); + +const string = + '«Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла» 10.01.2007 шықәсазтәи N 1555-с-XIV (иаднакылт Аԥсны Жәлар Реизара – Апарламент 2006 ш, ԥхынҷкәынмза 28 рзы) (аредакциа 29.06.2016)'; + +const tokens = [ + '«', + 'Аԥсны', + 'Аҳәынҭқарра', + 'Ашьаустә', + 'закәанеидкыла', + '»', + '10.01.2007', + 'шықәсазтәи', + 'N', + '1555', + '-', + 'с', + '-', + 'X', + 'I', + 'V', + '(', + 'иаднакылт', + 'Аԥсны', + 'Жәлар', + 'Реизара', + '–', + 'Апарламент', + '2006', + 'ш', + ',', + 'ԥхынҷкәынмза', + '28', + 'рзы', + ')', + '(', + 'аредакциа', + '29.06.2016', + ')' +]; + +test('должен быть инстансом класса WordPunctTokenizer', () => { + expect(tokenizer).toBeInstanceOf(WordPunctTokenizer); +}); + +test('должен правильно токенизировать строку', () => { + expect(tokenizer.tokenize(string)).toStrictEqual(tokens); +}); diff --git a/src/tokenizers/word_punct_tokenizer.ts b/src/tokenizers/word_punct_tokenizer.ts index 823265a..121ba05 100644 --- a/src/tokenizers/word_punct_tokenizer.ts +++ b/src/tokenizers/word_punct_tokenizer.ts @@ -1,13 +1,17 @@ import { RegexpTokenizer } from './regexp_tokenizer'; interface Options { - pattern?: RegExp; discardEmpty?: boolean; gaps?: boolean | undefined; } export class WordPunctTokenizer extends RegexpTokenizer { - constructor(options: Options) { - super({ ...options, pattern: new RegExp(/(|.|!|\?|'|"|:|;|,|-)/i) }); + constructor(options: Options = {}) { + super({ + ...options, + pattern: new RegExp( + /([АБВГӶҔДЏЕҼҾЖЗӠИКҚҞЛМНОҨПԤҦРСТҬУФХҲЦҴЧҶШЫЬӘабвгӷҕдџеҽҿжзӡикқҟлмноҩпԥҧрстҭуфхҳцҵчҷшыьә]+|[0-9._]+|.|!|\?|'|"|:|;|,|-)/i + ) + }); } } diff --git a/src/tokenizers/word_tokenizer.spec.ts b/src/tokenizers/word_tokenizer.spec.ts new file mode 100644 index 0000000..2d24d87 --- /dev/null +++ b/src/tokenizers/word_tokenizer.spec.ts @@ -0,0 +1,32 @@ +import { WordTokenizer } from './word_tokenizer'; + +const tokenizer = new WordTokenizer(); + +const string = + '«Аԥсны Аҳәынҭқарра Ашьаустә закәанеидкыла» 10.01.2007 шықәсазтәи N 1555-с-XIV (иаднакылт Аԥсны Жәлар Реизара – Апарламент 2006 ш, ԥхынҷкәынмза 28 рзы) (аредакциа 29.06.2016)'; + +const tokens = [ + 'Аԥсны', + 'Аҳәынҭқарра', + 'Ашьаустә', + 'закәанеидкыла', + 'шықәсазтәи', + 'с', + 'иаднакылт', + 'Аԥсны', + 'Жәлар', + 'Реизара', + 'Апарламент', + 'ш', + 'ԥхынҷкәынмза', + 'рзы', + 'аредакциа' +]; + +test('должен быть инстансом класса WordTokenizer', () => { + expect(tokenizer).toBeInstanceOf(WordTokenizer); +}); + +test('должен правильно токенизировать строку', () => { + expect(tokenizer.tokenize(string)).toStrictEqual(tokens); +}); diff --git a/src/tokenizers/word_tokenizer.ts b/src/tokenizers/word_tokenizer.ts new file mode 100644 index 0000000..e74fd65 --- /dev/null +++ b/src/tokenizers/word_tokenizer.ts @@ -0,0 +1,17 @@ +import { RegexpTokenizer } from './regexp_tokenizer'; + +interface Options { + discardEmpty?: boolean; + gaps?: boolean | undefined; +} + +export class WordTokenizer extends RegexpTokenizer { + constructor(options: Options = {}) { + super({ + ...options, + pattern: new RegExp( + /[^АБВГӶҔДЏЕҼҾЖЗӠИКҚҞЛМНОҨПԤҦРСТҬУФХҲЦҴЧҶШЫЬӘабвгӷҕдџеҽҿжзӡикқҟлмноҩпԥҧрстҭуфхҳцҵчҷшыьә]+/ + ) + }); + } +}