mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 05:47:10 -04:00
fix: refactor to service + add regex diagram + ui enhancements
This commit is contained in:
parent
f61db56abb
commit
c9f9bb1273
6 changed files with 213 additions and 57 deletions
106
src/tools/regex-tester/regex-tester.service.test.ts
Normal file
106
src/tools/regex-tester/regex-tester.service.test.ts
Normal file
|
@ -0,0 +1,106 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { matchRegex } from './regex-tester.service';
|
||||
|
||||
const regexesData = [
|
||||
{
|
||||
regex: '',
|
||||
text: '',
|
||||
flags: '',
|
||||
result: [],
|
||||
},
|
||||
{
|
||||
regex: '.*',
|
||||
text: '',
|
||||
flags: '',
|
||||
result: [],
|
||||
},
|
||||
{
|
||||
regex: '',
|
||||
text: 'aaa',
|
||||
flags: '',
|
||||
result: [],
|
||||
},
|
||||
{
|
||||
regex: 'a',
|
||||
text: 'baaa',
|
||||
flags: '',
|
||||
result: [
|
||||
{
|
||||
captures: [],
|
||||
groups: [],
|
||||
index: 1,
|
||||
value: 'a',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
regex: '(.)(?<g>r)',
|
||||
text: 'azertyr',
|
||||
flags: 'g',
|
||||
result: [
|
||||
{
|
||||
captures: [
|
||||
{
|
||||
end: 3,
|
||||
name: '1',
|
||||
start: 2,
|
||||
value: 'e',
|
||||
},
|
||||
{
|
||||
end: 4,
|
||||
name: '2',
|
||||
start: 3,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
groups: [
|
||||
{
|
||||
end: 4,
|
||||
name: 'g',
|
||||
start: 3,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
index: 2,
|
||||
value: 'er',
|
||||
},
|
||||
{
|
||||
captures: [
|
||||
{
|
||||
end: 6,
|
||||
name: '1',
|
||||
start: 5,
|
||||
value: 'y',
|
||||
},
|
||||
{
|
||||
end: 7,
|
||||
name: '2',
|
||||
start: 6,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
groups: [
|
||||
{
|
||||
end: 7,
|
||||
name: 'g',
|
||||
start: 6,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
index: 5,
|
||||
value: 'yr',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe('regex-tester', () => {
|
||||
for (const reg of regexesData) {
|
||||
const { regex, text, flags, result: expected_result } = reg;
|
||||
it(`Should matchRegex("${regex}","${text}","${flags}") return correct result`, async () => {
|
||||
const result = matchRegex(regex, text, `${flags}d`);
|
||||
|
||||
expect(result).to.deep.equal(expected_result);
|
||||
});
|
||||
}
|
||||
});
|
61
src/tools/regex-tester/regex-tester.service.ts
Normal file
61
src/tools/regex-tester/regex-tester.service.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
interface RegExpGroupIndices {
|
||||
[name: string]: [number, number]
|
||||
}
|
||||
interface RegExpIndices extends Array<[number, number]> {
|
||||
groups: RegExpGroupIndices
|
||||
}
|
||||
interface RegExpExecArrayWithIndices extends RegExpExecArray {
|
||||
indices: RegExpIndices
|
||||
}
|
||||
interface GroupCapture {
|
||||
name: string
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
};
|
||||
|
||||
export function matchRegex(regex: string, text: string, flags: string) {
|
||||
// if (regex === '' || text === '') {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
let lastIndex = -1;
|
||||
const re = new RegExp(regex, flags);
|
||||
const results = [];
|
||||
let match = re.exec(text) as RegExpExecArrayWithIndices;
|
||||
while (match !== null) {
|
||||
if (re.lastIndex === lastIndex || match[0] === '') {
|
||||
break;
|
||||
}
|
||||
const indices = match.indices;
|
||||
const captures: Array<GroupCapture> = [];
|
||||
Object.entries(match).forEach(([captureName, captureValue]) => {
|
||||
if (captureName !== '0' && captureName.match(/\d+/)) {
|
||||
captures.push({
|
||||
name: captureName,
|
||||
value: captureValue,
|
||||
start: indices[Number(captureName)][0],
|
||||
end: indices[Number(captureName)][1],
|
||||
});
|
||||
}
|
||||
});
|
||||
const groups: Array<GroupCapture> = [];
|
||||
Object.entries(match.groups || {}).forEach(([groupName, groupValue]) => {
|
||||
groups.push({
|
||||
name: groupName,
|
||||
value: groupValue,
|
||||
start: indices.groups[groupName][0],
|
||||
end: indices.groups[groupName][1],
|
||||
});
|
||||
});
|
||||
results.push({
|
||||
index: match.index,
|
||||
value: match[0],
|
||||
captures,
|
||||
groups,
|
||||
});
|
||||
lastIndex = re.lastIndex;
|
||||
match = re.exec(text) as RegExpExecArrayWithIndices;
|
||||
}
|
||||
return results;
|
||||
}
|
|
@ -1,24 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import RandExp from 'randexp';
|
||||
import { render } from '@regexper/render';
|
||||
import { matchRegex } from './regex-tester.service';
|
||||
import { useValidation } from '@/composable/validation';
|
||||
import { useQueryParamOrStorage } from '@/composable/queryParams';
|
||||
|
||||
interface RegExpGroupIndices {
|
||||
[name: string]: [number, number]
|
||||
}
|
||||
interface RegExpIndices extends Array<[number, number]> {
|
||||
groups: RegExpGroupIndices
|
||||
}
|
||||
interface RegExpExecArrayWithIndices extends RegExpExecArray {
|
||||
indices: RegExpIndices
|
||||
}
|
||||
interface GroupCapture {
|
||||
name: string
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
};
|
||||
|
||||
const regex = useQueryParamOrStorage({ name: 'regex', storageName: 'regex-tester:regex', defaultValue: '' });
|
||||
const text = ref('');
|
||||
const global = ref(true);
|
||||
|
@ -27,6 +13,7 @@ const multiline = ref(false);
|
|||
const dotAll = ref(true);
|
||||
const unicode = ref(true);
|
||||
const unicodeSets = ref(false);
|
||||
const visualizerSVG = ref() as Ref<SVGSVGElement>;
|
||||
|
||||
const regexValidation = useValidation({
|
||||
source: regex,
|
||||
|
@ -42,10 +29,6 @@ const regexValidation = useValidation({
|
|||
],
|
||||
});
|
||||
const results = computed(() => {
|
||||
if (regex.value === '' || text.value === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
let flags = 'd';
|
||||
if (global.value) {
|
||||
flags += 'g';
|
||||
|
@ -67,40 +50,7 @@ const results = computed(() => {
|
|||
}
|
||||
|
||||
try {
|
||||
const re = new RegExp(regex.value, flags);
|
||||
const results = [];
|
||||
let match = re.exec(text.value) as RegExpExecArrayWithIndices;
|
||||
while (match !== null) {
|
||||
const indices = match.indices;
|
||||
const captures: Array<GroupCapture> = [];
|
||||
Object.entries(match).forEach(([captureName, captureValue]) => {
|
||||
if (captureName !== '0' && captureName.match(/\d+/)) {
|
||||
captures.push({
|
||||
name: captureName,
|
||||
value: captureValue,
|
||||
start: indices[Number(captureName)][0],
|
||||
end: indices[Number(captureName)][1],
|
||||
});
|
||||
}
|
||||
});
|
||||
const groups: Array<GroupCapture> = [];
|
||||
Object.entries(match.groups || {}).forEach(([groupName, groupValue]) => {
|
||||
groups.push({
|
||||
name: groupName,
|
||||
value: groupValue,
|
||||
start: indices.groups[groupName][0],
|
||||
end: indices.groups[groupName][1],
|
||||
});
|
||||
});
|
||||
results.push({
|
||||
index: match.index,
|
||||
value: match[0],
|
||||
captures,
|
||||
groups,
|
||||
});
|
||||
match = re.exec(text.value) as RegExpExecArrayWithIndices;
|
||||
}
|
||||
return results;
|
||||
return matchRegex(regex.value, text.value, flags);
|
||||
}
|
||||
catch (_) {
|
||||
return [];
|
||||
|
@ -116,6 +66,19 @@ const sample = computed(() => {
|
|||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
watchEffect(
|
||||
async () => {
|
||||
const regexValue = regex.value;
|
||||
const svg = visualizerSVG.value;
|
||||
svg.childNodes.forEach(n => n.remove());
|
||||
try {
|
||||
await render(regexValue, svg);
|
||||
}
|
||||
catch (_) {
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -164,7 +127,7 @@ const sample = computed(() => {
|
|||
/>
|
||||
</c-card>
|
||||
|
||||
<c-card title="Matches" mb-1>
|
||||
<c-card title="Matches" mb-1 mt-3>
|
||||
<n-table v-if="results?.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -208,8 +171,12 @@ const sample = computed(() => {
|
|||
</c-alert>
|
||||
</c-card>
|
||||
|
||||
<c-card title="Sample matching text">
|
||||
<pre style="white-space: pre-wrap">{{ sample }}</pre>
|
||||
<c-card title="Sample matching text" mt-3>
|
||||
<pre style="white-space: pre-wrap; word-break: break-all;">{{ sample }}</pre>
|
||||
</c-card>
|
||||
|
||||
<c-card title="Regex Diagram" style="overflow-x: scroll;" mt-3>
|
||||
<svg ref="visualizerSVG" />
|
||||
</c-card>
|
||||
</div>
|
||||
</template>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue