mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-22 07:46:15 -04:00
194 lines
5.3 KiB
Vue
194 lines
5.3 KiB
Vue
![]() |
<script setup lang="ts">
|
||
|
import RandExp from 'randexp';
|
||
|
import { render } from '@regexper/render';
|
||
|
import type { ShadowRootExpose } from 'vue-shadow-dom';
|
||
|
import { matchRegex } from './regex-tester.service';
|
||
|
import { useValidation } from '@/composable/validation';
|
||
|
import { useQueryParamOrStorage } from '@/composable/queryParams';
|
||
|
|
||
|
const regex = useQueryParamOrStorage({ name: 'regex', storageName: 'regex-tester:regex', defaultValue: '' });
|
||
|
const text = ref('');
|
||
|
const global = ref(true);
|
||
|
const ignoreCase = ref(false);
|
||
|
const multiline = ref(false);
|
||
|
const dotAll = ref(true);
|
||
|
const unicode = ref(true);
|
||
|
const unicodeSets = ref(false);
|
||
|
const visualizerSVG = ref<ShadowRootExpose>();
|
||
|
|
||
|
const regexValidation = useValidation({
|
||
|
source: regex,
|
||
|
rules: [
|
||
|
{
|
||
|
message: 'Invalid regex: {0}',
|
||
|
validator: value => new RegExp(value),
|
||
|
getErrorMessage: (value) => {
|
||
|
const _ = new RegExp(value);
|
||
|
return '';
|
||
|
},
|
||
|
},
|
||
|
],
|
||
|
});
|
||
|
const results = computed(() => {
|
||
|
let flags = 'd';
|
||
|
if (global.value) {
|
||
|
flags += 'g';
|
||
|
}
|
||
|
if (ignoreCase.value) {
|
||
|
flags += 'i';
|
||
|
}
|
||
|
if (multiline.value) {
|
||
|
flags += 'm';
|
||
|
}
|
||
|
if (dotAll.value) {
|
||
|
flags += 's';
|
||
|
}
|
||
|
if (unicode.value) {
|
||
|
flags += 'u';
|
||
|
}
|
||
|
else if (unicodeSets.value) {
|
||
|
flags += 'v';
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
return matchRegex(regex.value, text.value, flags);
|
||
|
}
|
||
|
catch (_) {
|
||
|
return [];
|
||
|
}
|
||
|
});
|
||
|
|
||
|
const sample = computed(() => {
|
||
|
try {
|
||
|
const randexp = new RandExp(new RegExp(regex.value.replace(/\(\?\<[^\>]*\>/g, '(?:')));
|
||
|
return randexp.gen();
|
||
|
}
|
||
|
catch (_) {
|
||
|
return '';
|
||
|
}
|
||
|
});
|
||
|
|
||
|
watchEffect(
|
||
|
async () => {
|
||
|
const regexValue = regex.value;
|
||
|
// shadow root is required:
|
||
|
// @regexper/render append a <defs><style> that broke svg transparency of icons in the whole site
|
||
|
const visualizer = visualizerSVG.value?.shadow_root;
|
||
|
if (visualizer) {
|
||
|
while (visualizer.lastChild) {
|
||
|
visualizer.removeChild(visualizer.lastChild);
|
||
|
}
|
||
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||
|
try {
|
||
|
await render(regexValue, svg);
|
||
|
}
|
||
|
catch (_) {
|
||
|
}
|
||
|
visualizer.appendChild(svg);
|
||
|
}
|
||
|
},
|
||
|
);
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<div max-w-600px>
|
||
|
<c-card title="Regex" mb-1>
|
||
|
<c-input-text
|
||
|
v-model:value="regex"
|
||
|
label="Regex to test:"
|
||
|
placeholder="Put the regex to test"
|
||
|
multiline
|
||
|
rows="3"
|
||
|
:validation="regexValidation"
|
||
|
/>
|
||
|
<router-link target="_blank" to="/regex-memo" mb-1 mt-1>
|
||
|
See Regular Expression Cheatsheet
|
||
|
</router-link>
|
||
|
<n-space>
|
||
|
<n-checkbox v-model:checked="global">
|
||
|
<span title="Global search">Global search. (<code>g</code>)</span>
|
||
|
</n-checkbox>
|
||
|
<n-checkbox v-model:checked="ignoreCase">
|
||
|
<span title="Case-insensitive search">Case-insensitive search. (<code>i</code>)</span>
|
||
|
</n-checkbox>
|
||
|
<n-checkbox v-model:checked="multiline">
|
||
|
<span title="Allows ^ and $ to match next to newline characters.">Multiline(<code>m</code>)</span>
|
||
|
</n-checkbox>
|
||
|
<n-checkbox v-model:checked="dotAll">
|
||
|
<span title="Allows . to match newline characters.">Singleline(<code>s</code>)</span>
|
||
|
</n-checkbox>
|
||
|
<n-checkbox v-model:checked="unicode">
|
||
|
<span title="Unicode; treat a pattern as a sequence of Unicode code points.">Unicode(<code>u</code>)</span>
|
||
|
</n-checkbox>
|
||
|
<n-checkbox v-model:checked="unicodeSets">
|
||
|
<span title="An upgrade to the u mode with more Unicode features.">Unicode Sets (<code>v</code>)</span>
|
||
|
</n-checkbox>
|
||
|
</n-space>
|
||
|
|
||
|
<n-divider />
|
||
|
|
||
|
<c-input-text
|
||
|
v-model:value="text"
|
||
|
label="Text to match:"
|
||
|
placeholder="Put the text to match"
|
||
|
multiline
|
||
|
rows="5"
|
||
|
/>
|
||
|
</c-card>
|
||
|
|
||
|
<c-card title="Matches" mb-1 mt-3>
|
||
|
<n-table v-if="results?.length > 0">
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th scope="col">
|
||
|
Index in text
|
||
|
</th>
|
||
|
<th scope="col">
|
||
|
Value
|
||
|
</th>
|
||
|
<th scope="col">
|
||
|
Captures
|
||
|
</th>
|
||
|
<th scope="col">
|
||
|
Groups
|
||
|
</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody>
|
||
|
<tr v-for="match of results" :key="match.index">
|
||
|
<td>{{ match.index }}</td>
|
||
|
<td>{{ match.value }}</td>
|
||
|
<td>
|
||
|
<ul>
|
||
|
<li v-for="capture in match.captures" :key="capture.name">
|
||
|
"{{ capture.name }}" = {{ capture.value }} [{{ capture.start }} - {{ capture.end }}]
|
||
|
</li>
|
||
|
</ul>
|
||
|
</td>
|
||
|
<td>
|
||
|
<ul>
|
||
|
<li v-for="group in match.groups" :key="group.name">
|
||
|
"{{ group.name }}" = {{ group.value }} [{{ group.start }} - {{ group.end }}]
|
||
|
</li>
|
||
|
</ul>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</n-table>
|
||
|
<c-alert v-else>
|
||
|
No match
|
||
|
</c-alert>
|
||
|
</c-card>
|
||
|
|
||
|
<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>
|
||
|
<shadow-root ref="visualizerSVG">
|
||
|
 
|
||
|
</shadow-root>
|
||
|
</c-card>
|
||
|
</div>
|
||
|
</template>
|