Use Cases (업데이트: 2026. 6. 2.)

Claude Code로 정규식 작성, 테스트, 리뷰하기

Claude Code로 이메일, 전화번호, 로그 추출 정규식을 만들고 테스트와 리뷰까지 진행하는 실전 가이드.

Claude Code로 정규식 작성, 테스트, 리뷰하기

정규식에서 문제가 생기는 이유는 기호를 몰라서라기보다, 어떤 문자열을 허용하고 어떤 문자열을 거부할지 명확하지 않은 상태에서 시작하기 때문입니다. user@example.com 은 통과하지만 user+tag@sub.example.co.jp 는 실패하거나, 반대로 user@.com 같은 잘못된 값이 통과할 수 있습니다.

Claude Code는 정규식을 대신 외워 주는 도구가 아닙니다. 허용 예시, 거부 예시, 정규식, 실행 가능한 테스트, 리뷰 관점을 한 번에 정리해 주는 개발 보조 도구로 쓰는 편이 안전합니다. 정규식은 문자열의 모양을 규칙으로 표현하는 작은 언어이고, 이름 있는 캡처는 추출한 부분에 timestamp 또는 requestId 같은 이름을 붙이는 문법입니다.

처음 사용하는 독자라면 Claude Code 시작 가이드를 먼저 읽어 보세요. 프롬프트를 더 안정적으로 쓰는 방법은 더 나은 프롬프트를 위한 5가지 팁과 연결됩니다. 공식 자료는 Claude Code overview, JavaScript 정규식 문법은 MDN Regular expressions를 기준으로 확인합니다.

진행 흐름

flowchart LR
  A["허용할 예시"] --> C["Claude Code에 요청"]
  B["거부할 예시"] --> C
  C --> D["정규식과 헬퍼 함수"]
  D --> E["Node.js 테스트"]
  E --> F["리뷰와 함정 점검"]

“이메일 regex를 만들어 줘”라고만 요청하지 말고, 검증인지 추출인지, 어떤 값을 허용하고 거부할지 함께 전달합니다. 이 예시들이 곧 테스트의 기준이 됩니다.

첫 요청 예시

이메일 주소, 일본 전화번호, 애플리케이션 로그를 처리하는 JavaScript 정규식 헬퍼를 만들어 주세요.

조건:
- Node.js에서 바로 실행 가능해야 함
- user+tag@sub.example.co.jp 는 허용
- user..name@example.com 과 user@.com 은 거부
- 090-1234-5678, 03-1234-5678, 05012345678 은 허용
- 로그에서 timestamp, level, service, requestId, message 를 이름 있는 캡처로 추출
- node:test 테스트 추가
- 정규식만으로 처리하면 위험한 업무 규칙은 설명

핵심은 범위를 좁히는 것입니다. 이메일의 전체 RFC를 구현하려고 하면 입력 폼에는 과한 검증이 되기 쉽습니다. 여기서는 명백한 오입력을 막고, 실제 도달 가능성은 확인 메일이나 백엔드 로직에 맡깁니다.

예제1: 이메일, 전화번호, 로그 헬퍼

아래 코드를 regex-helper.mjs 로 저장하고 node regex-helper.mjs 를 실행합니다.

import { fileURLToPath } from "node:url";

export const emailRegex =
  /^(?!.*\.\.)[A-Z0-9_%+-]+(?:\.[A-Z0-9_%+-]+)*@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,63}$/i;

export const emailSearchRegex =
  /[A-Z0-9_%+-]+(?:\.[A-Z0-9_%+-]+)*@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,63}/gi;

export const normalizedJapanesePhoneRegex = /^0(?:[5789]0\d{8}|[1-9]\d{8,9})$/;

export const looseJapanesePhoneSearchRegex =
  /0\d{1,4}[-\s]?\d{1,4}[-\s]?\d{3,4}/g;

export const appLogRegex =
  /^\[(?<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z)\]\s+(?<level>INFO|WARN|ERROR)\s+(?<service>[a-z][a-z0-9-]*)\s+requestId=(?<requestId>[A-Za-z0-9_-]+)\s+message="(?<message>[^"]*)"$/;

export function isEmail(input) {
  return emailRegex.test(input.trim());
}

export function normalizePhone(input) {
  return input.replace(/[()\s-]/g, "");
}

export function isJapanesePhone(input) {
  return normalizedJapanesePhoneRegex.test(normalizePhone(input));
}

export function extractContacts(text) {
  const emails = [...text.matchAll(emailSearchRegex)]
    .map((match) => match[0])
    .filter(isEmail);

  const phones = (text.match(looseJapanesePhoneSearchRegex) ?? []).filter(
    isJapanesePhone,
  );

  return {
    emails: [...new Set(emails)],
    phones: [...new Set(phones)],
  };
}

export function parseLogLine(line) {
  const match = line.match(appLogRegex);
  if (!match?.groups) return null;

  return {
    timestamp: match.groups.timestamp,
    level: match.groups.level,
    service: match.groups.service,
    requestId: match.groups.requestId,
    message: match.groups.message,
  };
}

if (process.argv[1] === fileURLToPath(import.meta.url)) {
  const text = "Contact: user+tag@sub.example.co.jp / 090-1234-5678";
  const log =
    '[2026-06-02T10:15:30.000Z] ERROR billing-api requestId=req_123 message="payment failed"';

  console.log(extractContacts(text));
  console.log(parseLogLine(log));
}

전화번호는 검증 전에 정규화합니다. 하이픈과 공백을 제거하면 정규식이 짧아지고, 입력 형식 차이 때문에 검증이 흔들리지 않습니다. 로그는 이름 있는 캡처를 사용하므로 match[4] 대신 match.groups.requestId 로 의도를 읽을 수 있습니다.

예제2: 동작을 고정하는 테스트

아래 코드를 regex-helper.test.mjs 로 저장하고 node --test regex-helper.test.mjs 를 실행합니다.

import test from "node:test";
import assert from "node:assert/strict";
import {
  extractContacts,
  isEmail,
  isJapanesePhone,
  parseLogLine,
} from "./regex-helper.mjs";

test("validates practical email addresses", () => {
  assert.equal(isEmail("user@example.com"), true);
  assert.equal(isEmail("user+tag@sub.example.co.jp"), true);
  assert.equal(isEmail("user..name@example.com"), false);
  assert.equal(isEmail("user@.com"), false);
  assert.equal(isEmail("@example.com"), false);
});

test("validates Japanese phone numbers after normalization", () => {
  assert.equal(isJapanesePhone("090-1234-5678"), true);
  assert.equal(isJapanesePhone("03-1234-5678"), true);
  assert.equal(isJapanesePhone("05012345678"), true);
  assert.equal(isJapanesePhone("123-4567-8901"), false);
  assert.equal(isJapanesePhone("090-123-456"), false);
});

test("extracts contacts from free text", () => {
  assert.deepEqual(
    extractContacts("support: user+tag@example.com, tel: 090-1234-5678"),
    {
      emails: ["user+tag@example.com"],
      phones: ["090-1234-5678"],
    },
  );
});

test("parses application logs with named captures", () => {
  const parsed = parseLogLine(
    '[2026-06-02T10:15:30.000Z] WARN auth-service requestId=req_abc message="retry required"',
  );

  assert.deepEqual(parsed, {
    timestamp: "2026-06-02T10:15:30.000Z",
    level: "WARN",
    service: "auth-service",
    requestId: "req_abc",
    message: "retry required",
  });
});

Claude Code에는 테스트 실행까지 요청합니다.

node --test regex-helper.test.mjs 를 실행해 주세요.
실패하면 정규식이 틀렸는지 테스트 데이터가 틀렸는지 먼저 설명한 뒤 수정하세요.
이메일 허용 범위를 넓힐 때는 허용 예시와 거부 예시를 먼저 추가하세요.

예제3: 로그 추출 요청

로그 형식은 애플리케이션이 통제하므로 정규식을 쓰기 좋은 영역입니다.

logs/app.log 를 읽고 ERROR 행만 추출해서 requestId 와 message 를 CSV로 저장해 주세요.
regex-helper.mjs 의 appLogRegex 와 같은 형식을 사용합니다.
파싱하지 못한 행은 조용히 버리지 말고 마지막에 개수를 출력하세요.
이메일 주소나 전화번호는 CSV에 쓰지 마세요.

현실의 로그에는 오래된 형식, 잘린 줄, 임시 디버그 출력이 섞입니다. 파싱 실패를 null 로 돌려주는 설계가 조용히 무시하는 스크립트보다 리뷰하기 쉽습니다.

리뷰 템플릿

## Regex review request

Files:
- regex-helper.mjs
- regex-helper.test.mjs

Review:
- Are allowed and rejected examples covered by tests?
- Are email, phone, and log responsibilities separated?
- Are named capture names readable?
- Is there any ambiguous repetition that could cause ReDoS?
- Could personal data leak into logs or CSV output?

Output:
- For each issue, include file, line, reason, and suggested fix
- Ask a question instead of guessing when the business rule is unclear
- Run node --test regex-helper.test.mjs after changes

ReDoS는 특정 입력에서 정규식 처리 시간이 비정상적으로 길어지는 문제입니다. 반복이 중첩된 패턴을 만들었다면 Claude Code에 명시적으로 확인시킵니다.

흔한 함정

함정더 나은 지시
성공 예시만 전달거부 예시를 최소 3개 포함
.* 남용[^"]* 처럼 끝 경계를 구체화
g 플래그 정규식을 test()에 재사용검증용과 검색용 정규식을 분리
캡처 번호에 의존이름 있는 캡처나 비캡처 그룹 사용
정규식을 업무 검증으로 오해도달 가능성, 존재 여부, 권한은 백엔드에서 확인

정규식은 입력의 모양을 정리하고 통제된 텍스트에서 정보를 뽑는 데 적합합니다. 이메일이 실제로 도착하는지, 전화번호가 현재 사용 중인지까지 증명하지는 못합니다.

URL, JSON, CSV처럼 표준 파서가 있는 형식은 정규식보다 전용 API를 우선합니다. Claude Code에는 “순수 텍스트 추출에만 정규식을 쓰고, 더 안전한 parser가 있으면 그 이유와 함께 사용하라”고 적어 두면 과한 패턴을 줄일 수 있습니다. 또한 입력 형식, 업무 규칙, 저장 규칙을 분리해서 리뷰하면 작은 정규식 helper가 숨은 정책 엔진이 되는 일을 막을 수 있습니다.

CTA

정규식 개선은 리드 폼, 결제 로그, 고객 지원 접수, 자료 다운로드 신청처럼 수익 흐름과 가까운 곳에서 효과가 큽니다. 개인은 무료 Claude Code 치트시트로 시작하고, 재사용 가능한 템플릿은 제품 페이지에서 확인하세요. 팀 단위로 입력 검증, 로그 리뷰, 리뷰 게이트를 정리하려면 Claude Code 교육 및 상담이 더 적합합니다.

정리

Claude Code로 정규식을 만들 때는 예시, 반례, 테스트, 리뷰 기준을 한 번에 전달하는 것이 가장 안정적입니다. Masa가 실제로 시험했을 때도 “정규식만 작성”보다 “정규식과 테스트를 함께 작성”이 user+tag 이메일, 하이픈 있는 전화번호, 이름 있는 로그 캡처 문제를 더 빨리 잡아냈습니다.

#Claude Code #regular expressions #regex #debugging #testing
무료

무료 PDF: Claude Code 치트시트

이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.

개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.

Masa

작성자 소개

Masa

Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.