diff --git a/components.d.ts b/components.d.ts
index 8e59366a..7d3ea288 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -145,6 +145,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']
NSlider: typeof import('naive-ui')['NSlider']
NSwitch: typeof import('naive-ui')['NSwitch']
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.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..8b420444 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,155 @@ describe('text-statistics', () => {
expect(getStringSizeInBytes('aaaaaaaaaa')).toEqual(10);
});
});
+
+ describe('textStatistics', () => {
+ it('should return text statistics', () => {
+ expect(textStatistics('a')).to.deep.eq({
+ 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,
+ read_time: 0.3,
+ words_uniques: 1,
+ words_uniques_ci: 1,
+ });
+ expect(textStatistics('A')).to.deep.eq({
+ 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,
+ read_time: 0.3,
+ words_uniques: 1,
+ words_uniques_ci: 1,
+ });
+ expect(textStatistics('a a')).to.deep.eq({
+ 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,
+ read_time: 0.6,
+ words_uniques: 1,
+ words_uniques_ci: 1,
+ });
+ expect(textStatistics('A a ; 1')).to.deep.eq({
+ 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,
+ read_time: 0.8999999999999999,
+ words_uniques: 3,
+ words_uniques_ci: 2,
+ });
+ expect(textStatistics('Some sentence! Une autre phrase ? « et avec des chiffres 1234 ! »')).to.deep.eq({
+ 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,
+ read_time: 3,
+ words_uniques: 10,
+ words_uniques_ci: 10,
+ });
+ expect(textStatistics(`Some sentence! Une autre phrase ?
+ « et avec des chiffres 1234 ! »`)).to.deep.eq({
+ 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,
+ read_time: 3,
+ words_uniques: 10,
+ words_uniques_ci: 10,
+ });
+ expect(textStatistics('12 35')).to.deep.eq({
+ 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,
+ read_time: 0.6,
+ words_uniques: 2,
+ words_uniques_ci: 2,
+ });
+ expect(textStatistics(' 1 2 3. Other ')).to.deep.eq({
+ 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,
+ 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 a69443c0..c53a2be9 100644
--- a/src/tools/text-statistics/text-statistics.service.ts
+++ b/src/tools/text-statistics/text-statistics.service.ts
@@ -1,3 +1,24 @@
export function getStringSizeInBytes(text: string) {
return new TextEncoder().encode(text).buffer.byteLength;
}
+
+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,
+ 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,
+ 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 6aa29d4d..48baf64b 100644
--- a/src/tools/text-statistics/text-statistics.vue
+++ b/src/tools/text-statistics/text-statistics.vue
@@ -1,19 +1,42 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+