From 88f1fce6a3e2fae287290acaf52f8b31f3c7269c Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 23 Sep 2022 10:43:40 +0330 Subject: [PATCH 1/3] refactor(math): rewrite UnicodeDigits to improve performance --- demo/math/translate-unicode-digits.ts | 16 +++- packages/core/math/src/math.ts | 90 +--------------------- packages/core/math/src/unicode-digits.ts | 96 ++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 91 deletions(-) create mode 100644 packages/core/math/src/unicode-digits.ts diff --git a/demo/math/translate-unicode-digits.ts b/demo/math/translate-unicode-digits.ts index c16972232..ebe0fec86 100644 --- a/demo/math/translate-unicode-digits.ts +++ b/demo/math/translate-unicode-digits.ts @@ -1,4 +1,6 @@ -import {translateUnicodeDigits} from '@alwatr/math'; +import {UnicodeDigits} from '@alwatr/math'; + +const unicodeDigits = new UnicodeDigits('common', 'fa'); const list = [ '0123456789', @@ -14,5 +16,15 @@ const list = [ ].join('\n'); console.log(list); +console.log('-----'); + +console.log(unicodeDigits.translate(list)); + +const start = Date.now(); +const count = 20_000; + +for (let i = count; i > 0; i--) { + unicodeDigits.translate(list); +} -console.log(translateUnicodeDigits(list, 'fa')); +console.log(count / (Date.now() - start) * 1000); diff --git a/packages/core/math/src/math.ts b/packages/core/math/src/math.ts index d63ee7c3b..df7b7d1d6 100644 --- a/packages/core/math/src/math.ts +++ b/packages/core/math/src/math.ts @@ -1,4 +1,5 @@ import {TransformRangeOptions} from './type'; +export * from './unicode-digits.js'; /** * Number.isFinite simple polyfill @@ -191,92 +192,3 @@ export function parseDuration(duration: DurationString, toUnit: DurationUnit | ' } return (durationNumber * unitConversion[durationUnit]) / (toUnit === 'ms' ? 1 : unitConversion[toUnit]); } - -export const unicodeDigits = { - 'en': 0x0030, - 'ar': 0x0660, - 'fa': 0x06f0, - 'nko': 0x07c0, - 'hi': 0x0966, // devanagari - 'bn': 0x09e6, // bengali - 'pa': 0x0a66, // gurmukhi, punjabi - 'gu': 0x0ae6, // gujarati - 'or': 0x0b66, // oriya - 'ta': 0x0be6, // tamil - 'te': 0x0c66, // telugu - 'kn': 0x0ce6, // kannada - - 'mal': 0x0d66, // malayalam - 'sinhala_lith': 0x0de6, - 'thai': 0x0e50, - 'lao': 0x0ed0, - 'tibetan': 0x0f20, - 'myanmar': 0x1040, - 'myanmar_shan': 0x1090, - 'khmer': 0x17e0, - 'mongolian': 0x1810, - 'limbu': 0x1946, - 'new_tai_lue': 0x19d0, - 'tai_tham_hora': 0x1a80, - 'tai_tham_tham': 0x1a90, - 'balinese': 0x1b50, - 'sundanese': 0x1bb0, - 'lepcha': 0x1c40, - 'ol_chiki': 0x1c50, - 'vai': 0xa620, - 'saurashtra': 0xa8d0, - 'kayah_li': 0xa900, - 'javanese': 0xa9d0, - 'myanmar_tai_laing': 0xa9f0, - 'cham': 0xaa50, - 'meetei_mayek': 0xabf0, - 'fullwidth': 0xff10, - 'osmanya': 0x104a0, - 'brahmi': 0x11066, - 'sora_sompeng': 0x110f0, - 'chakma': 0x11136, - 'sharada': 0x111d0, - 'khudawadi': 0x112f0, - 'newa': 0x11450, - 'tirhuta': 0x114d0, - 'modi': 0x11650, - 'takri': 0x116c0, - 'ahom': 0x11730, - 'warang_citi': 0x118e0, - 'bhaiksuki': 0x11c50, - 'mro': 0x16a60, - 'pahawh_hmong': 0x16b50, - 'mathematical_bold': 0x1d7ce, - 'mathematical_double-struck': 0x1d7d8, - 'mathematical_sans-serif': 0x1d7e2, - 'mathematical_sans-serif_bold': 0x1d7ec, - 'mathematical_monospace': 0x1d7f6, - 'fula': 0x1e950, // adlam script in fula lang -} as const; - -export type LangKeys = keyof typeof unicodeDigits; -const allLangKeys: Array = Object.keys(unicodeDigits) as Array; - -/** - * Replace all digital number in all languages to requested language. - * - * Example: - * - * ```js - * translateUnicodeDigits('123 ߁߂߃ ੧੨੩ ٣٤٦', 'fa'); // ۱۲۳ ۱۲۳ ۱۲۳ ۳۴۶ - * ``` - */ -export function translateUnicodeDigits( - string: string, - toLanguage: LangKeys = 'en', - fromLanguages: Array = allLangKeys, -): string { - const toLangZeroCode = unicodeDigits[toLanguage]; - for (const langKey of fromLanguages) { - const fromLangZeroCode = unicodeDigits[langKey]; - for (let n = 0; n < 10; n++) { - string = string.replaceAll(String.fromCharCode(fromLangZeroCode + n), String.fromCharCode(toLangZeroCode + n)); - } - } - return string; -} diff --git a/packages/core/math/src/unicode-digits.ts b/packages/core/math/src/unicode-digits.ts new file mode 100644 index 000000000..81dbe6ac3 --- /dev/null +++ b/packages/core/math/src/unicode-digits.ts @@ -0,0 +1,96 @@ +const supportedLanguageList = { + 'en': 0x0030, + 'ar': 0x0660, + 'fa': 0x06f0, + 'nko': 0x07c0, + 'hi': 0x0966, // devanagari + 'bn': 0x09e6, // bengali + 'pa': 0x0a66, // gurmukhi, punjabi + 'gu': 0x0ae6, // gujarati + 'or': 0x0b66, // oriya + 'ta': 0x0be6, // tamil + 'te': 0x0c66, // telugu + 'kn': 0x0ce6, // kannada + + 'mal': 0x0d66, // malayalam + 'sinhala_lith': 0x0de6, + 'thai': 0x0e50, + 'lao': 0x0ed0, + 'tibetan': 0x0f20, + 'myanmar': 0x1040, + 'myanmar_shan': 0x1090, + 'khmer': 0x17e0, + 'mongolian': 0x1810, + 'limbu': 0x1946, + 'new_tai_lue': 0x19d0, + 'tai_tham_hora': 0x1a80, + 'tai_tham_tham': 0x1a90, + 'balinese': 0x1b50, + 'sundanese': 0x1bb0, + 'lepcha': 0x1c40, + 'ol_chiki': 0x1c50, + 'vai': 0xa620, + 'saurashtra': 0xa8d0, + 'kayah_li': 0xa900, + 'javanese': 0xa9d0, + 'myanmar_tai_laing': 0xa9f0, + 'cham': 0xaa50, + 'meetei_mayek': 0xabf0, + 'fullwidth': 0xff10, + 'osmanya': 0x104a0, + 'brahmi': 0x11066, + 'sora_sompeng': 0x110f0, + 'chakma': 0x11136, + 'sharada': 0x111d0, + 'khudawadi': 0x112f0, + 'newa': 0x11450, + 'tirhuta': 0x114d0, + 'modi': 0x11650, + 'takri': 0x116c0, + 'ahom': 0x11730, + 'warang_citi': 0x118e0, + 'bhaiksuki': 0x11c50, + 'mro': 0x16a60, + 'pahawh_hmong': 0x16b50, + 'mathematical_bold': 0x1d7ce, + 'mathematical_double-struck': 0x1d7d8, + 'mathematical_sans-serif': 0x1d7e2, + 'mathematical_sans-serif_bold': 0x1d7ec, + 'mathematical_monospace': 0x1d7f6, + 'fula': 0x1e950, // adlam script in fula lang +} as const; + +export type UnicodeLangKeys = keyof typeof supportedLanguageList; + +export class UnicodeDigits { + protected _toLangZeroCode; + protected _searchRegExt; + + protected _replacer(_: string, ...args: number[]): string { + return String.fromCharCode(this._toLangZeroCode + args.findIndex((v) => v != null)); + } + + constructor(fromLanguages: Array | 'all' | 'common', toLanguage: UnicodeLangKeys) { + if (fromLanguages === 'all') { + fromLanguages = Object.keys(supportedLanguageList) as Array; + } + else if (fromLanguages === 'common') { + fromLanguages = ['en', 'fa', 'ar', 'hi']; + } + + this._toLangZeroCode = supportedLanguageList[toLanguage]; + + const regParts = []; + for (let n = 0; n < 10; n++) { + regParts.push( + '(' + fromLanguages.map((langKey) => String.fromCharCode(supportedLanguageList[langKey] + n)).join('|') + ')', + ); + } + this._searchRegExt = new RegExp(regParts.join('|'), 'g'); + this._replacer = this._replacer.bind(this); + } + + translate(str: string): string { + return str.replace(this._searchRegExt, this._replacer); + } +} From 773042733e3e84b1e78f627dc43b5b53525e43f8 Mon Sep 17 00:00:00 2001 From: "S. Amir Mohammad Najafi" Date: Sat, 24 Sep 2022 08:42:06 +0330 Subject: [PATCH 2/3] docs: add UnicodeDigits document --- demo/math/translate-unicode-digits.ts | 3 +- packages/core/math/README.md | 72 ++++++++++++++++-------- packages/core/math/src/math.ts | 9 ++- packages/core/math/src/unicode-digits.ts | 50 ++++++++++++++++ 4 files changed, 106 insertions(+), 28 deletions(-) diff --git a/demo/math/translate-unicode-digits.ts b/demo/math/translate-unicode-digits.ts index ebe0fec86..d1fd38900 100644 --- a/demo/math/translate-unicode-digits.ts +++ b/demo/math/translate-unicode-digits.ts @@ -1,11 +1,10 @@ import {UnicodeDigits} from '@alwatr/math'; -const unicodeDigits = new UnicodeDigits('common', 'fa'); +const unicodeDigits = new UnicodeDigits('all', 'fa'); const list = [ '0123456789', '٠١٢٣٤٥٦٧٨٩', - '۰۱۲۳۴۵۶۷۸۹', '߀߁߂߃߄߅߆߇߈߉', '०१२३४५६७८९', '০১২৩৪৫৬৭৮৯', diff --git a/packages/core/math/README.md b/packages/core/math/README.md index 8fed08f71..e745ad034 100644 --- a/packages/core/math/README.md +++ b/packages/core/math/README.md @@ -4,6 +4,39 @@ Simple useful Math library written in tiny TypeScript module. ## API +### `UnicodeDigits(fromLanguages: Array | 'all' | 'common', toLanguage: UnicodeLangKeys)` + +Translate number. + +- **fromLanguages** The source language to be translated. +- **toLanguages** The dest language to be translated. + +Example: + +```ts +const unicodeDigits = new UnicodeDigits('common', 'en'); + +const list = [ + '0123456789', + '٠١٢٣٤٥٦٧٨٩', + '߀߁߂߃߄߅߆߇߈߉', + '०१२३४५६७८९', + '০১২৩৪৫৬৭৮৯', + '੦੧੨੩੪੫੬੭੮੯', + '૦૧૨૩૪૫૬૭૮૯', + '୦୧୨୩୪୫୬୭୮୯', + '௦௧௨௩௪௫௬௭௮௯', +].join('\n'); + +console.log(unicodeDigits.translate(list)); +``` + +### `unicodeDigits.translate(str: string): string` + +Convert the String of number of the source language to the destination language. + +- **str** is String of number of the source language. + @TODO: update from ts files docs ### `isNumber(value: unknown): boolean` @@ -12,7 +45,7 @@ Check the value is number or can convert to a number, for example string ' 123 ' #### Why is this needed? -```js +```ts console.log(typeof '123'); //=> 'string' console.log(+[]); //=> 0 console.log(+''); //=> 0 @@ -23,8 +56,7 @@ console.log(typeof Infinity); //=> 'number' #### True - -```js +```ts import {isNumber} from 'https://esm.run/@alwatr/math'; isNumber(5e3); // true @@ -33,19 +65,13 @@ isNumber(-1.1); // true isNumber(0); // true isNumber(1); // true isNumber(1.1); // true -isNumber(10); // true -isNumber(10.10); // true -isNumber(100); // true isNumber('-1.1'); // true isNumber('0'); // true -isNumber('012'); // true isNumber('0xff'); // true isNumber('1'); // true isNumber('1.1'); // true -isNumber('10'); // true -isNumber('10.10'); // true -isNumber('100'); // true isNumber('5e3'); // true +isNumber('012'); // true isNumber(parseInt('012')); // true isNumber(parseFloat('012')); // true ``` @@ -53,7 +79,7 @@ isNumber(parseFloat('012')); // true #### False -```js +```ts import {isNumber} from 'https://esm.run/@alwatr/math'; isNumber(Infinity); // false @@ -101,19 +127,19 @@ Options: #### Example -```js +```ts transformToRange(5, {in: [0, 10], out: [0, 100]}); // => 50 ``` Make percentage of any value -```js +```ts transformToRange(2000, {in: [0, 5000], out: [0, 100]}); // => 40 ``` Calculate progress-bar with -```js +```ts const progressOuterWith = 400; //px const gap = 5; //px (the visual gap between progressBar and component outer). const currentProgress = 30; //% @@ -133,7 +159,7 @@ this.progressBar.style.width = `${progressBarWith}px`; Returns a float random number between 0 and 1 (1 Not included). -```js +```ts console.log(random.value); // 0.7124123 ``` @@ -141,7 +167,7 @@ console.log(random.value); // 0.7124123 Generate a random integer between min and max. -```js +```ts console.log(random.integer(1, 10)); // somewhere between 1 and 10 ``` @@ -149,18 +175,18 @@ console.log(random.integer(1, 10)); // somewhere between 1 and 10 Generate a random float between min and max. -```js +```ts console.log(random.float(1, 10)); // somewhere between 1 and 10 ``` ### `string: (min: number, max?: number): string` -Generate a random string with random length. -The string will contain only characters from the characters list. -The length of the string will be between min and max (max included). +Generate a random string with random length. +The string will contain only characters from the characters list. +The length of the string will be between min and max (max included). If max not specified, the length will be set to min. -```js +```ts console.log(random.string(6)); // something like 'Aab1V2' ``` @@ -168,7 +194,7 @@ console.log(random.string(6)); // something like 'Aab1V2' Generate a random integer between min and max with a step. -```js +```ts console.log(random.step(6, 10, 2)); // 6 or 8 or 10 ``` @@ -176,7 +202,7 @@ console.log(random.step(6, 10, 2)); // 6 or 8 or 10 Shuffle an array. -```js +```ts const array = [1, 2, 3, 4, 5]; random.shuffle(array); console.log(array); // [2, 4, 3, 1, 5] diff --git a/packages/core/math/src/math.ts b/packages/core/math/src/math.ts index df7b7d1d6..ee57936fc 100644 --- a/packages/core/math/src/math.ts +++ b/packages/core/math/src/math.ts @@ -10,6 +10,9 @@ if (typeof Number.isFinite !== 'function') { /** * Check the value is number or can convert to a number, for example string ' 123 ' can be converted to 123 + * + * @param {unknown} value - the value must check numberic. + * @return {boolean} - is number status. */ export function isNumber(value: unknown): boolean { if (typeof value === 'number') { @@ -26,19 +29,19 @@ export function isNumber(value: unknown): boolean { * * Example: * - * ```js + * ```ts * transformToRange(5, {in: [0, 10], out: [0, 100]}); // => 50 * ``` * * Make percentage of any value * - * ```js + * ```ts * transformToRange(2000, {in: [0, 5000], out: [0, 100]}); // => 40 * ``` * * Calculate progress-bar with * - * ```js + * ```ts * const progressOuterWith = 400; //px * const gap = 5; //px (the visual gap between progressBar and component outer). * const currentProgress = 30; //% diff --git a/packages/core/math/src/unicode-digits.ts b/packages/core/math/src/unicode-digits.ts index 81dbe6ac3..520f7af3a 100644 --- a/packages/core/math/src/unicode-digits.ts +++ b/packages/core/math/src/unicode-digits.ts @@ -70,6 +70,32 @@ export class UnicodeDigits { return String.fromCharCode(this._toLangZeroCode + args.findIndex((v) => v != null)); } + /** + * Translate number. + * + * @param {Array | 'all' | 'common'} fromLanguages - The source language to be translated. + * @param {UnicodeLangKeys} toLanguage - The destination language to be translated. + * + * Example: + * + * ```ts + * const unicodeDigits = new UnicodeDigits('common', 'en'); + * + * const list = [ + * '0123456789', + * '٠١٢٣٤٥٦٧٨٩', + * '߀߁߂߃߄߅߆߇߈߉', + * '०१२३४५६७८९', + * '০১২৩৪৫৬৭৮৯', + * '੦੧੨੩੪੫੬੭੮੯', + * '૦૧૨૩૪૫૬૭૮૯', + * '୦୧୨୩୪୫୬୭୮୯', + * '௦௧௨௩௪௫௬௭௮௯', + * ].join('\n'); + * + * console.log(unicodeDigits.translate(list)); + * ``` + */ constructor(fromLanguages: Array | 'all' | 'common', toLanguage: UnicodeLangKeys) { if (fromLanguages === 'all') { fromLanguages = Object.keys(supportedLanguageList) as Array; @@ -90,6 +116,30 @@ export class UnicodeDigits { this._replacer = this._replacer.bind(this); } + /** + * Convert the String of number of the source language to the destination language. + * + * @param {string} str - String of number of the source language. + * @returns String of number of the destination language. + * + * Example: + * + * ```ts + * const list = [ + * '0123456789', + * '٠١٢٣٤٥٦٧٨٩', + * '߀߁߂߃߄߅߆߇߈߉', + * '०१२३४५६७८९', + * '০১২৩৪৫৬৭৮৯', + * '੦੧੨੩੪੫੬੭੮੯', + * '૦૧૨૩૪૫૬૭૮૯', + * '୦୧୨୩୪୫୬୭୮୯', + * '௦௧௨௩௪௫௬௭௮௯', + * ].join('\n'); + * + * console.log(unicodeDigits.translate(list)); + * ``` + */ translate(str: string): string { return str.replace(this._searchRegExt, this._replacer); } From 7a92dc22ab323ddea9ed166e597ea1924cf368e9 Mon Sep 17 00:00:00 2001 From: "S. Amir Mohammad Najafi" Date: Sat, 24 Sep 2022 08:42:20 +0330 Subject: [PATCH 3/3] feat: add math demo --- demo/index.html | 1 + demo/math/index.html | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 demo/math/index.html diff --git a/demo/index.html b/demo/index.html index 7bfd21bdc..fa4c81c96 100644 --- a/demo/index.html +++ b/demo/index.html @@ -12,6 +12,7 @@
  • Signal
  • Router
  • Font
  • +
  • Math
  • diff --git a/demo/math/index.html b/demo/math/index.html new file mode 100644 index 000000000..bc71e0c9d --- /dev/null +++ b/demo/math/index.html @@ -0,0 +1,13 @@ + + + + + + @alwatr/math + + + + +

    Check the console

    + +