From 2b6f8da0f960b7ff63901b95224fa0cc1bba5954 Mon Sep 17 00:00:00 2001 From: Dicken Date: Mon, 1 Jun 2026 13:38:17 +0200 Subject: [PATCH] =?UTF-8?q?DevTools=20Regex:=20schwarze=20Seite=20behoben,?= =?UTF-8?q?=20Zahlenbereich=20enth=C3=A4lt-nicht,=20Test=20mit=20Exakt-Tog?= =?UTF-8?q?gle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/tools/devtools.jsx | 43 ++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/frontend/src/tools/devtools.jsx b/frontend/src/tools/devtools.jsx index dbd299d..d99c32c 100644 --- a/frontend/src/tools/devtools.jsx +++ b/frontend/src/tools/devtools.jsx @@ -1424,8 +1424,9 @@ const RULE_TYPES = [ { id:'alnum_n', label:'Genau N Alphanumerisch',fields:['count'], hint:'8' }, { id:'minlength', label:'Mindestlänge', fields:['count'], hint:'5' }, { id:'maxlength', label:'Höchstlänge', fields:['count'], hint:'20' }, - { id:'numrange', label:'Zahlenbereich (enthält)', fields:['min','max'], hint:'' }, - { id:'numrange_exact',label:'Zahlenbereich (exakt)', fields:['min','max'], hint:'' }, + { id:'numrange', label:'Zahlenbereich (enthält)', fields:['min','max'], hint:'' }, + { id:'numrange_not', label:'Zahlenbereich (enthält nicht)',fields:['min','max'], hint:'' }, + { id:'numrange_exact',label:'Zahlenbereich (exakt)', fields:['min','max'], hint:'' }, { id:'onlynums', label:'Nur Zahlen', fields:[], hint:'' }, { id:'onlyletters', label:'Nur Buchstaben', fields:[], hint:'' }, { id:'onlyalnum', label:'Nur Alphanumerisch', fields:[], hint:'' }, @@ -1461,8 +1462,9 @@ function ruleToRegex(rule) { case 'alnum_n': return { pat: `[a-zA-Z0-9]{${f.count||1}}`, desc: `genau ${f.count||1} alphanumerische Zeichen` }; case 'minlength': return { pat: `.{${f.count||1},}`, desc: `mindestens ${f.count||1} Zeichen lang` }; case 'maxlength': return { pat: `.{0,${f.count||999}}`, desc: `höchstens ${f.count||999} Zeichen lang` }; - case 'numrange': return { pat: `(?:${buildNumRange(Number(f.min||0), Number(f.max||9))})`, desc: `enthält eine Zahl zwischen ${f.min||0} und ${f.max||9}` }; - case 'numrange_exact': return { pat: `^(?:${buildNumRange(Number(f.min||0), Number(f.max||9))})$`, desc: `ist exakt eine Zahl zwischen ${f.min||0} und ${f.max||9}` }; + case 'numrange': return { pat: `(?:${buildNumRange(Number(f.min||0), Number(f.max||9))})`, desc: `enthält eine Zahl zwischen ${f.min||0} und ${f.max||9}` }; + case 'numrange_not': return { pat: `^(?!.*(?:${buildNumRange(Number(f.min||0), Number(f.max||9))})).*$`, desc: `enthält KEINE Zahl zwischen ${f.min||0} und ${f.max||9}` }; + case 'numrange_exact': return { pat: `^(?:${buildNumRange(Number(f.min||0), Number(f.max||9))})$`, desc: `ist exakt eine Zahl zwischen ${f.min||0} und ${f.max||9}` }; case 'onlynums': return { pat: `^\\d+$`, desc: `nur Ziffern (0–9)` }; case 'onlyletters': return { pat: `^[a-zA-ZäöüÄÖÜß]+$`, desc: `nur Buchstaben` }; case 'onlyalnum': return { pat: `^[a-zA-Z0-9]+$`, desc: `nur Buchstaben und Ziffern` }; @@ -1697,6 +1699,7 @@ function RegexBuilder({ toast, mobile }) { // ── Build mode ── const [rules, setRules] = useState([]); const [testVal, setTestVal] = useState(''); + const [testExact, setTestExact] = useState(true); const [copied, setCopied] = useState(false); function addRule() { @@ -1728,7 +1731,8 @@ function RegexBuilder({ toast, mobile }) { let testResult = null; if (regex && testVal !== '') { try { - testResult = new RegExp(regex).test(testVal); + const pat = testExact ? `^(?:${regex})$` : regex; + testResult = new RegExp(pat).test(testVal); } catch(e) { testResult = null; } } @@ -1741,13 +1745,18 @@ function RegexBuilder({ toast, mobile }) { // ── Explain mode ── const [explainInput, setExplainInput] = useState(''); const [explainTestVal, setExplainTestVal] = useState(''); + const [explainExact, setExplainExact] = useState(false); const explained = explainInput ? explainRegex(explainInput) : []; let explainTestResult = null; if (explainInput && explainTestVal !== '') { - try { explainTestResult = new RegExp(explainInput).test(explainTestVal); } catch {} + try { + const pat = explainExact ? `^(?:${explainInput})$` : explainInput; + explainTestResult = new RegExp(pat).test(explainTestVal); + } catch {} } const inp = {...S.inp, fontSize:13, padding:'7px 9px', boxSizing:'border-box'}; + const lbl = {color:'rgba(255,255,255,0.55)', fontFamily:'monospace', fontSize:10, marginBottom:3}; return (
{/* Mode tabs */} @@ -1801,11 +1810,19 @@ function RegexBuilder({ toast, mobile }) { {/* Test-Bereich */}
-
TESTEN
+
+ TESTEN + +
setTestVal(e.target.value)}/> - {testResult===true && ✓ Treffer} + {testResult===true && ✓ Treffer} {testResult===false && ✗ Kein Treffer}
@@ -1848,7 +1865,15 @@ function RegexBuilder({ toast, mobile }) { {/* Test */}
-
TESTEN
+
+ TESTEN + +
setExplainTestVal(e.target.value)}/>