正则表达式构建器

nhan03bit2026-10-28查看 407复制 1032

构建、测试、解释和调试正则表达式,并提供清晰的文档和边界情况处理

Download (.md)

📘如何使用这个技能

  1. 1
    复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
  2. 2
    打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
  3. 3
    粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
  4. 4
    直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景

💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。

SKILL.md9426 chars
---
name: regex-builder
description: Construct, test, explain, and debug regular expressions with clear documentation and edge case handling
layer: utility
category: text-processing
triggers:
  - "regex for"
  - "regular expression"
  - "match pattern"
  - "explain this regex"
  - "regex help"
  - "validate format"
  - "parse this string"
inputs:
  - Description of what to match (natural language)
  - Example strings that should match
  - Example strings that should NOT match
  - Target language/engine (JS, Python, Go, PCRE)
outputs:
  - Regex pattern with explanation
  - Commented/documented version
  - Test cases
  - Edge cases and known limitations
  - Alternative approaches if regex is not ideal
linksTo:
  - json-transformer
  - code-explainer
  - testing-patterns
linkedFrom:
  - shell-scripting
  - security-scanner
preferredNextSkills:
  - testing-patterns
fallbackSkills:
  - code-explainer
riskLevel: low
memoryReadPolicy: selective
memoryWritePolicy: selective
sideEffects: []
---

# Regex Builder Skill

## Purpose

Regular expressions are powerful but notoriously hard to read and debug. This skill constructs correct, well-documented regex patterns from natural language descriptions, explains existing patterns in plain English, and always provides test cases to verify correctness.

## Key Concepts

### When to Use Regex (and When Not To)

**Use regex for:**
- Validating string formats (email, phone, date)
- Extracting structured parts from text
- Search and replace with patterns
- Log file parsing
- Simple tokenization

**Do NOT use regex for:**
- Parsing HTML/XML (use a DOM parser)
- Parsing JSON (use `JSON.parse`)
- Complex nested structures (use a proper parser/grammar)
- When a simple `string.includes()` / `string.startsWith()` suffices

### Engine Differences

| Feature | JavaScript | Python | Go | PCRE |
|---------|-----------|--------|-----|------|
| Lookahead `(?=...)` | Yes | Yes | No | Yes |
| Lookbehind `(?<=...)` | Yes (ES2018+) | Yes | No | Yes |
| Named groups `(?<name>...)` | Yes | `(?P<name>...)` | `(?P<name>...)` | Both |
| Unicode `\p{L}` | Yes (`/u` flag) | Yes (`regex` module) | Yes | Yes |
| Atomic groups | No | No | No | Yes |
| Possessive quantifiers | No | No | No | Yes |
| Backreferences | Yes | Yes | No | Yes |

### Regex Building Blocks

```
ANCHORS
  ^       Start of string (or line with /m)
  $       End of string (or line with /m)
  \b      Word boundary
  \B      Not a word boundary

CHARACTER CLASSES
  .       Any character (except newline unless /s)
  \d      Digit [0-9]
  \D      Non-digit
  \w      Word character [a-zA-Z0-9_]
  \W      Non-word character
  \s      Whitespace [\t\n\r\f\v ]
  \S      Non-whitespace
  [abc]   Character set (a, b, or c)
  [^abc]  Negated set (not a, b, or c)
  [a-z]   Range

QUANTIFIERS
  *       0 or more (greedy)
  +       1 or more (greedy)
  ?       0 or 1 (greedy)
  {n}     Exactly n
  {n,}    n or more
  {n,m}   Between n and m
  *?      0 or more (lazy)
  +?      1 or more (lazy)

GROUPS
  (...)       Capturing group
  (?:...)     Non-capturing group
  (?<name>...)  Named capturing group
  (?=...)     Positive lookahead
  (?!...)     Negative lookahead
  (?<=...)    Positive lookbehind
  (?<!...)    Negative lookbehind
  |           Alternation (OR)

FLAGS
  /g      Global (all matches)
  /i      Case insensitive
  /m      Multiline (^ and $ match line boundaries)
  /s      Dotall (. matches newline)
  /u      Unicode mode
```

## Workflow

### Step 1: Understand the Requirement

Break down the natural language description:
- What exact strings should match?
- What should NOT match?
- Are there edge cases (empty strings, unicode, very long input)?
- What parts need to be captured vs. just matched?

### Step 2: Build Incrementally

Never write the full regex at once. Build piece by piece:

```
Requirement: "Match a US phone number like (555) 123-4567 or 555-123-4567"

Step 1: Optional area code in parens
  (?:\(\d{3}\)\s?)?

Step 2: Three digits
  \d{3}

Step 3: Separator (dash or dot or space)
  [-.\s]

Step 4: Four digits
  \d{4}

Combined:
  (?:\(\d{3}\)\s?|\d{3}[-.\s])\d{3}[-.\s]\d{4}

Anchored:
  ^(?:\(\d{3}\)\s?|\d{3}[-.\s])\d{3}[-.\s]\d{4}$
```

### Step 3: Document with Comments

```javascript
// JavaScript verbose regex (using template literals)
const phoneRegex = new RegExp([
  '^',
  '(?:',
    '\\(\\d{3}\\)\\s?',  // (555) with optional space
    '|',
    '\\d{3}[-. ]',        // 555- or 555. or 555 (space)
  ')',
  '\\d{3}',               // 123
  '[-. ]',                 // separator
  '\\d{4}',               // 4567
  '$',
].join(''));
```

```python
# Python verbose regex (VERBOSE flag)
import re

phone_pattern = re.compile(r"""
    ^
    (?:
        \(\d{3}\)\s?     # (555) with optional space
        |
        \d{3}[-.\s]      # 555- or 555. or 555<space>
    )
    \d{3}                 # 123
    [-.\s]                # separator
    \d{4}                 # 4567
    $
""", re.VERBOSE)
```

### Step 4: Test Thoroughly

```typescript
function testRegex(pattern: RegExp, shouldMatch: string[], shouldNotMatch: string[]) {
  const results: { input: string; expected: boolean; actual: boolean; pass: boolean }[] = [];

  for (const input of shouldMatch) {
    const actual = pattern.test(input);
    results.push({ input, expected: true, actual, pass: actual === true });
  }

  for (const input of shouldNotMatch) {
    const actual = pattern.test(input);
    results.push({ input, expected: false, actual, pass: actual === false });
  }

  const failures = results.filter(r => !r.pass);
  if (failures.length > 0) {
    console.error('FAILURES:', failures);
  } else {
    console.log(`All ${results.length} tests passed`);
  }
}

// Usage
testRegex(phoneRegex,
  // Should match
  ['(555) 123-4567', '555-123-4567', '555.123.4567', '(555)123-4567'],
  // Should NOT match
  ['123-4567', '555-1234-567', '(555 123-4567', 'abc-def-ghij', '']
);
```

## Common Patterns Reference

### Email (RFC 5322 simplified)

```javascript
// Practical email validation (not RFC-complete, but covers 99.9% of real emails)
const email = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;

// For production, prefer: just check for @ and non-empty parts, then send a confirmation email
```

### URL

```javascript
const url = /^https?:\/\/(?:[\w-]+\.)+[\w]{2,}(?:\/[^\s]*)?$/i;
// For production, use the URL constructor: new URL(input) and catch errors
```

### Date (YYYY-MM-DD)

```javascript
const isoDate = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/;
// Note: This does not validate day-of-month accuracy (e.g., Feb 30). Use Date parsing for that.
```

### Slug (URL-safe string)

```javascript
const slug = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
// Matches: "hello-world", "post-123", "a"
// Rejects: "Hello-World", "--double", "trailing-", ""
```

### Semantic Version

```javascript
const semver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
```

### Password Strength (minimum requirements)

```javascript
// At least 8 chars, one upper, one lower, one digit, one special
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{}|;:,.<>?])[A-Za-z\d!@#$%^&*()_+\-=\[\]{}|;:,.<>?]{8,}$/;

// Better approach: check length >= 12 and zxcvbn score >= 3
```

### IP Addresses

```javascript
// IPv4
const ipv4 = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;

// For IPv6, do not use regex. Use a library or built-in parser.
```

## Explanation Format

When explaining an existing regex, use this format:

```
Pattern: ^(?:\+?1[-.\s]?)?(?:\(\d{3}\)|\d{3})[-.\s]?\d{3}[-.\s]?\d{4}$

Breakdown:
  ^                       Start of string
  (?:\+?1[-.\s]?)?       Optional country code: +1 or 1 with optional separator
  (?:                     Area code group (non-capturing):
    \(\d{3}\)               (555) — three digits in parentheses
    |                       OR
    \d{3}                   555 — three digits without parens
  )
  [-.\s]?                 Optional separator (dash, dot, or space)
  \d{3}                   Exchange: three digits
  [-.\s]?                 Optional separator
  \d{4}                   Subscriber: four digits
  $                       End of string

Matches:    +1 (555) 123-4567, 1-555-123-4567, 5551234567, (555)123.4567
No match:   123-4567, +44 555 123 4567, (55) 123-4567
```

## Performance Considerations

1. **Avoid catastrophic backtracking**: Patterns like `(a+)+b` on input `aaaaaaaac` cause exponential time. Use atomic groups or possessive quantifiers where available.
2. **Anchor your patterns**: `^...$` prevents the engine from trying every position in the string.
3. **Be specific**: `[a-z0-9]` is faster than `\S` when you know the character set.
4. **Compile once, use many**: Store compiled regex outside loops.
5. **Prefer non-capturing groups**: `(?:...)` instead of `(...)` when you do not need the capture.

```javascript
// BAD: Regex compiled on every call
function isValid(input: string) {
  return /^[a-z0-9]+$/.test(input); // Creates new RegExp each time in some engines
}

// GOOD: Compiled once
const VALID_PATTERN = /^[a-z0-9]+$/;
function isValid(input: string) {
  return VALID_PATTERN.test(input);
}
```
来源:skillsdirectory

评论0

登录后参与评论

还没有评论,来抢沙发吧