AI 업무 활용

AI가 작성한 정규표현식을 일치·불일치 예제로 검증하기

AI가 만든 정규표현식을 완성된 규칙이 아니라 초안으로 취급합니다. 작은 합성 테스트 표를 만들고 예상 결과와 실제 매칭 결과를 비교한 뒤, 수정된 패턴과 검토 보고서를 확인합니다.

목차 보기

이런 분께 맞아요AI를 이용해 정규표현식 초안을 만들고, 실제 사용 전에 알려진 일치·불일치 사례로 패턴을 검증하려는 사람을 위한 안내입니다.

준비할 것
  • Python 3.12와 해당 버전을 실행하는 터미널 명령이 준비되어 있어야 합니다.
  • UTF-8 CSV와 Python 파일을 저장할 수 있는 텍스트 편집기가 필요합니다.
  • 스크립트가 outputs 아래에 새 폴더를 만들 수 있는 작업 폴더가 필요합니다.
  • Python 표준 라이브러리인 csv, pathlib, re만 사용합니다.

01정규식을 시험하기 전에 요구사항부터 작성하기

사내 업무 ID의 형식이 WK-YYYY-NNNN이라고 가정합니다. 접두사는 대문자 WK여야 하고, 연도는 2000부터 2099까지여야 하며, 구분자는 하이픈이어야 합니다. 마지막 부분은 정확히 4개의 ASCII 숫자로 구성되어야 합니다.

AI가 WK-\d{4}-\d{4}라는 패턴을 제안했다고 가정해 보겠습니다. 겉보기에는 적절하지만 연도에 숫자 4개만 요구할 뿐 2000-2099 범위를 강제하지 않습니다. 바로 실제 데이터에 적용하는 대신 정답을 알고 있는 예제로 시험하는 것이 안전합니다.

02합성 테스트 사례 만들기

아래 데이터는 이 글을 위해 작성한 합성 데이터입니다. regex_cases.csv로 저장하세요. 일치해야 하는 문자열 3개와 일치하면 안 되는 문자열 7개가 들어 있습니다.

csv
case_id,value,should_match
C001,WK-2026-0001,yes
C002,WK-2000-0042,yes
C003,WK-2099-9999,yes
C004,WK-1999-0001,no
C005,wk-2026-0001,no
C006,WK-2026-001,no
C007,WK-2026-00001,no
C008,WK-2026_0001,no
C009," WK-2026-0001",no
C010,WK-20A6-0001,no

허용 연도의 양쪽 경계, 범위를 벗어난 연도, 소문자 접두사, 짧고 긴 번호 필드, 잘못된 구분자, 앞쪽 공백, 연도 안의 비숫자 문자를 포함했습니다. 정규식을 실행하기 전에 사람이 직접 분류할 수 있을 정도로 작은 데이터입니다.

03AI 패턴이 틀릴 사례를 먼저 예상하기

AI 패턴 WK-\d{4}-\d{4}는 C001, C002, C003을 받아들여야 합니다. C005부터 C010은 구조가 맞지 않으므로 거부해야 합니다. 하지만 C004의 1999도 숫자 4개이므로 이 패턴은 C004까지 잘못 받아들입니다.

사례예상AI 패턴결과
C001MATCHMATCHPASS
C002MATCHMATCHPASS
C003MATCHMATCHPASS
C004NO MATCHMATCHFAIL
C005NO MATCHNO MATCHPASS
C006NO MATCHNO MATCHPASS
C007NO MATCHNO MATCHPASS
C008NO MATCHNO MATCHPASS
C009NO MATCHNO MATCHPASS
C010NO MATCHNO MATCHPASS

수정 패턴은 WK-20[0-9]{2}-[0-9]{4}입니다. 앞의 20으로 연도를 2000부터 2099까지로 제한하고, [0-9]로 의도한 숫자 집합을 명시합니다. 스크립트에서는 전체 문자열이 패턴에 맞아야 하므로 fullmatch를 사용합니다.

04예상 결과와 실제 매칭을 자동으로 비교하기

다음 스크립트를 ai_regex_check.py로 저장하세요. AI가 제안한 패턴과 수정된 패턴을 모두 시험하고, 각 사례의 결과를 CSV 보고서로 저장합니다. 기존 출력 폴더는 재사용하지 않습니다.

python
import csv
import re
from pathlib import Path

SOURCE = Path("regex_cases.csv")
OUTPUT_DIR = Path("outputs") / "regex_check_result"
REPORT = OUTPUT_DIR / "regex_check.csv"

AI_PATTERN = re.compile(r"WK-\d{4}-\d{4}")
REVISED_PATTERN = re.compile(r"WK-20[0-9]{2}-[0-9]{4}")


def parse_expected(value: str) -> bool:
    normalized = value.strip().lower()
    if normalized == "yes":
        return True
    if normalized == "no":
        return False
    raise ValueError(f"Expected yes or no, got: {value!r}")


def label(value: bool) -> str:
    return "MATCH" if value else "NO MATCH"


def main() -> None:
    if not SOURCE.is_file():
        raise FileNotFoundError(f"Source CSV not found: {SOURCE}")
    if OUTPUT_DIR.exists():
        raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")

    results = []
    ai_failures = 0
    revised_failures = 0

    with SOURCE.open("r", encoding="utf-8-sig", newline="") as stream:
        reader = csv.DictReader(stream)
        required = {"case_id", "value", "should_match"}
        if reader.fieldnames is None or not required.issubset(reader.fieldnames):
            raise ValueError("CSV is missing a required column.")

        for row_number, row in enumerate(reader, start=2):
            expected = parse_expected(row["should_match"])
            text = row["value"]
            ai_actual = AI_PATTERN.fullmatch(text) is not None
            revised_actual = REVISED_PATTERN.fullmatch(text) is not None
            ai_pass = ai_actual == expected
            revised_pass = revised_actual == expected

            if not ai_pass:
                ai_failures += 1
            if not revised_pass:
                revised_failures += 1

            results.append({
                "case_id": row["case_id"],
                "value": text,
                "expected": label(expected),
                "ai_actual": label(ai_actual),
                "ai_test": "PASS" if ai_pass else "FAIL",
                "revised_actual": label(revised_actual),
                "revised_test": "PASS" if revised_pass else "FAIL",
            })

    OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
    OUTPUT_DIR.mkdir()
    fields = [
        "case_id", "value", "expected", "ai_actual", "ai_test",
        "revised_actual", "revised_test"
    ]
    with REPORT.open("x", encoding="utf-8", newline="") as stream:
        writer = csv.DictWriter(stream, fieldnames=fields)
        writer.writeheader()
        writer.writerows(results)

    print(f"Cases: {len(results)}.")
    print(f"AI pattern failures: {ai_failures}.")
    print(f"Revised pattern failures: {revised_failures}.")
    print(f"Report: {REPORT.as_posix()}")

    if revised_failures:
        raise RuntimeError("Revised pattern still fails one or more tests.")


if __name__ == "__main__":
    main()
text
python ai_regex_check.py

05예상 보고서 확인하기

테스트 사례는 10개입니다. AI 패턴은 C004 하나에서 실패해야 하고, 수정된 패턴은 10개 사례를 모두 통과해야 합니다.

항목예상값
전체 사례10
AI 패턴 실패1
수정 패턴 실패0
AI 실패 사례C004
수정 패턴 통과 사례10

아래 예상 콘솔 출력은 테스트 표와 스크립트를 바탕으로 손으로 도출한 결과입니다. 실제 실행 로그가 아닙니다.

text
Cases: 10.
AI pattern failures: 1.
Revised pattern failures: 0.
Report: outputs/regex_check_result/regex_check.csv

06경계 사례를 추가하고 흔한 실수 확인하기

  • 이 예제의 2000과 2099처럼 허용 범위의 최솟값과 최댓값을 포함하세요.
  • 1999처럼 경계 바로 바깥의 값도 하나 이상 포함하세요.
  • 잘못된 대소문자, 구분자, 필드 길이, 공백, 비정상 문자를 시험하세요.
  • 필드 전체가 규칙에 맞아야 한다면 fullmatch를 사용하세요.
  • OUTPUT_DIR을 바꾸지 않고 다시 실행합니다. 이전 보고서를 덮어쓰지 않고 FileExistsError로 중단되어야 합니다.
실수문제가 되는 이유
일치해야 하는 문자열만 시험너무 느슨한 정규식도 음성 사례를 넣기 전에는 맞는 것처럼 보일 수 있습니다.
AI 패턴을 사용하면서 요구사항을 다시 쓰지 않음패턴이 실제로 원한 문제와 조금 다른 문제를 해결할 수 있습니다.
정상 사례 하나만 확인경계, 길이, 대소문자, 구분자 오류가 시험되지 않습니다.
필드 전체 규칙인데 search 사용잘못된 전체 문자열 안에서 유효해 보이는 일부 문자열만 발견될 수 있습니다.
정규식 결과를 본 뒤 기대값 변경테스트가 요구사항에 대한 독립적인 기준 역할을 하지 못하게 됩니다.

07정규식 테스트가 증명하지 못하는 것 이해하기

10개 테스트를 통과했다는 것은 수정된 패턴이 이 10개의 합성 사례에서 예상대로 동작한다는 뜻일 뿐입니다. 가능한 모든 입력에 대해 정확하다는 수학적 증명은 아닙니다. 새로운 경계나 실패 사례를 발견할 때마다 테스트를 추가해야 합니다.

정규식은 형식을 검사할 뿐 업무상 사실까지 검증하지 않습니다. WK-2026-1234가 완벽하게 매칭되더라도 실제 데이터베이스에 존재하지 않을 수 있습니다. 존재 여부, 고유성, 권한, 다른 필드와의 관계는 별도 검사가 필요합니다.

이 작은 예제는 매우 길거나 공격적으로 구성된 입력에서의 성능을 평가하지 않습니다. 더 복잡한 AI 생성 패턴을 신뢰되지 않은 텍스트를 처리하는 서비스에 적용할 때는 정확성뿐 아니라 실행 시간 특성도 별도로 검토해야 합니다.

실행·검증 기록

2026-09-20 · 예제 수동 검토 · 대상: Python 3.12 · 표준 라이브러리: csv, pathlib, re · 실행하지 않음

  • 합성 문자열 10개 중 3개를 일치 예상, 7개를 불일치 예상으로 수동 분류했습니다.
  • 1999가 네 자리 숫자 조건을 만족하므로 AI 패턴이 C004를 받아들인다는 점을 수동 확인했습니다.
  • AI 패턴의 실패 사례가 10개 중 정확히 1개임을 수동으로 계산했습니다.
  • 수정된 20[0-9]{2} 연도 부분이 2000부터 2099까지 허용하고 예제의 1999를 거부하는지 확인했습니다.
  • fullmatch 사용, 예상값과 실제값 비교, 출력 충돌 방지, 보고서 생성 로직을 코드로 검토했습니다.
  • 예상 실패 개수와 콘솔 출력을 손으로 도출했습니다.
검증 한계
  • 이 응답의 작성자는 코드를 실행하지 않았으며, Python 정규식 동작이나 파일 시스템 출력을 실제로 시험하지 않았습니다.
  • 목록에 있는 합성 사례 10개만 수동으로 평가했으며 모든 가능한 입력에 대한 완전한 정확성을 증명하지 않았습니다.
  • 매우 길거나 공격적으로 구성된 문자열에 대한 성능은 시험하지 않았습니다.
  • 공식 문서 URL은 알려진 문서 위치를 사용했지만 실시간으로 접속해 확인하지 않았습니다.

사이트 전체 작성·검증 원칙

참고 출처

설명과 예제는 직접 작성했습니다. 관련 동작과 개념은 아래 공식 자료에서 확인할 수 있습니다.