Skip to content

Commit 9854f85

Browse files
committed
Merge branch 'up/fix/text-to-bin-enh' into chore/all-my-stuffs
2 parents 52909fc + 236b7ae commit 9854f85

File tree

5 files changed

+105
-50
lines changed

5 files changed

+105
-50
lines changed

locales/en.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,8 @@ tools:
434434
description: Encode text to URL-encoded format (also known as "percent-encoded"), or decode from it.
435435

436436
text-to-binary:
437-
title: Text to ASCII binary
438-
description: Convert text to its ASCII binary representation and vice-versa.
437+
title: Text to UTF-8 binary
438+
description: Convert text to its UTF-8 binary representation and vice-versa.
439439

440440
image-resizer:
441441
title: Image resizer

src/tools/text-to-binary/text-to-binary.e2e.spec.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { expect, test } from '@playwright/test';
22

3-
test.describe('Tool - Text to ASCII binary', () => {
3+
test.describe('Tool - Text to UTF-8 binary', () => {
44
test.beforeEach(async ({ page }) => {
55
await page.goto('/text-to-binary');
66
});
77

88
test('Has correct title', async ({ page }) => {
9-
await expect(page).toHaveTitle('Text to ASCII binary - IT Tools');
9+
await expect(page).toHaveTitle('Text to UTF-8 binary - IT Tools');
1010
});
1111

1212
test('Text to binary conversion', async ({ page }) => {
@@ -17,7 +17,9 @@ test.describe('Tool - Text to ASCII binary', () => {
1717
});
1818

1919
test('Binary to text conversion', async ({ page }) => {
20-
await page.getByTestId('binary-to-text-input').fill('01101001 01110100 00101101 01110100 01101111 01101111 01101100 01110011');
20+
await page
21+
.getByTestId('binary-to-text-input')
22+
.fill('01101001 01110100 00101101 01110100 01101111 01101111 01101100 01110011');
2123
const text = await page.getByTestId('binary-to-text-output').inputValue();
2224

2325
expect(text).toEqual('it-tools');
Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,56 @@
11
import { describe, expect, it } from 'vitest';
2-
import { convertAsciiBinaryToText, convertTextToAsciiBinary } from './text-to-binary.models';
2+
import { convertTextToUtf8Binary, convertUtf8BinaryToText } from './text-to-binary.models';
33

44
describe('text-to-binary', () => {
5-
describe('convertTextToAsciiBinary', () => {
6-
it('a text string is converted to its ascii binary representation', () => {
7-
expect(convertTextToAsciiBinary('A')).toBe('01000001');
8-
expect(convertTextToAsciiBinary('hello')).toBe('01101000 01100101 01101100 01101100 01101111');
9-
expect(convertTextToAsciiBinary('')).toBe('');
5+
const utf8Tests = [
6+
{ text: '文字', binary: '11100110 10010110 10000111 11100101 10101101 10010111' },
7+
{ text: '💩', binary: '11110000 10011111 10010010 10101001' },
8+
];
9+
10+
describe('convertTextToUtf8Binary', () => {
11+
it('a text string is converted to its UTF-8 binary representation', () => {
12+
expect(convertTextToUtf8Binary('A')).toBe('01000001');
13+
expect(convertTextToUtf8Binary('hello')).toBe('01101000 01100101 01101100 01101100 01101111');
14+
expect(convertTextToUtf8Binary('')).toBe('');
1015
});
1116
it('the separator between octets can be changed', () => {
12-
expect(convertTextToAsciiBinary('hello', { separator: '' })).toBe('0110100001100101011011000110110001101111');
17+
expect(convertTextToUtf8Binary('hello', { separator: '' })).toBe('0110100001100101011011000110110001101111');
18+
expect(convertTextToUtf8Binary('hello', { separator: '-' })).toBe('01101000-01100101-01101100-01101100-01101111');
19+
});
20+
it('works with non-ASCII input', () => {
21+
for (const { text, binary } of utf8Tests) {
22+
const converted = convertTextToUtf8Binary(text);
23+
expect(converted).toBe(binary);
24+
}
1325
});
1426
});
1527

16-
describe('convertAsciiBinaryToText', () => {
28+
describe('convertUtf8BinaryToText', () => {
1729
it('an ascii binary string is converted to its text representation', () => {
18-
expect(convertAsciiBinaryToText('01101000 01100101 01101100 01101100 01101111')).toBe('hello');
19-
expect(convertAsciiBinaryToText('01000001')).toBe('A');
20-
expect(convertTextToAsciiBinary('')).toBe('');
30+
expect(convertUtf8BinaryToText('01101000 01100101 01101100 01101100 01101111')).toBe('hello');
31+
expect(convertUtf8BinaryToText('01000001')).toBe('A');
32+
expect(convertTextToUtf8Binary('')).toBe('');
2133
});
2234

2335
it('the given binary string is cleaned before conversion', () => {
24-
expect(convertAsciiBinaryToText(' 01000 001garbage')).toBe('A');
36+
expect(convertUtf8BinaryToText(' 01000 001garbage')).toBe('A');
37+
});
38+
39+
it('throws an error if the given binary string is not an integer number of complete octets', () => {
40+
expect(() => convertUtf8BinaryToText('010000011')).toThrow('Invalid binary string');
41+
expect(() => convertUtf8BinaryToText('010000011 010000011')).toThrow('Invalid binary string');
42+
expect(() => convertUtf8BinaryToText('1')).toThrow('Invalid binary string');
43+
});
44+
45+
it('throws an error if the given binary string is not valid UTF-8', () => {
46+
expect(() => convertUtf8BinaryToText('11111111')).toThrow();
2547
});
2648

27-
it('throws an error if the given binary string as no complete octet', () => {
28-
expect(() => convertAsciiBinaryToText('010000011')).toThrow('Invalid binary string');
29-
expect(() => convertAsciiBinaryToText('1')).toThrow('Invalid binary string');
49+
it('works with non-ASCII input', () => {
50+
for (const { text, binary } of utf8Tests) {
51+
const reverted = convertUtf8BinaryToText(binary);
52+
expect(reverted).toBe(text);
53+
}
3054
});
3155
});
3256
});
Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
export { convertTextToAsciiBinary, convertAsciiBinaryToText };
1+
export { convertTextToUtf8Binary, convertUtf8BinaryToText };
22

3-
function convertTextToAsciiBinary(text: string, { separator = ' ' }: { separator?: string } = {}): string {
4-
return text
5-
.split('')
6-
.map(char => char.charCodeAt(0).toString(2).padStart(8, '0'))
7-
.join(separator);
3+
function convertTextToUtf8Binary(text: string, { separator = ' ' }: { separator?: string } = {}): string {
4+
return [...new TextEncoder().encode(text)].map(x => x.toString(2).padStart(8, '0')).join(separator);
85
}
96

10-
function convertAsciiBinaryToText(binary: string): string {
11-
const cleanBinary = binary.replace(/[^01]/g, '');
7+
function convertUtf8BinaryToText(binary: string): string {
8+
const cleanBinary = binary.replace(/[^01]+/g, '');
129

1310
if (cleanBinary.length % 8) {
1411
throw new Error('Invalid binary string');
1512
}
1613

17-
return cleanBinary
18-
.split(/(\d{8})/)
19-
.filter(Boolean)
20-
.map(binary => String.fromCharCode(Number.parseInt(binary, 2)))
21-
.join('');
14+
return new TextDecoder(undefined, { fatal: true }).decode(
15+
Uint8Array.from({ length: cleanBinary.length / 8 }, (_, i) =>
16+
Number.parseInt(cleanBinary.slice(i * 8, (i + 1) * 8), 2),
17+
),
18+
);
2219
}
Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,74 @@
11
<script setup lang="ts">
2-
import { convertAsciiBinaryToText, convertTextToAsciiBinary } from './text-to-binary.models';
2+
import { convertTextToUtf8Binary, convertUtf8BinaryToText } from './text-to-binary.models';
33
import { withDefaultOnError } from '@/utils/defaults';
44
import { useCopy } from '@/composable/copy';
55
import { isNotThrowing } from '@/utils/boolean';
66
77
const inputText = ref('');
8-
const binaryFromText = computed(() => convertTextToAsciiBinary(inputText.value));
8+
const binaryFromText = computed(() => convertTextToUtf8Binary(inputText.value));
99
const { copy: copyBinary } = useCopy({ source: binaryFromText });
1010
1111
const inputBinary = ref('');
12-
const textFromBinary = computed(() => withDefaultOnError(() => convertAsciiBinaryToText(inputBinary.value), ''));
12+
const textFromBinary = computed(() => withDefaultOnError(() => convertUtf8BinaryToText(inputBinary.value), ''));
1313
const inputBinaryValidationRules = [
1414
{
15-
validator: (value: string) => isNotThrowing(() => convertAsciiBinaryToText(value)),
16-
message: 'Binary should be a valid ASCII binary string with multiples of 8 bits',
15+
validator: (value: string) => isNotThrowing(() => convertUtf8BinaryToText(value)),
16+
message: 'Binary should be a valid UTF-8 binary string with multiples of 8 bits',
1717
},
1818
];
1919
const { copy: copyText } = useCopy({ source: textFromBinary });
2020
</script>
2121

2222
<template>
23-
<c-card title="Text to ASCII binary">
24-
<c-input-text v-model:value="inputText" multiline placeholder="e.g. 'Hello world'" label="Enter text to convert to binary" autosize autofocus raw-text test-id="text-to-binary-input" />
25-
<c-input-text v-model:value="binaryFromText" label="Binary from your text" multiline raw-text readonly mt-2 placeholder="The binary representation of your text will be here" test-id="text-to-binary-output" />
23+
<c-card title="Text to UTF-8 binary">
24+
<c-input-text
25+
v-model:value="inputText"
26+
multiline
27+
placeholder="e.g. 'Hello world'"
28+
label="Enter text to convert to binary"
29+
autosize
30+
autofocus
31+
raw-text
32+
test-id="text-to-binary-input"
33+
/>
34+
<c-input-text
35+
v-model:value="binaryFromText"
36+
label="Binary from your text"
37+
multiline
38+
raw-text
39+
readonly
40+
mt-2
41+
placeholder="The binary representation of your text will be here"
42+
test-id="text-to-binary-output"
43+
/>
2644
<div mt-2 flex justify-center>
27-
<c-button :disabled="!binaryFromText" @click="copyBinary()">
28-
Copy binary to clipboard
29-
</c-button>
45+
<c-button :disabled="!binaryFromText" @click="copyBinary()"> Copy binary to clipboard </c-button>
3046
</div>
3147
</c-card>
3248

33-
<c-card title="ASCII binary to text">
34-
<c-input-text v-model:value="inputBinary" multiline placeholder="e.g. '01001000 01100101 01101100 01101100 01101111'" label="Enter binary to convert to text" autosize raw-text :validation-rules="inputBinaryValidationRules" test-id="binary-to-text-input" />
35-
<c-input-text v-model:value="textFromBinary" label="Text from your binary" multiline raw-text readonly mt-2 placeholder="The text representation of your binary will be here" test-id="binary-to-text-output" />
49+
<c-card title="UTF-8 binary to text">
50+
<c-input-text
51+
v-model:value="inputBinary"
52+
multiline
53+
placeholder="e.g. '01001000 01100101 01101100 01101100 01101111'"
54+
label="Enter binary to convert to text"
55+
autosize
56+
raw-text
57+
:validation-rules="inputBinaryValidationRules"
58+
test-id="binary-to-text-input"
59+
/>
60+
<c-input-text
61+
v-model:value="textFromBinary"
62+
label="Text from your binary"
63+
multiline
64+
raw-text
65+
readonly
66+
mt-2
67+
placeholder="The text representation of your binary will be here"
68+
test-id="binary-to-text-output"
69+
/>
3670
<div mt-2 flex justify-center>
37-
<c-button :disabled="!textFromBinary" @click="copyText()">
38-
Copy text to clipboard
39-
</c-button>
71+
<c-button :disabled="!textFromBinary" @click="copyText()"> Copy text to clipboard </c-button>
4072
</div>
4173
</c-card>
4274
</template>

0 commit comments

Comments
 (0)