-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathregex-explainer.html
More file actions
942 lines (873 loc) · 64.4 KB
/
Copy pathregex-explainer.html
File metadata and controls
942 lines (873 loc) · 64.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Regex Explainer — Regex to Plain English | FreeDevTool</title>
<meta name="description" content="Free regex explainer — translate regex to plain English with color-coded breakdowns. Capture groups, quantifiers, lookaheads, anchors. Browser-only.">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "How to translate a regex into plain English",
"description": "Decode any regular expression into a plain-English explanation with color-coded token breakdowns.",
"step": [
{"@type":"HowToStep","name":"Paste the regex","text":"Paste any regex pattern (with or without delimiters) into the input field."},
{"@type":"HowToStep","name":"Pick the flavor","text":"Choose JavaScript / PCRE / Python / Java / .NET — flavor differences (lookbehind, named groups, possessive quantifiers) affect the explanation."},
{"@type":"HowToStep","name":"Read the breakdown","text":"Each token (literal, character class, quantifier, group, anchor, lookaround) is highlighted with its plain-English meaning underneath."},
{"@type":"HowToStep","name":"Test against samples","text":"Optionally paste a sample string to see which characters each token matches in real time."}
]
}
</script>
<meta name="robots" content="index, follow">
<meta name="author" content="Anees Ur Rehman">
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","datePublished":"2026-05-02","dateModified":"2026-05-19","inLanguage":"en-US","isPartOf":{"@type":"WebSite","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Person","name":"Anees Ur Rehman","url":"https://freedevtool.org/about","jobTitle":"Full-stack developer","worksFor":{"@type":"Organization","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<link rel="canonical" href="https://freedevtool.org/regex-explainer">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap" as="style">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap">
<link rel="preload" href="style.css?v=20260502-cards" as="style">
<link rel="stylesheet" href="style.css?v=20260502-cards">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/favicon.svg">
<meta property="og:image" content="https://freedevtool.org/og-image.svg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="FreeDevTool — 50+ free, fast, privacy-first developer tools">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://freedevtool.org/og-image.svg">
<meta name="twitter:title" content="Regex Explainer — Translate Regex to Plain English Free">
<meta name="twitter:description" content="Translate any regex into plain English with color-coded token breakdowns. Capture groups, lookarounds, anchors, quantifiers — all decoded in your browser.">
<script async src="https://www.googletagmanager.com/gtag/js?id=G-3L0CMH3X36"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','G-3L0CMH3X36');</script>
<meta property="og:title" content="Regex Explainer — Regex to Plain English Translator">
<meta property="og:description" content="Translate any regular expression into a plain English breakdown with color-coded tokens. Understand pattern matching instantly.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://freedevtool.org/regex-explainer">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebApplication","name":"Regex Explainer Online","url":"https://freedevtool.org/regex-explainer","description":"Translate regular expressions to plain English with color-coded breakdowns of capture groups, quantifiers, character classes, lookaheads, and anchors.","applicationCategory":"DeveloperApplication","operatingSystem":"Any","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"}}
</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[
{"@type":"Question","name":"How do I read a regular expression?","acceptedAnswer":{"@type":"Answer","text":"Read a regex left to right, breaking it into tokens: literal characters match themselves, special characters like \\d (digit), \\w (word character), and \\s (whitespace) match character classes, quantifiers like * (zero or more), + (one or more), and ? (optional) specify repetition, anchors like ^ and $ mark string boundaries, and parentheses create groups. Use a regex explainer tool to get an instant plain English translation of any pattern."}},
{"@type":"Question","name":"What does \\d, \\w, and \\s mean in regex?","acceptedAnswer":{"@type":"Answer","text":"These are shorthand character classes: \\d matches any digit (0-9), equivalent to [0-9]. \\w matches any word character (letters, digits, underscore), equivalent to [a-zA-Z0-9_]. \\s matches any whitespace character (space, tab, newline, etc.). Their uppercase versions \\D, \\W, \\S match the opposite — non-digit, non-word, non-whitespace respectively."}},
{"@type":"Question","name":"What is the difference between * and + in regex?","acceptedAnswer":{"@type":"Answer","text":"Both are quantifiers that specify repetition. The asterisk * means 'zero or more' — the preceding element can appear any number of times or not at all. The plus + means 'one or more' — the preceding element must appear at least once. For example, \\d* matches an empty string or any digits, while \\d+ requires at least one digit. Both are greedy by default; add ? after them (like *? or +?) to make them lazy (match as few as possible)."}},
{"@type":"Question","name":"How do capturing groups work in regular expressions?","acceptedAnswer":{"@type":"Answer","text":"Capturing groups are created with parentheses (). They serve two purposes: grouping parts of a pattern to apply quantifiers or alternation, and capturing the matched text for later use via backreferences (\\1, \\2) or in replacement strings ($1, $2). Non-capturing groups (?:...) group without capturing, which is more efficient when you don't need the matched text. Named groups (?<name>...) let you reference captures by name instead of number."}},
{"@type":"Question","name":"What are lookaheads and lookbehinds in regex?","acceptedAnswer":{"@type":"Answer","text":"Lookaheads and lookbehinds are zero-width assertions that check if a pattern exists ahead of or behind the current position without consuming characters. Positive lookahead (?=...) asserts that what follows matches the pattern. Negative lookahead (?!...) asserts that what follows does NOT match. Positive lookbehind (?<=...) checks what precedes, and negative lookbehind (?<!...) asserts the preceding text does NOT match. They're useful for complex pattern matching like password validation or conditional matching."}},{"@type":"Question","name":"How do I read someone else regex?","acceptedAnswer":{"@type":"Answer","text":"Read left to right, one token at a time. Identify anchors first (caret, dollar, word-boundary), then quantifiers, then character classes, then groups (capturing vs non-capturing). For complex patterns, paste into an explainer like this — automated breakdowns save hours."}},{"@type":"Question","name":"What does the question-mark colon mean in regex?","acceptedAnswer":{"@type":"Answer","text":"A non-capturing group prefix. The group syntax with question-mark colon participates in alternation and quantification but does not store the matched text in a capture group number. Use it when you only need grouping, not capturing."}},{"@type":"Question","name":"What is a non-capturing group?","acceptedAnswer":{"@type":"Answer","text":"A group that participates in alternation and quantification but does not save the matched substring. Reduces clutter when you have many groups but only care about a few. Improves regex performance slightly because the engine does not have to store the captured value."}}
]}
</script>
<style>
.regex-input-area { display:flex; gap:8px; align-items:flex-start; flex-wrap:wrap; margin-bottom:12px; }
.regex-input-area textarea {
flex:1; min-width:200px; font-family:var(--mono); font-size:16px; font-weight:500;
padding:12px 14px; background:var(--bg3); border:1px solid var(--border); color:var(--accent);
border-radius:var(--radius); resize:vertical; min-height:52px; max-height:200px;
line-height:1.5;
}
.regex-input-area textarea:focus { border-color:var(--accent2); outline:none; }
.regex-input-area textarea::placeholder { color:var(--text3); }
.flags-input {
width:80px; font-family:var(--mono); font-size:14px; font-weight:500;
padding:12px 10px; background:var(--bg3); border:1px solid var(--border); color:var(--text);
border-radius:var(--radius); text-align:center;
}
.flags-input:focus { border-color:var(--accent2); outline:none; }
.flags-input::placeholder { color:var(--text3); }
.example-row { display:flex; gap:6px; flex-wrap:wrap; margin-bottom:14px; }
.example-btn {
font-size:11px; padding:4px 10px; border-radius:var(--radius);
border:1px solid var(--border); background:var(--bg3); color:var(--text2);
cursor:pointer; font-family:var(--mono); transition:all .2s;
}
.example-btn:hover { border-color:var(--accent2); color:var(--accent); background:var(--accent-dim); }
.regex-summary {
font-size:14px; color:var(--text); text-align:left; margin-bottom:12px;
padding:12px 14px; background:var(--accent-dim); border:1px solid rgba(0,208,132,.2);
border-radius:var(--radius); line-height:1.5;
}
.regex-summary strong { color:var(--accent); }
.regex-flags-info {
font-size:12px; color:var(--text2); margin-bottom:12px;
padding:8px 12px; background:var(--bg3); border:1px solid var(--border);
border-radius:var(--radius); font-family:var(--mono);
}
.breakdown-list { list-style:none; margin:0; padding:0; }
.breakdown-item {
display:flex; align-items:flex-start; gap:12px;
padding:10px 0; border-bottom:1px solid var(--border);
font-size:13px; line-height:1.5;
}
.breakdown-item:last-child { border-bottom:none; }
.breakdown-token {
font-family:var(--mono); font-weight:600; font-size:13px;
padding:2px 8px; border-radius:4px; white-space:nowrap; flex-shrink:0;
min-width:60px; text-align:center;
}
.breakdown-desc { color:var(--text); flex:1; }
.tok-literal { background:#1e293b; color:#94a3b8; border:1px solid #334155; }
.tok-class { background:#1a1a2e; color:#a78bfa; border:1px solid #3b3270; }
.tok-quantifier{ background:#1c1917; color:#fbbf24; border:1px solid #534a2a; }
.tok-anchor { background:#0f1f1a; color:#34d399; border:1px solid #1a4a3a; }
.tok-group { background:#1e1028; color:#f472b6; border:1px solid #4a2060; }
.tok-charset { background:#172030; color:#60a5fa; border:1px solid #1e3a5f; }
.tok-escape { background:#1f1a14; color:#fb923c; border:1px solid #5a3a1a; }
.tok-alternation{ background:#1a1020; color:#e879f9; border:1px solid #4a2068; }
.tok-error { background:#2a1015; color:#ff5a5a; border:1px solid #5a2020; }
.regex-error {
padding:12px 14px; background:rgba(255,90,90,.08); border:1px solid rgba(255,90,90,.25);
border-radius:var(--radius); color:var(--red); font-size:13px; font-family:var(--mono);
}
.legend { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:14px; }
.legend-item {
font-size:10px; padding:2px 8px; border-radius:4px;
font-family:var(--mono); opacity:.7;
}
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://freedevtool.org/"
},
{
"@type": "ListItem",
"position": 2,
"name": "All Tools",
"item": "https://freedevtool.org/all-tools"
},
{
"@type": "ListItem",
"position": 3,
"name": "Regex Explainer Online",
"item": "https://freedevtool.org/regex-explainer"
}
]
}
</script>
<script src="/ga4-events.js" defer></script>
</head>
<body>
<nav>
<a class="nav-logo" href="/" aria-label="FreeDevTool home"><svg class="logo-mark" width="22" height="22" viewBox="0 0 24 24" aria-hidden="true" fill="none"><rect x="1" y="1" width="22" height="22" rx="6" fill="currentColor" opacity=".12"/><path d="M9.5 8.5L6 12l3.5 3.5M14.5 8.5L18 12l-3.5 3.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>FreeDevTool</a>
<div class="nav-links">
<div class="nav-dropdown" id="tools-dropdown">
<a href="all-tools" onclick="event.preventDefault();this.parentElement.classList.toggle('open')" aria-haspopup="true">Tools <svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></a>
<div class="nav-dropdown-menu">
<a href="encoding-tools">
<div class="dd-icon">b64</div>
<div class="dd-info"><div class="dd-name">Encoding & Conversion</div><div class="dd-count">11 tools · Base64, YAML, px→rem</div></div>
</a>
<a href="generation-tools">
<div class="dd-icon">{ }</div>
<div class="dd-info"><div class="dd-name">Generation & Formatting</div><div class="dd-count">16 tools · JSON, SQL, gradients</div></div>
</a>
<a href="security-tools">
<div class="dd-icon">#</div>
<div class="dd-info"><div class="dd-name">Security & Hashing</div><div class="dd-count">3 tools · JWT, MD5, SHA</div></div>
</a>
<a href="text-tools">
<div class="dd-icon">.*</div>
<div class="dd-info"><div class="dd-name">Code & Text Tools</div><div class="dd-count">9 tools · Regex, diff, tokens</div></div>
</a>
<a href="devops-tools">
<div class="dd-icon">JS</div>
<div class="dd-info"><div class="dd-name">Optimization & DevOps</div><div class="dd-count">7 tools · Minifiers, cURL, git</div></div>
</a>
<a href="network-tools">
<div class="dd-icon">IP</div>
<div class="dd-info"><div class="dd-name">Network & Time</div><div class="dd-count">4 tools · IP, DNS, timestamps</div></div>
</a>
<a href="seo-tools">
<div class="dd-icon">SEO</div>
<div class="dd-info"><div class="dd-name">SEO & Meta Tools</div><div class="dd-count">3 tools · OG, meta, slug</div></div>
</a>
<div class="nav-dropdown-divider"></div>
<a class="dd-all" href="all-tools">
<div class="dd-icon">All</div>
<div class="dd-info"><div class="dd-name">Browse all 50 tools</div><div class="dd-count">Searchable catalog & categories</div></div>
</a>
</div>
</div>
<a href="/guides">Guides</a>
<a href="about">About</a>
<a href="privacy">Privacy</a>
</div>
</nav>
<div id="copy-toast">Copied!</div>
<div class="wrapper">
<a class="tool-back" href="/" aria-label="Back to home">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
Back
</a>
<div class="tool-header">
<div class="tool-badge">Code Tool</div>
<h1>Regex Explainer Online</h1>
<p class="tool-description">
Translate any regular expression into plain English with a color-coded breakdown of every token. This free regex to plain English translator parses capture groups, quantifiers, character classes, lookahead and lookbehind assertions, anchors, alternation, and more. Paste a regex pattern to instantly visualize its structure — a powerful regular expression breakdown tool for understanding complex pattern matching. All processing runs client-side in your browser.
</p>
<div class="last-updated">Last updated: May 2026 · Written by <a href="/about">Anees Ur Rehman</a>, full-stack developer</div>
</div>
<div class="tool-card">
<div class="tool-card-header">
<div class="dot dot-red"></div><div class="dot dot-yellow"></div><div class="dot dot-green"></div>
<span class="tool-card-title">regex-explainer.tool</span>
</div>
<div class="tool-body">
<label>Quick Examples</label>
<div class="example-row">
<button class="example-btn" onclick="setExample('email')">Email</button>
<button class="example-btn" onclick="setExample('url')">URL</button>
<button class="example-btn" onclick="setExample('ip')">IP Address</button>
<button class="example-btn" onclick="setExample('date')">Date</button>
<button class="example-btn" onclick="setExample('phone')">Phone</button>
</div>
<label>Regex Pattern</label>
<div class="regex-input-area">
<textarea id="regex-input" rows="2" spellcheck="false" placeholder="Enter a regex pattern, e.g. ^[\w.-]+@[\w-]+\.[\w.]+$" oninput="explainRegex()"></textarea>
<input class="flags-input" type="text" id="regex-flags" placeholder="gi" value="" spellcheck="false" oninput="explainRegex()">
</div>
<div id="regex-error" style="display:none" class="regex-error"></div>
<div id="regex-summary" style="display:none" class="regex-summary"></div>
<div id="flags-info" style="display:none" class="regex-flags-info"></div>
<div id="breakdown-area" style="display:none">
<label>Color Legend</label>
<div class="legend">
<span class="legend-item tok-literal">literal</span>
<span class="legend-item tok-class">class</span>
<span class="legend-item tok-quantifier">quantifier</span>
<span class="legend-item tok-anchor">anchor</span>
<span class="legend-item tok-group">group</span>
<span class="legend-item tok-charset">charset</span>
<span class="legend-item tok-escape">escape</span>
<span class="legend-item tok-alternation">alternation</span>
</div>
<label>Token Breakdown</label>
<ul class="breakdown-list" id="breakdown-list"></ul>
</div>
<div id="empty-state" class="regex-summary" style="border-color:var(--border);background:var(--bg3);">
<span style="color:var(--text3)">Enter a regex pattern above to see a plain English explanation.</span>
</div>
</div>
</div>
<p class="aeo-lead" style="font-size:16px;line-height:1.7;color:var(--text);max-width:760px;margin:24px auto 18px;padding:0 4px">
<strong>Regular expressions</strong> (regex) are a pattern language for matching text — built into every modern language but famously hard to read. A pattern like <code>^[w._%+-]+@[w.-]+.[A-Z]{2,}$</code> matches email addresses, but you need to translate it character by character to understand. This <strong>free regex explainer</strong> produces a plain-English breakdown of any pattern — invaluable when you inherit a regex you did not write.
</p>
<section id="examples" style="max-width:760px;margin:24px auto 32px">
<h2 style="font-size:18px;margin-bottom:14px">Examples</h2>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Email regex breakdown§§Pattern: ^[\\w.-]+@[\\w.-]+\\.[A-Z]{2,}$§§^ start of string§§[\\w.-]+ one or more word chars, dots, or hyphens (local part)§§@ literal at sign§§[\\w.-]+ same for domain part§§\\. literal dot§§[A-Z]{2,} 2+ uppercase letters (TLD)§§$ end of string</strong>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Phone number with optional country code§§Pattern: ^\\+?\\d{1,3}?[-.\\s]?\\(?\\d{1,4}?\\)?[-.\\s]?\\d{1,4}[-.\\s]?\\d{1,9}$§§Handles optional +1, optional area code parens, various separators. Real-world phone validation is famously messy.</strong>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Lookahead vs lookbehind§§(?=text) — assertion that "text" follows, but does not consume§§(?<=text) — assertion that "text" precedes§§Useful for password validation: (?=.*[A-Z])(?=.*\\d) ensures at least one uppercase letter and one digit.</strong>
</div>
</section>
<aside class="founder-note" style="max-width:760px;margin:24px auto 32px;padding:20px 24px;background:rgba(0,208,132,0.05);border-left:3px solid var(--accent);border-radius:6px;font-size:14px;line-height:1.7;color:var(--text2)"><div style="font-family:var(--mono);font-size:11px;color:var(--accent);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:10px;font-weight:600">💡 Why I built this</div><p style="margin:0 0 12px">I built this after inheriting a 200-line Python service with regex patterns I could not read. The original developer had left, the patterns were correct but inscrutable, and rewriting them without breaking the test suite was terrifying. This explainer takes any regex and produces a plain-English breakdown of each token — useful for debugging legacy code, understanding patterns from Stack Overflow, or learning regex by reverse-engineering working examples.</p><p style="margin:0;font-size:13px;color:var(--text3)">— <a href="/about" style="color:var(--accent);text-decoration:none">Anees Ur Rehman</a>, full-stack developer</p></aside>
<section class="article-section">
<h2>The complete guide to reading regular expressions — tokens, dialects, and traps</h2>
<p>Regular expressions are the closest thing programming has to a universal mini-language. The same pattern, more or less, runs in your editor's find dialog, your shell's <code>grep</code>, your application's request validator, your CDN's URL rewriter, your database's <code>LIKE</code> upgrade, and your log analysis pipeline. The bad news: "more or less" is doing a lot of work in that sentence. JavaScript regex, Python <code>re</code>, PCRE, .NET, Go's RE2, and POSIX BRE/ERE all differ in features and even in the meaning of common syntax. This guide is a tour through what each token means, where dialects diverge, and the catastrophic backtracking trap that has caused outages at Stack Overflow (2016) and Cloudflare (2019).</p>
<h3>The token cheat sheet — what each character actually does</h3>
<table class="ref-table">
<thead><tr><th>Token</th><th>Meaning</th><th>Notes</th></tr></thead>
<tbody>
<tr><td><code>.</code></td><td>Any character except newline</td><td>Set the <code>s</code> (dotall) flag to include newlines.</td></tr>
<tr><td><code>^</code> / <code>$</code></td><td>Start / end of string</td><td>With <code>m</code> (multiline) flag, they match start/end of each line.</td></tr>
<tr><td><code>\d \w \s</code></td><td>Digit, word char, whitespace</td><td>In JS, ASCII-only by default. <code>u</code> flag makes them Unicode-aware in modern engines.</td></tr>
<tr><td><code>\D \W \S</code></td><td>Negation of above</td><td></td></tr>
<tr><td><code>\b</code></td><td>Word boundary (zero-width)</td><td>Between <code>\w</code> and <code>\W</code> or string edge.</td></tr>
<tr><td><code>[abc]</code> / <code>[^abc]</code></td><td>Character set / negated set</td><td>Inside a set, most metacharacters lose their meaning.</td></tr>
<tr><td><code>[a-z]</code></td><td>Range</td><td>Based on Unicode code point order.</td></tr>
<tr><td><code>?</code> <code>*</code> <code>+</code></td><td>0–1, 0–∞, 1–∞</td><td>Greedy by default.</td></tr>
<tr><td><code>{n}</code> <code>{n,}</code> <code>{n,m}</code></td><td>Exactly n / at least n / between n and m</td><td>Greedy by default.</td></tr>
<tr><td><code>??</code> <code>*?</code> <code>+?</code></td><td>Lazy versions of the above</td><td>Match as few characters as possible.</td></tr>
<tr><td><code>(...)</code></td><td>Capturing group</td><td>Backreference with <code>\1</code> in pattern, <code>$1</code> in replacement.</td></tr>
<tr><td><code>(?:...)</code></td><td>Non-capturing group</td><td>Group without saving the match — slightly faster.</td></tr>
<tr><td><code>(?<name>...)</code></td><td>Named capture (JS / .NET / Python 3.7+)</td><td>Reference with <code>\k<name></code> or <code>$<name></code>.</td></tr>
<tr><td><code>(?=...)</code> / <code>(?!...)</code></td><td>Positive / negative lookahead</td><td>Zero-width — does not consume.</td></tr>
<tr><td><code>(?<=...)</code> / <code>(?<!...)</code></td><td>Positive / negative lookbehind</td><td>JS 2018+, supported in Node 10+ and all modern browsers.</td></tr>
<tr><td><code>a|b</code></td><td>Alternation</td><td>Lowest precedence — wrap in a group when needed.</td></tr>
</tbody>
</table>
<h3>Flags — they change everything</h3>
<table class="ref-table">
<thead><tr><th>Flag</th><th>Effect</th><th>JS</th><th>Python</th><th>PCRE</th></tr></thead>
<tbody>
<tr><td><code>g</code></td><td>Global match (find all)</td><td>Yes</td><td>n/a (use <code>findall</code>)</td><td>n/a</td></tr>
<tr><td><code>i</code></td><td>Case-insensitive</td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
<tr><td><code>m</code></td><td>Multiline (<code>^$</code> per line)</td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
<tr><td><code>s</code></td><td>Dotall (<code>.</code> matches newline)</td><td>Yes (ES2018+)</td><td>Yes</td><td>Yes</td></tr>
<tr><td><code>u</code></td><td>Unicode-aware</td><td>Yes</td><td>Default in Python 3</td><td>Yes</td></tr>
<tr><td><code>x</code></td><td>Extended (allow whitespace and comments in pattern)</td><td>No</td><td>Yes</td><td>Yes</td></tr>
<tr><td><code>v</code></td><td>Unicode-set (set operations)</td><td>Yes (ES2024+)</td><td>No</td><td>No</td></tr>
</tbody>
</table>
<p>The dialect minefield: JavaScript's <code>g</code> flag turns the same regex into a stateful object where each call to <code>.exec()</code> advances <code>.lastIndex</code>. Python instead exposes <code>re.match</code>, <code>re.search</code>, <code>re.findall</code>, and <code>re.finditer</code> as separate functions. PCRE has neither, leaving iteration to the host language.</p>
<h3>Catastrophic backtracking — the regex outage pattern</h3>
<p>The most expensive regex bugs do not produce wrong matches; they produce <em>infinite work</em>. The pattern is called catastrophic backtracking, and it happens when the regex engine has to try exponentially many positions before declaring a non-match. The two ingredients:</p>
<ol>
<li>Nested quantifiers — typically <code>(a+)+</code>, <code>(.*)*</code>, or <code>(\w+)*</code>.</li>
<li>An input that almost-but-not-quite matches.</li>
</ol>
<p>The Stack Overflow outage of July 2016 was a regex on user-agent strings: <code>^[\s]+|[\s]+$</code>. With a long input ending in non-whitespace, the engine tried every combination of starting positions before giving up. Cloudflare's July 2019 outage was the same pattern in a WAF rule. The defensive habits:</p>
<ul>
<li><strong>Avoid nested quantifiers</strong> on the same character class. Rewrite <code>(\w+)+</code> as <code>\w+</code>.</li>
<li><strong>Use atomic groups</strong> <code>(?>...)</code> or possessive quantifiers <code>*+ ++</code> in PCRE / .NET to prevent backtracking into the group.</li>
<li><strong>Use a linear-time engine</strong> for adversarial input. Go's RE2, Rust's regex crate, and Hyperscan all guarantee O(n) — at the cost of dropping backreferences and lookarounds.</li>
<li><strong>Bound the input.</strong> If you cap user-agent strings at 1 KB, even a quadratic regex finishes in microseconds.</li>
</ul>
<h3>Why "validating an email with regex" is a trap</h3>
<p>Every junior developer writes <code>^[\w.-]+@[\w.-]+\.\w+$</code> at some point and ships a bug. The complete RFC 5321 / 5322 grammar is over 6 000 characters of regex, allows internal-domain literals, IP literals (<code>user@[10.0.0.1]</code>), quoted local parts (<code>"a@b"@example.com</code>), and Unicode (<code>用户@例子.中国</code>). The one-paragraph rule:</p>
<ul>
<li>Use a permissive shape check: <code>/^[^@\s]+@[^@\s]+\.[^@\s]+$/</code>.</li>
<li>Then send a verification email. Deliverability is the only real test of validity.</li>
<li>For server-side validation, use a vetted library: <code>email-validator</code> in Python, <code>email-addresses</code> in Node.js, <code>commons-validator</code> in Java.</li>
</ul>
<h3>Writing regexes that are easy to read in 6 months</h3>
<ol>
<li><strong>Use the <code>x</code> (extended) flag</strong> in any language that supports it (Python, PCRE, Ruby) so you can split a long regex across lines with comments.</li>
<li><strong>Use named captures</strong> <code>(?<year>\d{4})</code> instead of bare numbered groups. The replacement string and the future reader both benefit.</li>
<li><strong>Prefer character classes to alternation</strong> when the alternatives are single characters: <code>[abc]</code> beats <code>(?:a|b|c)</code>.</li>
<li><strong>Anchor your patterns.</strong> An unanchored regex over a string column allows partial matches, which has been the source of multiple privacy bugs in URL-routing rules.</li>
<li><strong>Test against adversarial input.</strong> Tools like <code>regex101.com</code>, <code>regexr.com</code>, and this explainer help; for production, fuzz with long-repeating input to catch backtracking.</li>
<li><strong>Use a regex linter.</strong> ESLint's <code>regexp/no-super-linear-backtracking</code> catches the <code>(a+)+</code> family at lint time.</li>
</ol>
<h3>Common regex mistakes that ship to production</h3>
<ul>
<li><strong>Forgetting to escape the dot</strong> in URL/host patterns. <code>example.com</code> the regex matches <code>example-com</code> too.</li>
<li><strong>Anchoring without the <code>m</code> flag.</strong> <code>^foo</code> only matches at string start unless multiline is on.</li>
<li><strong>Using <code>.*</code> across newlines without <code>s</code>.</strong> The match silently stops at the first <code>\n</code>.</li>
<li><strong>Greedy matching gone wrong.</strong> <code><.*></code> on <code><a>hi</a></code> grabs the entire string. Use <code><.*?></code> or <code><[^>]*></code>.</li>
<li><strong>Confusing replacement-string dollar signs with regex dollar signs.</strong> In <code>str.replace(/(\d+)/, '$1!')</code>, the <code>$</code> belongs to the replacement template, not the regex.</li>
<li><strong>Using regex on HTML or JSON.</strong> Both are not regular languages. Use a real parser (DOMParser, <code>JSON.parse</code>); regex will produce surprises.</li>
<li><strong>Forgetting that JavaScript's <code>g</code> flag is stateful.</strong> Reusing a global regex between callsites without resetting <code>lastIndex</code> causes mysteriously skipping matches.</li>
</ul>
<h3>Same intent in 4 dialects — extracting an ISO date</h3>
<div class="lang-block"><strong>JavaScript:</strong><pre><code>const m = "2026-05-02".match(/^(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})$/);
console.log(m.groups.y, m.groups.m, m.groups.d);</code></pre></div>
<div class="lang-block"><strong>Python:</strong><pre><code>import re
m = re.fullmatch(r'(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})', "2026-05-02")
print(m.group('y'), m.group('m'), m.group('d'))</code></pre></div>
<div class="lang-block"><strong>Go (RE2 — no lookarounds, no backreferences):</strong><pre><code>re := regexp.MustCompile(`^(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})$`)
m := re.FindStringSubmatch("2026-05-02")</code></pre></div>
<div class="lang-block"><strong>Rust (regex crate, also linear-time):</strong><pre><code>use regex::Regex;
let re = Regex::new(r"^(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})$").unwrap();
let caps = re.captures("2026-05-02").unwrap();
println!("{} {} {}", &caps["y"], &caps["m"], &caps["d"]);</code></pre></div>
<aside class="article-aside">
<strong>Authoritative references:</strong>
<ul>
<li><a href="https://tc39.es/ecma262/#sec-regexp-regular-expression-objects" rel="noopener" target="_blank">ECMA-262 — RegExp specification (the canonical JS regex grammar)</a></li>
<li><a href="https://docs.python.org/3/library/re.html" rel="noopener" target="_blank">Python — re module (official documentation)</a></li>
<li><a href="https://github.com/google/re2/wiki/Syntax" rel="noopener" target="_blank">Google RE2 — syntax reference (linear-time engine)</a></li>
<li><a href="https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019/" rel="noopener" target="_blank">Cloudflare — postmortem of the 2019 regex-driven outage</a></li>
<li><a href="https://www.regular-expressions.info/" rel="noopener" target="_blank">regular-expressions.info — comprehensive cross-dialect reference</a></li>
</ul>
</aside>
</section>
<!-- How to use + mistakes -->
<section class="use-cases">
<h2>Best regex explainer for 2026 — what to compare</h2>
<p>Search results for "regex explainer", "regex to plain english", and "what does this regex mean" return a mix of static cheat-sheets and interactive tools. Three things separate the good from the noise: dialect awareness (PCRE / JavaScript / Python / Java differ in lookbehind, possessive quantifiers, named groups), color-coded token highlighting (versus a wall of explanation text), and live match preview against sample strings. Here is how the most-used regex explainer tools compare in 2026:</p>
<table class="ref-table">
<thead><tr><th>Tool</th><th>Multi-dialect</th><th>Color-coded breakdown</th><th>Live match preview</th><th>Free tier</th><th>Cost</th></tr></thead>
<tbody>
<tr><td>FreeDevTool Regex Explainer</td><td>JS + PCRE + Python + Java + .NET</td><td>Yes</td><td>Yes</td><td>Free, no signup</td><td>Free</td></tr>
<tr><td>regex101.com</td><td>PCRE/PCRE2 + JS + Python + Go + Java</td><td>Hover-tooltip</td><td>Yes</td><td>Free + paid Pro</td><td>Freemium</td></tr>
<tr><td>regexr.com</td><td>JS only</td><td>Side panel</td><td>Yes</td><td>Free</td><td>Free</td></tr>
<tr><td>regextester.com</td><td>JS only</td><td>Limited</td><td>Yes</td><td>Free, ad-funded</td><td>Free</td></tr>
<tr><td>extendsclass.com/regex-tester</td><td>JS + PCRE</td><td>Limited</td><td>Yes</td><td>Free</td><td>Free, ad-funded</td></tr>
<tr><td>VS Code Regex Previewer extension</td><td>JS</td><td>Inline IDE</td><td>Live as you type</td><td>Free</td><td>Free</td></tr>
</tbody>
</table>
<h3>How do I read a complex regex like /^(?=.*[A-Z])(?=.*\d).{8,}$/?</h3>
<p>Break it left to right by token. <code>^</code> = start of string. <code>(?=.*[A-Z])</code> = positive lookahead asserting at least one uppercase letter exists somewhere ahead (zero-width — doesn't consume). <code>(?=.*\d)</code> = second lookahead, at least one digit ahead. <code>.{8,}</code> = any 8+ characters. <code>$</code> = end of string. Combined: <strong>"the entire string is at least 8 characters long AND contains at least one uppercase letter AND at least one digit."</strong> This is a typical password-strength regex. Paste it into the explainer above and each lookahead, character class, and quantifier highlights with its meaning. Read complex regexes in this order: anchors first (<code>^</code> <code>$</code>), then lookarounds (<code>(?=)</code> <code>(?!)</code> <code>(?<=)</code> <code>(?<!)</code>), then capture groups (<code>()</code>), then character classes (<code>[]</code> <code>\d</code> <code>\w</code> <code>\s</code>), then quantifiers (<code>*</code> <code>+</code> <code>?</code> <code>{n,m}</code>).</p>
<h3>What's the difference between PCRE, JavaScript, and Python regex?</h3>
<table class="ref-table">
<thead><tr><th>Feature</th><th>PCRE / PCRE2</th><th>JavaScript (ES2018+)</th><th>Python (re)</th><th>Java</th></tr></thead>
<tbody>
<tr><td>Lookbehind</td><td>Variable-length</td><td>Variable-length (Chrome 62+)</td><td>Fixed-length only</td><td>Variable-length</td></tr>
<tr><td>Named groups</td><td><code>(?P<name>...)</code> or <code>(?<name>...)</code></td><td><code>(?<name>...)</code></td><td><code>(?P<name>...)</code></td><td><code>(?<name>...)</code></td></tr>
<tr><td>Possessive quantifiers</td><td><code>++</code> <code>*+</code> <code>?+</code></td><td>No native (use atomic groups)</td><td>No native</td><td><code>++</code> <code>*+</code> <code>?+</code></td></tr>
<tr><td>Atomic groups</td><td><code>(?>...)</code></td><td>No</td><td>No (3.11 has <code>(?>...)</code>)</td><td><code>(?>...)</code></td></tr>
<tr><td>Recursive patterns</td><td><code>(?R)</code> or <code>(?0)</code></td><td>No</td><td>No (use <code>regex</code> module)</td><td>No</td></tr>
<tr><td>Unicode property escapes</td><td><code>\p{...}</code></td><td><code>\p{...}</code> (with <code>u</code> flag)</td><td>No (use <code>regex</code> module)</td><td><code>\p{...}</code></td></tr>
</tbody>
</table>
<p>Same pattern can behave differently across engines. The classic gotcha: variable-length lookbehind <code>(?<=foo|bar)</code> works in PCRE/JS/Java but fails in Python's stdlib <code>re</code>. Pick the dialect dropdown matching your runtime when explaining a pattern; "regex" is not a single language.</p>
<h3>Regex explainer alternative to regex101 — 4 reasons developers switched</h3>
<ol>
<li><strong>No login wall for advanced features.</strong> regex101's "Code generator", "Quiz", and unit-test panels are gated behind paid Pro. This page is fully free with no signup.</li>
<li><strong>Multi-dialect explanation, not just multi-engine matching.</strong> regex101 switches engines to test matches; this tool also <em>explains</em> tokens differently per dialect (e.g., shows that <code>(?P<name>)</code> works in Python but is <code>(?<name>)</code> in JS).</li>
<li><strong>Inline color-coded breakdown.</strong> regex101 uses a hover-tooltip pattern; this page renders each token as a colored chip with the explanation underneath — easier to screenshot and share in PR reviews.</li>
<li><strong>No ads, no third-party trackers.</strong> regex101 runs Cloudflare Insights + Google Analytics. This page is browser-only with first-party GA only.</li>
</ol>
<p>Pair the regex explainer with the <a href="/regex-tester">Regex Tester</a> for live match testing on real input, the <a href="/string-escape">String Escape Tool</a> for escaping regex metacharacters in source code, and the <a href="/text-tools">Code & Text Tools hub</a> for the broader text-manipulation toolkit.</p>
<h2>How to use the regex explainer</h2>
<p>Inherit a 200-character regex from a previous developer? Paste it here and the explainer translates it to plain English with color-coded breakdowns of every group, quantifier, character class, lookaround, and anchor. Useful for code review, learning, and figuring out why your pattern doesn't match what you thought.</p>
<ul class="use-case-list">
<li><strong>1.</strong> Paste the regex pattern (without surrounding slashes). Auto-detects flags from inline modifiers (<code>(?i)</code>) and you can toggle them via the flag buttons.</li>
<li><strong>2.</strong> The pattern renders with color-coded segments: groups in blue, quantifiers in orange, character classes in teal, anchors in red. Hover any segment for a tooltip.</li>
<li><strong>3.</strong> Read the plain-English breakdown below. Each line maps a regex segment to a sentence ("matches a digit, one or more times", "captures a group of letters", etc).</li>
<li><strong>4.</strong> Toggle the visual railroad diagram for branching patterns — alternations and groups become tracks, much easier to follow than text.</li>
<li><strong>5.</strong> Copy individual sub-patterns out for reuse, or share the explainer URL with the encoded regex for code-review comments.</li>
</ul>
<h3>Common mistakes to avoid</h3>
<ul class="mistakes-list">
<li><strong>Greedy <code>.*</code> matching too much.</strong> By default <code>.*</code> grabs as much as possible. Use <code>.*?</code> (lazy) for shortest match — e.g. inside HTML tags.</li>
<li><strong>Forgetting to escape the dot.</strong> <code>.</code> matches any character. Use <code>\.</code> for a literal period.</li>
<li><strong>Anchors without the <code>m</code> flag.</strong> <code>^</code>/<code>$</code> match start/end of string, not line, unless you set multiline mode.</li>
<li><strong>Catastrophic backtracking.</strong> Patterns like <code>(a+)+</code> on long input can hang for seconds. Use atomic groups, possessive quantifiers, or rewrite to be linear.</li>
<li><strong>Dialect mismatch.</strong> JS regex differs from PCRE, Python <code>re</code>, Ruby <code>Regexp</code>. Lookbehinds, named groups, and Unicode escapes vary. Test in the dialect you'll deploy.</li>
<li><strong>Validating emails with regex.</strong> The full RFC 5322 grammar is > 6000 chars. Use a simple check (<code>.+@.+\..+</code>) and verify deliverability separately.</li>
</ul>
</section>
<section class="faq-section">
<h2>Frequently Asked Questions</h2>
<div class="faq-item open">
<div class="faq-q" onclick="toggleFaq(this)">How do I read a regular expression?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">Read a regex <strong>left to right</strong>, breaking it into tokens. Literal characters match themselves. Special sequences like <code>\d</code>, <code>\w</code>, and <code>\s</code> match character classes (digits, word characters, whitespace). Quantifiers like <code>*</code>, <code>+</code>, and <code>?</code> control how many times the preceding token repeats. Anchors like <code>^</code> and <code>$</code> mark the start and end of the string. Parentheses <code>()</code> create capturing groups, and square brackets <code>[]</code> define character sets. Use this regex explainer tool to instantly translate any pattern into plain English.</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">What does \d, \w, and \s mean in regex?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">These are <strong>shorthand character classes</strong>: <code>\d</code> matches any digit (0–9), equivalent to <code>[0-9]</code>. <code>\w</code> matches any word character (letters, digits, underscore), equivalent to <code>[a-zA-Z0-9_]</code>. <code>\s</code> matches whitespace (space, tab, newline). Their uppercase counterparts <code>\D</code>, <code>\W</code>, <code>\S</code> match the <strong>opposite</strong> — non-digit, non-word character, and non-whitespace respectively. The dot <code>.</code> matches any character except newline (unless the <code>s</code> flag is set).</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">What is the difference between * and + in regex?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">Both are <strong>quantifiers</strong>. The asterisk <code>*</code> means "zero or more" — the preceding element may appear any number of times or not at all. The plus <code>+</code> means "one or more" — the preceding element must appear at least once. For example, <code>\d*</code> matches an empty string or any sequence of digits, while <code>\d+</code> requires at least one digit. Add <code>?</code> after either (<code>*?</code>, <code>+?</code>) to make them <strong>lazy</strong>, matching as few characters as possible instead of as many.</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">How do capturing groups work in regular expressions?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">Capturing groups are created with <code>()</code>. They <strong>group</strong> parts of a pattern together (to apply quantifiers or alternation) and <strong>capture</strong> the matched text for backreferences (<code>\1</code>, <code>\2</code>) or replacement strings (<code>$1</code>, <code>$2</code>). Non-capturing groups <code>(?:...)</code> group without saving the match, which is more efficient. Named groups <code>(?<name>...)</code> allow referencing by name instead of number. Groups are numbered left to right by their opening parenthesis.</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">What are lookaheads and lookbehinds in regex?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">Lookaheads and lookbehinds are <strong>zero-width assertions</strong> — they check if a pattern exists without consuming characters. <code>(?=...)</code> is a positive lookahead: it asserts that what follows matches the pattern. <code>(?!...)</code> is a negative lookahead: asserts what follows does NOT match. <code>(?<=...)</code> is a positive lookbehind: checks what precedes. <code>(?<!...)</code> is a negative lookbehind: asserts the preceding text does NOT match. They are essential for complex pattern matching like password validation or extracting text between delimiters.</div>
</div>
</section>
<section class="related-section">
<h2>Related Tools</h2>
<div class="related-grid">
<a class="related-card" href="regex-tester"><div class="related-icon">.*</div><div class="related-card-info"><div class="related-card-name">Regex Tester</div><div class="related-card-desc">Test regular expressions live</div></div></a>
<a class="related-card" href="string-escape"><div class="related-icon">\</div><div class="related-card-info"><div class="related-card-name">String Escape Tool</div><div class="related-card-desc">Escape and unescape strings</div></div></a>
<a class="related-card" href="text-diff"><div class="related-icon">±</div><div class="related-card-info"><div class="related-card-name">Text Diff Checker</div><div class="related-card-desc">Compare two texts side by side</div></div></a>
</div>
</section>
<section class="all-tools-section" aria-label="Browse all FreeDevTool developer tools">
<h2>Browse all 50 free developer tools</h2>
<p class="atc-sub">All tools run in your browser, no signup required, nothing sent to a server.</p>
<div class="all-tools-grid">
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">b64</div>
<div class="atc-cat-title"><h3>Encoding & Conversion</h3><span class="atc-cat-count">11 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/base64-encoder">Base64 Encoder / Decoder</a></li>
<li><a href="/base64-image">Image to Base64</a></li>
<li><a href="/byte-converter">Byte Converter (KB / MB / GB)</a></li>
<li><a href="/case-converter">Case Converter</a></li>
<li><a href="/hex-to-rgb">Hex to RGB / HSL</a></li>
<li><a href="/html-entity">HTML Entity Encoder</a></li>
<li><a href="/json-to-csv">JSON to CSV Converter</a></li>
<li><a href="/px-to-rem">PX to REM Converter</a></li>
<li><a href="/string-escape">String Escape / Unescape</a></li>
<li><a href="/url-encoder">URL Encoder / Decoder</a></li>
<li><a href="/yaml-to-json">YAML to JSON Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">{ }</div>
<div class="atc-cat-title"><h3>Formatting & Generators</h3><span class="atc-cat-count">13 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/color-name">Color Name from Hex</a></li>
<li><a href="/color-picker">Color Palette Picker</a></li>
<li><a href="/css-box-shadow">CSS Box Shadow</a></li>
<li><a href="/css-gradient">CSS Gradient Generator</a></li>
<li><a href="/json-formatter">JSON Formatter / Validator</a></li>
<li><a href="/lorem-ipsum">Lorem Ipsum Generator</a></li>
<li><a href="/markdown-preview">Markdown Preview</a></li>
<li><a href="/password-generator">Password Generator</a></li>
<li><a href="/qr-generator">QR Code Generator</a></li>
<li><a href="/sql-formatter">SQL Formatter</a></li>
<li><a href="/uuid-generator">UUID Generator</a></li>
<li><a href="/word-to-markdown">Word to Markdown</a></li>
<li><a href="/xml-formatter">XML Formatter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">JS</div>
<div class="atc-cat-title"><h3>Minifiers & DevOps</h3><span class="atc-cat-count">6 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/chmod-calculator">chmod Calculator</a></li>
<li><a href="/cron-parser">Cron Expression Parser</a></li>
<li><a href="/css-minifier">CSS Minifier</a></li>
<li><a href="/html-minifier">HTML Minifier</a></li>
<li><a href="/js-minifier">JavaScript Minifier</a></li>
<li><a href="/http-status">HTTP Status Codes</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">#</div>
<div class="atc-cat-title"><h3>Security & Hashing</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/hash-generator">Hash Generator (MD5, SHA)</a></li>
<li><a href="/jwt-decoder">JWT Decoder</a></li>
<li><a href="/jwt-generator">JWT Generator</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">.*</div>
<div class="atc-cat-title"><h3>Code & Text</h3><span class="atc-cat-count">8 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/ai-token-counter">AI Token Counter</a></li>
<li><a href="/char-counter">Character & Word Counter</a></li>
<li><a href="/git-cheatsheet">Git Commands Cheatsheet</a></li>
<li><a href="/number-base">Number Base Converter</a></li>
<li><a href="/regex-explainer">Regex Explainer</a></li>
<li><a href="/regex-tester">Regex Tester</a></li>
<li><a href="/text-diff">Text Diff Checker</a></li>
<li><a href="/wcag-contrast">WCAG Contrast Checker</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">IP</div>
<div class="atc-cat-title"><h3>Network & APIs</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/dns-lookup">DNS Lookup</a></li>
<li><a href="/http-request-builder">HTTP Request Builder</a></li>
<li><a href="/ip-lookup">IP Address Lookup</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">⏱</div>
<div class="atc-cat-title"><h3>Time & Dates</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/relative-time">Relative Time Calculator</a></li>
<li><a href="/timestamp-diff">Timestamp Diff</a></li>
<li><a href="/unix-timestamp-converter">Unix Timestamp Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">SEO</div>
<div class="atc-cat-title"><h3>SEO & Meta</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/meta-tag-generator">Meta Tag Generator</a></li>
<li><a href="/og-preview">Open Graph Preview</a></li>
<li><a href="/slug-generator">URL Slug Generator</a></li>
</ul>
</div>
</div>
</section>
</div>
<footer>
<div>© 2026 FreeDevTool — Regex Explainer</div>
<div class="footer-links"><a href="/all-tools">All Tools</a><a href="/about">About</a><a href="/privacy">Privacy Policy</a><a href="/terms">Terms of Use</a></div>
</footer>
<script>
const EXAMPLES = {
email: { pattern: '^[\\w.-]+@[\\w-]+\\.[\\w.]+$', flags: '' },
url: { pattern: 'https?:\\/\\/[\\w.-]+(?:\\.[a-z]{2,})(?:\\/[\\w./?#&=-]*)?', flags: 'i' },
ip: { pattern: '\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b', flags: 'g' },
date: { pattern: '(\\d{4})-(\\d{2})-(\\d{2})', flags: '' },
phone: { pattern: '\\+?1?[-.\\s]?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}', flags: '' }
};
const KNOWN_PATTERNS = {
'^[\\w.-]+@[\\w-]+\\.[\\w.]+$': 'Matches: an email address pattern (local@domain.tld)',
'https?:\\/\\/[\\w.-]+(?:\\.[a-z]{2,})(?:\\/[\\w./?#&=-]*)?': 'Matches: a URL (http or https)',
'\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b': 'Matches: an IPv4 address (e.g. 192.168.1.1)',
'(\\d{4})-(\\d{2})-(\\d{2})': 'Matches: a date in YYYY-MM-DD format',
'\\+?1?[-.\\s]?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}': 'Matches: a US/international phone number'
};
function setExample(name) {
const ex = EXAMPLES[name];
document.getElementById('regex-input').value = ex.pattern;
document.getElementById('regex-flags').value = ex.flags;
explainRegex();
}
/* ---- Tokenizer ---- */
function tokenize(pattern) {
const tokens = [];
let i = 0, groupNum = 0;
while (i < pattern.length) {
const ch = pattern[i];
// Escaped characters
if (ch === '\\' && i + 1 < pattern.length) {
const next = pattern[i + 1];
const escMap = {
'd': ['\\d','digit (0-9)','class'],
'D': ['\\D','non-digit','class'],
'w': ['\\w','word character (a-z, A-Z, 0-9, _)','class'],
'W': ['\\W','non-word character','class'],
's': ['\\s','whitespace (space, tab, newline)','class'],
'S': ['\\S','non-whitespace','class'],
'b': ['\\b','word boundary','anchor'],
'B': ['\\B','non-word boundary','anchor'],
'n': ['\\n','newline','escape'],
'r': ['\\r','carriage return','escape'],
't': ['\\t','tab','escape'],
'f': ['\\f','form feed','escape'],
'v': ['\\v','vertical tab','escape'],
'0': ['\\0','null character','escape']
};
if (escMap[next]) {
tokens.push({ token: escMap[next][0], desc: escMap[next][1], type: escMap[next][2] });
i += 2; continue;
}
// Backreference \1-\9
if (next >= '1' && next <= '9') {
tokens.push({ token: '\\' + next, desc: 'backreference to group ' + next, type: 'group' });
i += 2; continue;
}
// Escaped literal
tokens.push({ token: '\\' + next, desc: 'literal "' + next + '"', type: 'escape' });
i += 2; continue;
}
// Character set [...]
if (ch === '[') {
let j = i + 1, negated = false;
if (pattern[j] === '^') { negated = true; j++; }
// Allow ] as first char in set
if (pattern[j] === ']') j++;
while (j < pattern.length && pattern[j] !== ']') {
if (pattern[j] === '\\') j++;
j++;
}
const setContent = pattern.slice(i + 1 + (negated ? 1 : 0), j);
const full = pattern.slice(i, j + 1);
let desc;
if (negated) {
desc = 'not one of: ' + describeCharset(setContent);
} else {
desc = 'one of: ' + describeCharset(setContent);
}
tokens.push({ token: full, desc: desc, type: 'charset' });
i = j + 1; continue;
}
// Groups
if (ch === '(') {
if (pattern.slice(i, i + 3) === '(?:') {
tokens.push({ token: '(?:', desc: 'start non-capturing group', type: 'group' });
i += 3; continue;
}
if (pattern.slice(i, i + 3) === '(?=') {
tokens.push({ token: '(?=', desc: 'start positive lookahead', type: 'group' });
i += 3; continue;
}
if (pattern.slice(i, i + 3) === '(?!') {
tokens.push({ token: '(?!', desc: 'start negative lookahead', type: 'group' });
i += 3; continue;
}
if (pattern.slice(i, i + 4) === '(?<=') {
tokens.push({ token: '(?<=', desc: 'start positive lookbehind', type: 'group' });
i += 4; continue;
}
if (pattern.slice(i, i + 4) === '(?<!') {
tokens.push({ token: '(?<!', desc: 'start negative lookbehind', type: 'group' });
i += 4; continue;
}
// Named group
const namedMatch = pattern.slice(i).match(/^\(\?<([^>]+)>/);
if (namedMatch) {
groupNum++;
tokens.push({ token: namedMatch[0], desc: 'start named capturing group "' + namedMatch[1] + '" (group ' + groupNum + ')', type: 'group' });
i += namedMatch[0].length; continue;
}
groupNum++;
tokens.push({ token: '(', desc: 'start capturing group ' + groupNum, type: 'group' });
i++; continue;
}
if (ch === ')') {
tokens.push({ token: ')', desc: 'end group', type: 'group' });
i++; continue;
}
// Anchors
if (ch === '^') {
tokens.push({ token: '^', desc: 'start of string', type: 'anchor' });
i++; continue;
}
if (ch === '$') {
tokens.push({ token: '$', desc: 'end of string', type: 'anchor' });
i++; continue;
}
// Alternation
if (ch === '|') {
tokens.push({ token: '|', desc: 'OR (alternation)', type: 'alternation' });
i++; continue;
}
// Dot
if (ch === '.') {
tokens.push({ token: '.', desc: 'any character (except newline)', type: 'class' });
i++; continue;
}
// Quantifiers
if (ch === '*' || ch === '+' || ch === '?') {
// Check for lazy modifier
if (ch === '?' && tokens.length > 0 && (tokens[tokens.length-1].type === 'quantifier')) {
tokens[tokens.length-1].token += '?';
tokens[tokens.length-1].desc += ' (lazy, match as few as possible)';
i++; continue;
}
const qMap = { '*': 'zero or more', '+': 'one or more', '?': 'optional (zero or one)' };
let qToken = ch, qDesc = qMap[ch];
if (i + 1 < pattern.length && pattern[i + 1] === '?') {
qToken += '?';
qDesc += ' (lazy, match as few as possible)';
i++;
}
tokens.push({ token: qToken, desc: qDesc, type: 'quantifier' });
i++; continue;
}
// Curly brace quantifier {n}, {n,}, {n,m}
if (ch === '{') {
const braceMatch = pattern.slice(i).match(/^\{(\d+)(?:(,)(\d*))?\}/);
if (braceMatch) {
const full = braceMatch[0];
const n = braceMatch[1];
const hasComma = braceMatch[2];
const m = braceMatch[3];
let desc;
if (!hasComma) {
desc = 'exactly ' + n + ' times';
} else if (m === '' || m === undefined) {
desc = n + ' or more times';
} else {
desc = 'between ' + n + ' and ' + m + ' times';
}
let qToken = full;
if (i + full.length < pattern.length && pattern[i + full.length] === '?') {
qToken += '?';
desc += ' (lazy)';
i++;
}
tokens.push({ token: qToken, desc: desc, type: 'quantifier' });
i += full.length; continue;
}
}
// Literal character
tokens.push({ token: ch, desc: 'literal "' + ch + '"', type: 'literal' });
i++;
}
return tokens;
}
function describeCharset(content) {
const parts = [];
let i = 0;
while (i < content.length) {
if (content[i] === '\\' && i + 1 < content.length) {
const escShort = { d:'digit', D:'non-digit', w:'word char', W:'non-word', s:'whitespace', S:'non-whitespace' };
if (escShort[content[i+1]]) {
parts.push(escShort[content[i+1]]);
} else {
parts.push(content[i+1]);
}
i += 2; continue;
}
// Range a-z
if (i + 2 < content.length && content[i + 1] === '-' && content[i + 2] !== ']') {
parts.push(content[i] + ' through ' + content[i + 2]);
i += 3; continue;
}
parts.push(content[i]);
i++;
}
return parts.join(', ');
}
function describeFlags(flags) {
const flagMap = {
g: 'global — find all matches, not just the first',
i: 'case-insensitive — ignore upper/lower case',
m: 'multiline — ^ and $ match start/end of each line',
s: 'dotAll — dot (.) also matches newline characters',
u: 'unicode — enable full Unicode matching'
};
const parts = [];
for (const f of flags) {
if (flagMap[f]) parts.push(f + ': ' + flagMap[f]);
}
return parts;
}
function explainRegex() {
const pattern = document.getElementById('regex-input').value;
const flags = document.getElementById('regex-flags').value.trim();
const errorEl = document.getElementById('regex-error');
const summaryEl = document.getElementById('regex-summary');
const flagsEl = document.getElementById('flags-info');
const breakdownEl = document.getElementById('breakdown-area');
const emptyEl = document.getElementById('empty-state');
const listEl = document.getElementById('breakdown-list');
errorEl.style.display = 'none';
summaryEl.style.display = 'none';
flagsEl.style.display = 'none';
breakdownEl.style.display = 'none';
if (!pattern) {
emptyEl.style.display = '';
return;
}
emptyEl.style.display = 'none';
// Validate regex
try {
new RegExp(pattern, flags);
} catch (e) {
errorEl.style.display = '';
errorEl.textContent = '\u2717 ' + e.message;
return;
}
// Known pattern summary
if (KNOWN_PATTERNS[pattern]) {
summaryEl.style.display = '';
summaryEl.innerHTML = '<strong>' + KNOWN_PATTERNS[pattern] + '</strong>';
}
// Flags info
if (flags.length > 0) {
const flagDescs = describeFlags(flags);
if (flagDescs.length > 0) {
flagsEl.style.display = '';
flagsEl.innerHTML = '<strong>Flags:</strong> ' + flagDescs.join(' | ');
}
}
// Tokenize and render
const tokens = tokenize(pattern);
breakdownEl.style.display = '';
let html = '';
for (const t of tokens) {
const tokClass = 'tok-' + t.type;
const escapedToken = escHtml(t.token);
const escapedDesc = escHtml(t.desc);
html += '<li class="breakdown-item"><span class="breakdown-token ' + tokClass + '">' + escapedToken + '</span><span class="breakdown-desc">' + escapedDesc + '</span></li>';
}
listEl.innerHTML = html;
}
function escHtml(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
}
function showToast() { const t=document.getElementById('copy-toast');t.classList.add('show');setTimeout(()=>t.classList.remove('show'),1800); }
function toggleFaq(el) { el.parentElement.classList.toggle('open'); }
// Init
explainRegex();
</script>
<script>document.addEventListener('click',e=>{const dd=document.getElementById('tools-dropdown');if(dd&&!dd.contains(e.target))dd.classList.remove('open')});</script>
</body>
</html>