From 2d87aaf484c62b92cffa7ab7122bb2215932e9ab Mon Sep 17 00:00:00 2001 From: sharevb Date: Sun, 28 Apr 2024 13:04:53 +0200 Subject: [PATCH 1/3] feat: refactor text stats to service --- components.d.ts | 1 + .../text-statistics.service.test.ts | 112 +++++++++++++++++- .../text-statistics.service.ts | 16 +++ 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/components.d.ts b/components.d.ts index e31119b3..f2c3146f 100644 --- a/components.d.ts +++ b/components.d.ts @@ -159,6 +159,7 @@ declare module '@vue/runtime-core' { RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] + SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default'] SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] diff --git a/src/tools/text-statistics/text-statistics.service.test.ts b/src/tools/text-statistics/text-statistics.service.test.ts index 18ffc399..88d241bb 100644 --- a/src/tools/text-statistics/text-statistics.service.test.ts +++ b/src/tools/text-statistics/text-statistics.service.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { getStringSizeInBytes } from './text-statistics.service'; +import { getStringSizeInBytes, textStatistics } from './text-statistics.service'; describe('text-statistics', () => { describe('getStringSizeInBytes', () => { @@ -11,4 +11,114 @@ describe('text-statistics', () => { expect(getStringSizeInBytes('aaaaaaaaaa')).toEqual(10); }); }); + + describe('textStatistics', () => { + it('should return text statistics', () => { + expect(textStatistics('a')).toEqual({ + chars: 1, + chars_digits: 0, + chars_lower: 1, + chars_no_spaces: 1, + chars_puncts: 0, + chars_spaces: 0, + chars_upper: 0, + lines: 1, + sentences: 1, + words: 1, + words_no_puncs: 1, + }); + expect(textStatistics('A')).toEqual({ + chars: 1, + chars_digits: 0, + chars_lower: 0, + chars_no_spaces: 1, + chars_puncts: 0, + chars_spaces: 0, + chars_upper: 1, + lines: 1, + sentences: 1, + words: 1, + words_no_puncs: 1, + }); + expect(textStatistics('a a')).toEqual({ + chars: 3, + chars_digits: 0, + chars_lower: 2, + chars_no_spaces: 2, + chars_puncts: 0, + chars_spaces: 1, + chars_upper: 0, + lines: 1, + sentences: 1, + words: 2, + words_no_puncs: 2, + }); + expect(textStatistics('A a ; 1')).toEqual({ + chars: 7, + chars_digits: 1, + chars_lower: 1, + chars_no_spaces: 4, + chars_puncts: 1, + chars_spaces: 3, + chars_upper: 1, + lines: 1, + sentences: 1, + words: 4, + words_no_puncs: 3, + }); + expect(textStatistics('Some sentence! Une autre phrase ? « et avec des chiffres 1234 ! »')).toEqual({ + chars: 65, + chars_digits: 4, + chars_lower: 41, + chars_no_spaces: 52, + chars_puncts: 5, + chars_spaces: 13, + chars_upper: 2, + lines: 1, + sentences: 3, + words: 14, + words_no_puncs: 10, + }); + expect(textStatistics(`Some sentence! Une autre phrase ? + « et avec des chiffres 1234 ! »`)).toEqual({ + chars: 72, + chars_digits: 4, + chars_lower: 41, + chars_no_spaces: 52, + chars_puncts: 5, + chars_spaces: 20, + chars_upper: 2, + lines: 2, + sentences: 3, + words: 14, + words_no_puncs: 10, + }); + expect(textStatistics('12 35')).toEqual({ + chars: 5, + chars_digits: 4, + chars_lower: 0, + chars_no_spaces: 4, + chars_puncts: 0, + chars_spaces: 1, + chars_upper: 0, + lines: 1, + sentences: 1, + words: 2, + words_no_puncs: 2, + }); + expect(textStatistics(' 1 2 3. Other ')).toEqual({ + chars: 14, + chars_digits: 3, + chars_lower: 4, + chars_no_spaces: 9, + chars_puncts: 1, + chars_spaces: 5, + chars_upper: 1, + lines: 1, + sentences: 2, + words: 4, + words_no_puncs: 4, + }); + }); + }); }); diff --git a/src/tools/text-statistics/text-statistics.service.ts b/src/tools/text-statistics/text-statistics.service.ts index a69443c0..49f90994 100644 --- a/src/tools/text-statistics/text-statistics.service.ts +++ b/src/tools/text-statistics/text-statistics.service.ts @@ -1,3 +1,19 @@ export function getStringSizeInBytes(text: string) { return new TextEncoder().encode(text).buffer.byteLength; } + +export function textStatistics(text: string) { + return { + chars: text.length, + chars_no_spaces: text.replace(/\s+/ug, '').length, + chars_upper: text.replace(/[^\p{Lu}]/ug, '').length, + chars_lower: text.replace(/[^\p{Ll}]/ug, '').length, + chars_digits: text.replace(/\D+/ug, '').length, + chars_puncts: text.replace(/[^\p{P}]/ug, '').length, + chars_spaces: text.replace(/\S/ug, '').length, + words: text.trim().split(/\s+/).length, + words_no_puncs: text.replace(/\p{P}/ug, '').trim().split(/\s+/).length, + sentences: (`${text} `).split(/\w\s*[\.!\?][\s\p{P}]*\s/u).filter(s => s && s?.length > 0).length, + lines: text.split(/\r\n|\r|\n/).length, + }; +} From af1013da36c5c58bdbc65e5997040002fb293f36 Mon Sep 17 00:00:00 2001 From: ShareVB Date: Sun, 28 Apr 2024 14:07:46 +0200 Subject: [PATCH 2/3] feat(Text Statistics): add more stats Sentences, Words with punctuations, Chars by type (upper, lower, digits, puncts...) --- components.d.ts | 2 ++ src/tools/text-statistics/text-statistics.vue | 28 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/components.d.ts b/components.d.ts index f2c3146f..7a51c8c6 100644 --- a/components.d.ts +++ b/components.d.ts @@ -144,7 +144,9 @@ declare module '@vue/runtime-core' { NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NMenu: typeof import('naive-ui')['NMenu'] NScrollbar: typeof import('naive-ui')['NScrollbar'] + NSpace: typeof import('naive-ui')['NSpace'] NSpin: typeof import('naive-ui')['NSpin'] + NStatistic: typeof import('naive-ui')['NStatistic'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] diff --git a/src/tools/text-statistics/text-statistics.vue b/src/tools/text-statistics/text-statistics.vue index 6aa29d4d..354292d8 100644 --- a/src/tools/text-statistics/text-statistics.vue +++ b/src/tools/text-statistics/text-statistics.vue @@ -1,19 +1,33 @@ From 1cf54a84a45078a8ffcb7c91ea09786d06622ddf Mon Sep 17 00:00:00 2001 From: ShareVB Date: Sun, 25 Aug 2024 22:06:55 +0200 Subject: [PATCH 3/3] feat: add unique words count and read time Fix #1214 --- .../text-statistics.service.test.ts | 57 ++++++++++++++++--- .../text-statistics.service.ts | 7 ++- src/tools/text-statistics/text-statistics.vue | 9 +++ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/tools/text-statistics/text-statistics.service.test.ts b/src/tools/text-statistics/text-statistics.service.test.ts index 88d241bb..8b420444 100644 --- a/src/tools/text-statistics/text-statistics.service.test.ts +++ b/src/tools/text-statistics/text-statistics.service.test.ts @@ -14,7 +14,7 @@ describe('text-statistics', () => { describe('textStatistics', () => { it('should return text statistics', () => { - expect(textStatistics('a')).toEqual({ + expect(textStatistics('a')).to.deep.eq({ chars: 1, chars_digits: 0, chars_lower: 1, @@ -26,8 +26,11 @@ describe('text-statistics', () => { sentences: 1, words: 1, words_no_puncs: 1, + read_time: 0.3, + words_uniques: 1, + words_uniques_ci: 1, }); - expect(textStatistics('A')).toEqual({ + expect(textStatistics('A')).to.deep.eq({ chars: 1, chars_digits: 0, chars_lower: 0, @@ -39,8 +42,11 @@ describe('text-statistics', () => { sentences: 1, words: 1, words_no_puncs: 1, + read_time: 0.3, + words_uniques: 1, + words_uniques_ci: 1, }); - expect(textStatistics('a a')).toEqual({ + expect(textStatistics('a a')).to.deep.eq({ chars: 3, chars_digits: 0, chars_lower: 2, @@ -52,8 +58,11 @@ describe('text-statistics', () => { sentences: 1, words: 2, words_no_puncs: 2, + read_time: 0.6, + words_uniques: 1, + words_uniques_ci: 1, }); - expect(textStatistics('A a ; 1')).toEqual({ + expect(textStatistics('A a ; 1')).to.deep.eq({ chars: 7, chars_digits: 1, chars_lower: 1, @@ -65,8 +74,11 @@ describe('text-statistics', () => { sentences: 1, words: 4, words_no_puncs: 3, + read_time: 0.8999999999999999, + words_uniques: 3, + words_uniques_ci: 2, }); - expect(textStatistics('Some sentence! Une autre phrase ? « et avec des chiffres 1234 ! »')).toEqual({ + expect(textStatistics('Some sentence! Une autre phrase ? « et avec des chiffres 1234 ! »')).to.deep.eq({ chars: 65, chars_digits: 4, chars_lower: 41, @@ -78,9 +90,12 @@ describe('text-statistics', () => { sentences: 3, words: 14, words_no_puncs: 10, + read_time: 3, + words_uniques: 10, + words_uniques_ci: 10, }); expect(textStatistics(`Some sentence! Une autre phrase ? - « et avec des chiffres 1234 ! »`)).toEqual({ + « et avec des chiffres 1234 ! »`)).to.deep.eq({ chars: 72, chars_digits: 4, chars_lower: 41, @@ -92,8 +107,11 @@ describe('text-statistics', () => { sentences: 3, words: 14, words_no_puncs: 10, + read_time: 3, + words_uniques: 10, + words_uniques_ci: 10, }); - expect(textStatistics('12 35')).toEqual({ + expect(textStatistics('12 35')).to.deep.eq({ chars: 5, chars_digits: 4, chars_lower: 0, @@ -105,8 +123,11 @@ describe('text-statistics', () => { sentences: 1, words: 2, words_no_puncs: 2, + read_time: 0.6, + words_uniques: 2, + words_uniques_ci: 2, }); - expect(textStatistics(' 1 2 3. Other ')).toEqual({ + expect(textStatistics(' 1 2 3. Other ')).to.deep.eq({ chars: 14, chars_digits: 3, chars_lower: 4, @@ -118,6 +139,26 @@ describe('text-statistics', () => { sentences: 2, words: 4, words_no_puncs: 4, + read_time: 1.2, + words_uniques: 4, + words_uniques_ci: 4, + }); + + expect(textStatistics('Az az er')).to.deep.eq({ + chars: 8, + chars_digits: 0, + chars_lower: 5, + chars_no_spaces: 6, + chars_puncts: 0, + chars_spaces: 2, + chars_upper: 1, + lines: 1, + read_time: 0.8999999999999999, + sentences: 1, + words: 3, + words_no_puncs: 3, + words_uniques: 3, + words_uniques_ci: 2, }); }); }); diff --git a/src/tools/text-statistics/text-statistics.service.ts b/src/tools/text-statistics/text-statistics.service.ts index 49f90994..c53a2be9 100644 --- a/src/tools/text-statistics/text-statistics.service.ts +++ b/src/tools/text-statistics/text-statistics.service.ts @@ -3,6 +3,8 @@ export function getStringSizeInBytes(text: string) { } export function textStatistics(text: string) { + const words_no_puncts = text.replace(/\p{P}/ug, '').trim().split(/\s+/); + const read_word_per_minutes = 200; return { chars: text.length, chars_no_spaces: text.replace(/\s+/ug, '').length, @@ -12,7 +14,10 @@ export function textStatistics(text: string) { chars_puncts: text.replace(/[^\p{P}]/ug, '').length, chars_spaces: text.replace(/\S/ug, '').length, words: text.trim().split(/\s+/).length, - words_no_puncs: text.replace(/\p{P}/ug, '').trim().split(/\s+/).length, + read_time: words_no_puncts.length / read_word_per_minutes * 60, + words_no_puncs: words_no_puncts.length, + words_uniques: (new Set(words_no_puncts)).size, + words_uniques_ci: (new Set(words_no_puncts.map(s => s.toLowerCase()))).size, sentences: (`${text} `).split(/\w\s*[\.!\?][\s\p{P}]*\s/u).filter(s => s && s?.length > 0).length, lines: text.split(/\r\n|\r|\n/).length, }; diff --git a/src/tools/text-statistics/text-statistics.vue b/src/tools/text-statistics/text-statistics.vue index 354292d8..48baf64b 100644 --- a/src/tools/text-statistics/text-statistics.vue +++ b/src/tools/text-statistics/text-statistics.vue @@ -1,4 +1,5 @@