$npx -y skills add girijashankarj/cursor-handbook --skill regex-builderBuild, explain, and test regular expressions step-by-step with plain-English breakdowns. Use when the user asks to create, debug, or explain a regex pattern.
| 1 | # Skill: Regex Builder |
| 2 | |
| 3 | Construct and explain regular expressions incrementally with test cases and plain-English documentation. |
| 4 | |
| 5 | ## Trigger |
| 6 | When the user asks to build, create, explain, debug, or optimize a regular expression. |
| 7 | |
| 8 | ## Prerequisites |
| 9 | - [ ] Target pattern or matching criteria described |
| 10 | - [ ] Sample inputs (should match and should NOT match) |
| 11 | - [ ] Target language/flavor (JavaScript, Python, Go, PCRE) |
| 12 | |
| 13 | ## Steps |
| 14 | |
| 15 | ### Step 1: Clarify Requirements |
| 16 | - [ ] What should the regex match? (exact description) |
| 17 | - [ ] What should it NOT match? (edge cases) |
| 18 | - [ ] Capture groups needed? (which parts to extract) |
| 19 | - [ ] Flags needed? (case-insensitive, multiline, global, dotall) |
| 20 | - [ ] Performance constraints? (large input, many matches) |
| 21 | |
| 22 | ### Step 2: Build Incrementally |
| 23 | |
| 24 | Start with the simplest pattern that matches, then refine: |
| 25 | |
| 26 | 1. **Literal match** — match the exact string first |
| 27 | 2. **Character classes** — generalize with `[a-z]`, `\d`, `\w` |
| 28 | 3. **Quantifiers** — add `+`, `*`, `{n,m}` for repetition |
| 29 | 4. **Anchors** — add `^`, `$` for position |
| 30 | 5. **Groups** — add `()` for captures, `(?:)` for non-capturing |
| 31 | 6. **Alternation** — add `|` for OR logic |
| 32 | 7. **Lookahead/behind** — add `(?=)`, `(?<=)` for assertions |
| 33 | |
| 34 | ### Step 3: Document the Pattern |
| 35 | |
| 36 | Break down every component: |
| 37 | |
| 38 | ``` |
| 39 | Pattern: ^(?<protocol>https?):\/\/(?<domain>[a-zA-Z0-9.-]+)(?::(?<port>\d{1,5}))?(?<path>\/[^\s?#]*)?(?:\?(?<query>[^\s#]*))?(?:#(?<fragment>\S*))?$ |
| 40 | |
| 41 | Breakdown: |
| 42 | ^ Start of string |
| 43 | (?<protocol>https?) Capture "http" or "https" |
| 44 | :\/\/ Literal "://" |
| 45 | (?<domain>[a-zA-Z0-9.-]+) Capture domain name |
| 46 | (?::(?<port>\d{1,5}))? Optional port number (1-5 digits) |
| 47 | (?<path>\/[^\s?#]*)? Optional path starting with / |
| 48 | (?:\?(?<query>[^\s#]*))? Optional query string after ? |
| 49 | (?:#(?<fragment>\S*))? Optional fragment after # |
| 50 | $ End of string |
| 51 | ``` |
| 52 | |
| 53 | ### Step 4: Create Test Cases |
| 54 | |
| 55 | ``` |
| 56 | ✅ Should match: |
| 57 | "https://example.com" → protocol=https, domain=example.com |
| 58 | "http://api.example.com:8080/v1/users" → port=8080, path=/v1/users |
| 59 | "https://example.com/search?q=test#top" → query=q=test, fragment=top |
| 60 | |
| 61 | ❌ Should NOT match: |
| 62 | "ftp://example.com" → wrong protocol |
| 63 | "not-a-url" → no protocol |
| 64 | "" → empty string |
| 65 | ``` |
| 66 | |
| 67 | ### Step 5: Validate Edge Cases |
| 68 | - [ ] Empty input |
| 69 | - [ ] Very long input (ReDoS risk) |
| 70 | - [ ] Unicode characters |
| 71 | - [ ] Special regex characters in input (`.`, `*`, `+`, `?`) |
| 72 | - [ ] Newlines and whitespace |
| 73 | |
| 74 | ### Step 6: Check for ReDoS Vulnerability |
| 75 | Avoid catastrophic backtracking patterns: |
| 76 | - **Dangerous:** `(a+)+`, `(a|a)+`, `(a+b?)+` on non-matching input |
| 77 | - **Safe:** Use atomic groups, possessive quantifiers, or rewrite |
| 78 | - If pattern has nested quantifiers on overlapping character classes → flag as risky |
| 79 | |
| 80 | ### Step 7: Provide Language-Specific Usage |
| 81 | |
| 82 | **JavaScript:** |
| 83 | ```javascript |
| 84 | const pattern = /^https?:\/\/[a-zA-Z0-9.-]+/; |
| 85 | const match = url.match(pattern); |
| 86 | const isValid = pattern.test(url); |
| 87 | ``` |
| 88 | |
| 89 | **Python:** |
| 90 | ```python |
| 91 | import re |
| 92 | pattern = re.compile(r'^https?://[a-zA-Z0-9.-]+') |
| 93 | match = pattern.match(url) |
| 94 | is_valid = bool(pattern.match(url)) |
| 95 | ``` |
| 96 | |
| 97 | **Go:** |
| 98 | ```go |
| 99 | pattern := regexp.MustCompile(`^https?://[a-zA-Z0-9.-]+`) |
| 100 | match := pattern.FindString(url) |
| 101 | isValid := pattern.MatchString(url) |
| 102 | ``` |
| 103 | |
| 104 | ## Common Patterns Reference |
| 105 | |
| 106 | | Need | Pattern | Notes | |
| 107 | |------|---------|-------| |
| 108 | | Email (basic) | `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` | Not RFC-compliant, covers 99% | |
| 109 | | UUID | `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$` | Case-insensitive flag | |
| 110 | | ISO date | `^\d{4}-\d{2}-\d{2}$` | Doesn't validate ranges | |
| 111 | | Semantic version | `^v?\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$` | Optional `v` prefix | |
| 112 | | IP address (v4) | `^(\d{1,3}\.){3}\d{1,3}$` | Doesn't validate 0–255 | |
| 113 | | Slug | `^[a-z0-9]+(-[a-z0-9]+)*$` | Lowercase with hyphens | |
| 114 | |
| 115 | ## Rules |
| 116 | - **ALWAYS** explain each component in plain English |
| 117 | - **ALWAYS** provide test cases (match and non-match) |
| 118 | - **ALWAYS** check for ReDoS vulnerability on complex patterns |
| 119 | - **NEVER** use regex for HTML parsing — use a proper parser |
| 120 | - Prefer readability over cleverness — comment complex patterns |
| 121 | - Use named capture groups when extracting data |
| 122 | - Mention flavor differences (JS vs Python vs Go) when they matter |
| 123 | |
| 124 | ## Completion |
| 125 | Working regex with plain-English breakdown, test cases, language-specific usage, and ReDoS safety check. |
| 126 | |
| 127 | ## If a Step Fails |
| 128 | - **Can't express requirement in regex:** Consider a parser or multi-step validation instead |
| 129 | - **ReDoS risk detected:** Rewrite with non-overlapping character classes or use a timeout |
| 130 | - **Flavor mismatch:** Note which features are unavailable (e.g., lookbehind in older JS) |
| 131 | - **Too complex:** Split into multiple simpler patterns applied sequentia |