From 28216555544189bb0b7b634077fbcedc01a9ee64 Mon Sep 17 00:00:00 2001 From: ng-anhhtuann Date: Thu, 16 May 2024 12:42:12 +0700 Subject: [PATCH] feat(new tool): unicode to java entities --- components.d.ts | 23 +++++-- locales/en.yml | 4 ++ locales/vi.yml | 4 ++ src/tools/index.ts | 2 + .../index.ts | 13 ++++ ...ode-characters-to-java-entities.service.ts | 63 +++++++++++++++++++ ...nicode-characters-to-java-entities.spec.ts | 25 ++++++++ ...nicode-characters-to-java-entities.test.ts | 20 ++++++ .../unicode-characters-to-java-entities.vue | 34 ++++++++++ 9 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 src/tools/unicode-characters-to-java-entities-converter/index.ts create mode 100644 src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.service.ts create mode 100644 src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.spec.ts create mode 100644 src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.test.ts create mode 100644 src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.vue diff --git a/components.d.ts b/components.d.ts index f2c3146f..d2d12d3d 100644 --- a/components.d.ts +++ b/components.d.ts @@ -3,11 +3,9 @@ // @ts-nocheck // Generated by unplugin-vue-components // Read more: https://github.com/vuejs/core/pull/3399 -import '@vue/runtime-core' - export {} -declare module '@vue/runtime-core' { +declare module 'vue' { export interface GlobalComponents { '404.page': typeof import('./src/pages/404.page.vue')['default'] About: typeof import('./src/pages/About.vue')['default'] @@ -90,16 +88,24 @@ declare module '@vue/runtime-core' { IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default'] 'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default'] 'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default'] + IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default'] + IconMdiCamera: typeof import('~icons/mdi/camera')['default'] IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] IconMdiClose: typeof import('~icons/mdi/close')['default'] IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] + IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default'] + IconMdiDownload: typeof import('~icons/mdi/download')['default'] IconMdiEye: typeof import('~icons/mdi/eye')['default'] IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default'] IconMdiHeart: typeof import('~icons/mdi/heart')['default'] + IconMdiPause: typeof import('~icons/mdi/pause')['default'] + IconMdiPlay: typeof import('~icons/mdi/play')['default'] + IconMdiRecord: typeof import('~icons/mdi/record')['default'] IconMdiSearch: typeof import('~icons/mdi/search')['default'] IconMdiTranslate: typeof import('~icons/mdi/translate')['default'] IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] + IconMdiVideo: typeof import('~icons/mdi/video')['default'] InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] @@ -126,25 +132,33 @@ declare module '@vue/runtime-core' { MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] + NAlert: typeof import('naive-ui')['NAlert'] NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] + NCheckbox: typeof import('naive-ui')['NCheckbox'] NCode: typeof import('naive-ui')['NCode'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] + NColorPicker: typeof import('naive-ui')['NColorPicker'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NDivider: typeof import('naive-ui')['NDivider'] NEllipsis: typeof import('naive-ui')['NEllipsis'] + NForm: typeof import('naive-ui')['NForm'] NFormItem: typeof import('naive-ui')['NFormItem'] NGi: typeof import('naive-ui')['NGi'] NGrid: typeof import('naive-ui')['NGrid'] NH1: typeof import('naive-ui')['NH1'] NH3: typeof import('naive-ui')['NH3'] NIcon: typeof import('naive-ui')['NIcon'] + NInputGroup: typeof import('naive-ui')['NInputGroup'] + NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel'] NInputNumber: typeof import('naive-ui')['NInputNumber'] - NLabel: typeof import('naive-ui')['NLabel'] NLayout: typeof import('naive-ui')['NLayout'] NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NMenu: typeof import('naive-ui')['NMenu'] NScrollbar: typeof import('naive-ui')['NScrollbar'] + NSlider: typeof import('naive-ui')['NSlider'] NSpin: typeof import('naive-ui')['NSpin'] + NSwitch: typeof import('naive-ui')['NSwitch'] + NTable: typeof import('naive-ui')['NTable'] 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'] @@ -179,6 +193,7 @@ declare module '@vue/runtime-core' { 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default'] ToolCard: typeof import('./src/components/ToolCard.vue')['default'] UlidGenerator: typeof import('./src/tools/ulid-generator/ulid-generator.vue')['default'] + UnicodeCharactersToJavaEntities: typeof import('./src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.vue')['default'] UrlEncoder: typeof import('./src/tools/url-encoder/url-encoder.vue')['default'] UrlParser: typeof import('./src/tools/url-parser/url-parser.vue')['default'] UserAgentParser: typeof import('./src/tools/user-agent-parser/user-agent-parser.vue')['default'] diff --git a/locales/en.yml b/locales/en.yml index d09d435a..4384a5e3 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -391,3 +391,7 @@ tools: text-to-binary: title: Text to ASCII binary description: Convert text to its ASCII binary representation and vice-versa. + + unicode-to-java-entites: + title: Unicode Characters to Java Entities Converter + description: Unicode Characters to Java Entities Converter and vice-versa \ No newline at end of file diff --git a/locales/vi.yml b/locales/vi.yml index 9eb16bf0..33703a8c 100644 --- a/locales/vi.yml +++ b/locales/vi.yml @@ -380,3 +380,7 @@ tools: text-to-binary: title: Chuyển đổi văn bản thành nhị phân ASCII description: Chuyển đổi văn bản thành biểu diễn nhị phân ASCII của nó và ngược lại. + + unicode-to-java-entites: + title: Chuyển đổi ký tự Unicode sang thực thể Java + description: Chuyển đổi ký tự Unicode sang thực thể Java và ngược lại \ No newline at end of file diff --git a/src/tools/index.ts b/src/tools/index.ts index aa861c93..dda8cbf0 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -81,6 +81,7 @@ import { tool as uuidGenerator } from './uuid-generator'; import { tool as macAddressLookup } from './mac-address-lookup'; import { tool as xmlFormatter } from './xml-formatter'; import { tool as yamlViewer } from './yaml-viewer'; +import { tool as unicodeToJavaEntities } from './unicode-characters-to-java-entities-converter'; export const toolsByCategory: ToolCategory[] = [ { @@ -107,6 +108,7 @@ export const toolsByCategory: ToolCategory[] = [ listConverter, tomlToJson, tomlToYaml, + unicodeToJavaEntities, ], }, { diff --git a/src/tools/unicode-characters-to-java-entities-converter/index.ts b/src/tools/unicode-characters-to-java-entities-converter/index.ts new file mode 100644 index 00000000..c3d5b96c --- /dev/null +++ b/src/tools/unicode-characters-to-java-entities-converter/index.ts @@ -0,0 +1,13 @@ +import { TextWrapDisabled } from '@vicons/tabler'; +import { defineTool } from '../tool'; +import { translate } from '@/plugins/i18n.plugin'; + +export const tool = defineTool({ + name: translate('tools.unicode-to-java-entites.title'), + path: '/unicode-to-java-entites', + description: translate('tools.unicode-to-java-entites.description'), + keywords: ['text', 'to', 'unicode'], + component: () => import('./unicode-characters-to-java-entities.vue'), + icon: TextWrapDisabled, + createdAt: new Date('2024-01-31'), +}); diff --git a/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.service.ts b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.service.ts new file mode 100644 index 00000000..7433ee61 --- /dev/null +++ b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.service.ts @@ -0,0 +1,63 @@ +function strlenFix(str: string): string { + while (str.length < 4) { + str = `0${str}`; + } + return str; +} + +function parseUnicodeToJavaEntities(source: string, direction: '0' | '-1'): string { + let result = ''; + + if (direction === '0') { + // UTF-8 to entities + for (let i = 0; i < source.length; i++) { + const charCode = source.charCodeAt(i); + if (charCode <= 127) { + result += source.charAt(i); + } + else { + result += `\\u${strlenFix(charCode.toString(16).toUpperCase())}`; + } + } + } + else { + // Entities to UTF-8 + let state: 0 | 1 | 2 = 0; + let chars = 0; + let value = ''; + for (let i = 0; i < source.length; i++) { + switch (state) { + case 0: + if (source.charAt(i) === '\\') { + state = 1; + } + else { + result += source.charAt(i); + } + break; + case 1: + if (source.charAt(i) === 'u') { + state = 2; + chars = 0; + value = ''; + } + else { + result += `\\${source.charAt(i)}`; + state = 0; + } + break; + case 2: + chars++; + value += source.charAt(i); + if (chars >= 4) { + result += String.fromCharCode(Number.parseInt(value, 16)); + state = 0; + } + break; + } + } + } + return result; +} + +export { parseUnicodeToJavaEntities }; diff --git a/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.spec.ts b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.spec.ts new file mode 100644 index 00000000..8e94c0b0 --- /dev/null +++ b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.spec.ts @@ -0,0 +1,25 @@ +import { expect, test } from '@playwright/test'; + +test.describe('Tool - Unicode to Java entities', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/unicode-to-java-entites'); + }); + + test('Has correct title', async ({ page }) => { + await expect(page).toHaveTitle('Unicode to Java Entities - IT Tools'); + }); + + test('Unicode to Entities conversion', async ({ page }) => { + await page.getByTestId('unicode-to-entities-input').fill('việt nam'); + const unicode = await page.getByTestId('unicode-to-entities-output').inputValue(); + + expect(unicode).toEqual('vi\u1EC7t nam'); + }); + + test('Entities to Unicode conversion', async ({ page }) => { + await page.getByTestId('entities-to-unicode-input').fill('vi\u1EC7t nam'); + const text = await page.getByTestId('entities-to-unicode-output').inputValue(); + + expect(text).toEqual('việt nam'); + }); +}); diff --git a/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.test.ts b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.test.ts new file mode 100644 index 00000000..9b274798 --- /dev/null +++ b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; +import { parseUnicodeToJavaEntities } from './unicode-characters-to-java-entities.service'; + +describe('unicode-to-entities', () => { + describe('convertTextToUnicode', () => { + it('a unicode string is converted to java entities representation', () => { + expect(parseUnicodeToJavaEntities('là', '0')).toBe('l\u00E0'); + expect(parseUnicodeToJavaEntities('sơn tùng MTP', '0')).toBe('s\u01A1n t\u00F9ng MTP'); + expect(parseUnicodeToJavaEntities('', '0')).toBe(''); + }); + }); + + describe('entities-to-unicode', () => { + it('java entities string is converted to its unicode representation', () => { + expect(parseUnicodeToJavaEntities('l\u00E0', '-1')).toBe('là'); + expect(parseUnicodeToJavaEntities('s\u01A1n t\u00F9ng MTP', '-1')).toBe('sơn tùng MTP'); + expect(parseUnicodeToJavaEntities('', '-1')).toBe(''); + }); + }); +}); diff --git a/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.vue b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.vue new file mode 100644 index 00000000..107f8b26 --- /dev/null +++ b/src/tools/unicode-characters-to-java-entities-converter/unicode-characters-to-java-entities.vue @@ -0,0 +1,34 @@ + + +