DevTools Regex: schwarze Seite behoben, Zahlenbereich enthält-nicht, Test mit Exakt-Toggle

This commit is contained in:
2026-06-01 13:38:17 +02:00
parent a6dd7ab09c
commit 2b6f8da0f9

View File

@@ -1424,8 +1424,9 @@ const RULE_TYPES = [
{ id:'alnum_n', label:'Genau N Alphanumerisch',fields:['count'], hint:'8' }, { id:'alnum_n', label:'Genau N Alphanumerisch',fields:['count'], hint:'8' },
{ id:'minlength', label:'Mindestlänge', fields:['count'], hint:'5' }, { id:'minlength', label:'Mindestlänge', fields:['count'], hint:'5' },
{ id:'maxlength', label:'Höchstlänge', fields:['count'], hint:'20' }, { id:'maxlength', label:'Höchstlänge', fields:['count'], hint:'20' },
{ id:'numrange', label:'Zahlenbereich (enthält)', fields:['min','max'], hint:'' }, { id:'numrange', label:'Zahlenbereich (enthält)', fields:['min','max'], hint:'' },
{ id:'numrange_exact',label:'Zahlenbereich (exakt)', 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:'onlynums', label:'Nur Zahlen', fields:[], hint:'' },
{ id:'onlyletters', label:'Nur Buchstaben', fields:[], hint:'' }, { id:'onlyletters', label:'Nur Buchstaben', fields:[], hint:'' },
{ id:'onlyalnum', label:'Nur Alphanumerisch', 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 '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 '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 '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': 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_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 (09)` }; case 'onlynums': return { pat: `^\\d+$`, desc: `nur Ziffern (09)` };
case 'onlyletters': return { pat: `^[a-zA-ZäöüÄÖÜß]+$`, desc: `nur Buchstaben` }; case 'onlyletters': return { pat: `^[a-zA-ZäöüÄÖÜß]+$`, desc: `nur Buchstaben` };
case 'onlyalnum': return { pat: `^[a-zA-Z0-9]+$`, desc: `nur Buchstaben und Ziffern` }; case 'onlyalnum': return { pat: `^[a-zA-Z0-9]+$`, desc: `nur Buchstaben und Ziffern` };
@@ -1697,6 +1699,7 @@ function RegexBuilder({ toast, mobile }) {
// ── Build mode ── // ── Build mode ──
const [rules, setRules] = useState([]); const [rules, setRules] = useState([]);
const [testVal, setTestVal] = useState(''); const [testVal, setTestVal] = useState('');
const [testExact, setTestExact] = useState(true);
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
function addRule() { function addRule() {
@@ -1728,7 +1731,8 @@ function RegexBuilder({ toast, mobile }) {
let testResult = null; let testResult = null;
if (regex && testVal !== '') { if (regex && testVal !== '') {
try { try {
testResult = new RegExp(regex).test(testVal); const pat = testExact ? `^(?:${regex})$` : regex;
testResult = new RegExp(pat).test(testVal);
} catch(e) { testResult = null; } } catch(e) { testResult = null; }
} }
@@ -1741,13 +1745,18 @@ function RegexBuilder({ toast, mobile }) {
// ── Explain mode ── // ── Explain mode ──
const [explainInput, setExplainInput] = useState(''); const [explainInput, setExplainInput] = useState('');
const [explainTestVal, setExplainTestVal] = useState(''); const [explainTestVal, setExplainTestVal] = useState('');
const [explainExact, setExplainExact] = useState(false);
const explained = explainInput ? explainRegex(explainInput) : []; const explained = explainInput ? explainRegex(explainInput) : [];
let explainTestResult = null; let explainTestResult = null;
if (explainInput && explainTestVal !== '') { 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 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 ( return (
<div> <div>
{/* Mode tabs */} {/* Mode tabs */}
@@ -1801,11 +1810,19 @@ function RegexBuilder({ toast, mobile }) {
{/* Test-Bereich */} {/* Test-Bereich */}
<div style={{borderRadius:9,background:'rgba(255,255,255,0.03)', <div style={{borderRadius:9,background:'rgba(255,255,255,0.03)',
border:'1px solid rgba(255,255,255,0.08)',padding:'12px 14px'}}> border:'1px solid rgba(255,255,255,0.08)',padding:'12px 14px'}}>
<div style={{color:'rgba(255,255,255,0.45)',fontFamily:'monospace',fontSize:10,marginBottom:8}}>TESTEN</div> <div style={{display:'flex',alignItems:'center',gap:12,marginBottom:8,flexWrap:'wrap'}}>
<span style={{color:'rgba(255,255,255,0.45)',fontFamily:'monospace',fontSize:10}}>TESTEN</span>
<label style={{display:'flex',alignItems:'center',gap:6,cursor:'pointer'}}>
<input type="checkbox" checked={testExact} onChange={e=>setTestExact(e.target.checked)}/>
<span style={{color:'rgba(255,255,255,0.5)',fontFamily:'monospace',fontSize:10}}>
Exakt (^$) ganzer Text muss passen
</span>
</label>
</div>
<div style={{display:'flex',gap:10,alignItems:'center',flexWrap:'wrap'}}> <div style={{display:'flex',gap:10,alignItems:'center',flexWrap:'wrap'}}>
<input style={{...inp,flex:1,minWidth:160}} placeholder="Testwert eingeben…" <input style={{...inp,flex:1,minWidth:160}} placeholder="Testwert eingeben…"
value={testVal} onChange={e=>setTestVal(e.target.value)}/> value={testVal} onChange={e=>setTestVal(e.target.value)}/>
{testResult===true && <span style={{color:'#4ecdc4',fontFamily:'monospace',fontSize:14,fontWeight:700}}> Treffer</span>} {testResult===true && <span style={{color:'#4ecdc4',fontFamily:'monospace',fontSize:14,fontWeight:700}}> Treffer</span>}
{testResult===false && <span style={{color:'#ff6b9d',fontFamily:'monospace',fontSize:14,fontWeight:700}}> Kein Treffer</span>} {testResult===false && <span style={{color:'#ff6b9d',fontFamily:'monospace',fontSize:14,fontWeight:700}}> Kein Treffer</span>}
</div> </div>
</div> </div>
@@ -1848,7 +1865,15 @@ function RegexBuilder({ toast, mobile }) {
{/* Test */} {/* Test */}
<div style={{borderRadius:9,background:'rgba(255,255,255,0.03)', <div style={{borderRadius:9,background:'rgba(255,255,255,0.03)',
border:'1px solid rgba(255,255,255,0.08)',padding:'12px 14px'}}> border:'1px solid rgba(255,255,255,0.08)',padding:'12px 14px'}}>
<div style={{color:'rgba(255,255,255,0.45)',fontFamily:'monospace',fontSize:10,marginBottom:8}}>TESTEN</div> <div style={{display:'flex',alignItems:'center',gap:12,marginBottom:8,flexWrap:'wrap'}}>
<span style={{color:'rgba(255,255,255,0.45)',fontFamily:'monospace',fontSize:10}}>TESTEN</span>
<label style={{display:'flex',alignItems:'center',gap:6,cursor:'pointer'}}>
<input type="checkbox" checked={explainExact} onChange={e=>setExplainExact(e.target.checked)}/>
<span style={{color:'rgba(255,255,255,0.5)',fontFamily:'monospace',fontSize:10}}>
Exakt (^…$)
</span>
</label>
</div>
<div style={{display:'flex',gap:10,alignItems:'center',flexWrap:'wrap'}}> <div style={{display:'flex',gap:10,alignItems:'center',flexWrap:'wrap'}}>
<input style={{...inp,flex:1,minWidth:160}} placeholder="Testwert eingeben" <input style={{...inp,flex:1,minWidth:160}} placeholder="Testwert eingeben"
value={explainTestVal} onChange={e=>setExplainTestVal(e.target.value)}/> value={explainTestVal} onChange={e=>setExplainTestVal(e.target.value)}/>