ساخت Regex با هوش مصنوعی؛ آموزش تولید، تست و توضیح عبارت منظم با AI
در این آموزش یاد میگیرید Regex دقیق را با AI تولید و آزمایش کنید و یک AI Regex Generator بسازید که نیاز متنی، نمونههای مثبت و منفی را به الگوی تستشده و قابل توضیح تبدیل میکند.
ساخت Regex با هوش مصنوعی؛ از توضیح نیاز تا الگوی تستشده
Regex یا Regular Expression ابزاری قدرتمند برای جستوجو، استخراج و اعتبارسنجی متن است. با Regex میتوان فعالیتهایی مانند اینها را انجام داد:
- استخراج شماره سفارش از متن
- پیدا کردن تاریخها
- جداسازی کد محصول
- اعتبارسنجی قالب یک شناسه داخلی
- حذف فاصلههای تکراری
- استخراج مقدار از لاگ
- پیدا کردن تگها و Placeholderها
- تغییر قالب متن
- پردازش فایلهای متنی
- ساخت Rule برای Search و Replace
مشکل این است که Regexهای پیچیده بهسرعت ناخوانا میشوند:
^(?:[A-Z]{2}-)?\d{4,8}(?:-[a-z0-9]{2,6})?$
حتی اگر این Pattern در نگاه اول درست به نظر برسد، پرسشهای زیادی باقی میماند:
- پیشوند اجباری است یا اختیاری؟
- حروف کوچک مجازند؟
- عدد فارسی پذیرفته میشود؟
- فاصله ابتدا و انتهای ورودی چه میشود؟
- Match باید تمام رشته را پوشش دهد یا بخشی از آن را؟
- Dialect مربوط به Python است یا JavaScript؟
- رفتار
\dبرای Unicode چیست؟ - چه ورودیهایی نباید Match شوند؟
- Pattern روی متن طولانی چه عملکردی دارد؟
هوش مصنوعی میتواند نیاز زبانی را به Regex تبدیل و الگو را توضیح دهد، اما یک Regex تولیدشده نباید فقط بهدلیل ظاهر حرفهای پذیرفته شود. هر Pattern باید با مجموعهای از نمونههای مثبت، منفی و مرزی آزمایش شود.
در این مقاله یک AI Regex Generator واقعی با پایتون و API درواره میسازیم که:
- توضیح فارسی نیاز را دریافت میکند.
- Dialect و نوع Match را مشخص میکند.
- نمونههای مثبت و منفی را میگیرد.
- Regex و توضیح ساختاریافته تولید میکند.
- Pattern را Compile میکند.
- تمام نمونهها را اجرا میکند.
- خطاهای False Positive و False Negative را گزارش میدهد.
- حداکثر در چند مرحله محدود Pattern را اصلاح میکند.
- کد آماده Python و JavaScript میسازد.
Regex چیست؟
Regex زبانی برای تعریف الگوی متنی است.
یک Pattern ساده:
\d+
این الگو یک یا چند رقم متوالی را پیدا میکند.
نمونه:
شماره سفارش 1258 ثبت شد.
نتیجه:
1258
الگوی دیگری برای شناسه سفارش:
^ORD-\d{6}$
این Pattern فقط رشتههایی با ساختار زیر را قبول میکند:
ORD-123456
توضیح:
^ابتدای رشتهORD-متن ثابت\d{6}دقیقاً شش رقم$انتهای رشته
هوش مصنوعی چگونه به ساخت Regex کمک میکند؟
تبدیل توضیح فارسی به Pattern
درخواست:
شناسه باید با PRD- شروع شود و بعد از آن دقیقاً 8 رقم لاتین بیاید.
خروجی مناسب:
^PRD-[0-9]{8}$
توضیح Regex موجود
ورودی:
^(?:[A-Z]{2}-)?[0-9]{4,8}$
توضیح:
- پیشوند دو حرف بزرگ انگلیسی و
-اختیاری است. - بخش عددی بین ۴ تا ۸ رقم لاتین دارد.
- تمام رشته باید با Pattern سازگار باشد.
تولید Test Case
مدل میتواند نمونههای مثبت، منفی و مرزی پیشنهاد دهد.
تبدیل میان Dialectها
برخی قابلیتهای Regex در Python، JavaScript، Java، .NET و PCRE متفاوتاند. مدل میتواند تبدیل اولیه انجام دهد، اما Pattern باید در Runtime مقصد Compile و تست شود.
بهینهکردن خوانایی
یک Pattern طولانی میتواند به چند بخش نامگذاریشده یا حالت Verbose تبدیل شود.
استخراج داده با Named Group
^(?P<prefix>[A-Z]{3})-(?P<number>[0-9]{6})$
در Python میتوان prefix و number را جداگانه دریافت کرد.
مهمترین اصل: Regex بدون مثال ناقص است
این درخواست مبهم است:
یک Regex برای شماره سفارش بنویس.
اطلاعات لازم:
- پیشوند چیست؟
- تعداد رقمها چقدر است؟
- رقم فارسی مجاز است؟
- حروف کوچک پذیرفته میشوند؟
- فاصله مجاز است؟
- Match روی تمام رشته انجام میشود؟
- نمونه معتبر چیست؟
- نمونه نامعتبر چیست؟
- Runtime مقصد چیست؟
درخواست بهتر:
برای Python یک Regex بساز.
قالب معتبر:
- کل رشته باید Match شود.
- با ORD- شروع شود.
- بعد از آن دقیقاً 6 رقم لاتین باشد.
- فاصله مجاز نیست.
- حروف کوچک مجاز نیست.
نمونههای معتبر:
ORD-123456
ORD-000001
نمونههای نامعتبر:
ord-123456
ORD-12345
ORD-۱۲۳۴۵۶
XORD-123456
ORD-123456-7
Positive Example و Negative Example
نمونه مثبت
ورودیای که باید Match شود:
INV-2026-000125
نمونه منفی
ورودیای که نباید Match شود:
INV-26-125
نمونه مرزی
ورودیای که دقیقاً در حداقل یا حداکثر محدودیت است:
AB-0001
AB-99999999
کیفیت Regex بیشتر از توضیح طولانی، به تنوع Test Caseها وابسته است.
تفاوت Search، Match و Full Match
این سه هدف یکسان نیستند.
Search
الگو در هر بخش متن پیدا شود:
شماره سفارش ORD-123456 ثبت شد.
Prefix Match
رشته از ابتدای خود با الگو آغاز شود، اما ممکن است پس از Match متن دیگری داشته باشد.
Full Match
تمام رشته باید با Pattern سازگار باشد:
ORD-123456
برای اعتبارسنجی یک فیلد معمولاً Full Match مناسبتر است.
در Python:
re.search(pattern, text)
re.match(pattern, text)
re.fullmatch(pattern, text)
در JavaScript متد test بر اساس Anchorهای Pattern عمل میکند:
pattern.test(value)
برای Full Match در JavaScript معمولاً از ^ و $ استفاده میشود.
تفاوت Dialectهای Regex
| قابلیت | Python | JavaScript |
|---|---|---|
| Named Group | (?P<name>...) | (?<name>...) |
| Verbose Mode | re.VERBOSE | پشتیبانی مستقیم ندارد |
| Full Match | re.fullmatch | Anchorهای ^ و $ |
| Lookbehind | پشتیبانی میشود | در Runtimeهای مدرن پشتیبانی میشود |
| Unicode Flag | رفتار داخلی Python | معمولاً Flag u |
| Global Match | findall یا finditer | Flag g |
Pattern باید برای Runtime مقصد تولید شود.
\d یا [0-9]؟
در Python، \d میتواند ارقام Unicode را نیز Match کند؛ از جمله در بسیاری از شرایط ارقام فارسی:
۱۲۳۴۵۶
اگر فقط رقم لاتین میخواهید، صریح بنویسید:
[0-9]
اگر هر رقم Unicode مورد قبول است:
\d
در Requirement باید این تفاوت مشخص شود.
ساخت Regex برای کد محصول
Requirement:
کد محصول:
- با سه حرف بزرگ انگلیسی شروع شود.
- سپس خط تیره قرار گیرد.
- بعد از آن بین 4 تا 8 رقم لاتین باشد.
- کل رشته باید Match شود.
Pattern:
^[A-Z]{3}-[0-9]{4,8}$
نمونههای معتبر:
PRD-1234
ABC-00001234
نمونههای نامعتبر:
prd-1234
AB-1234
ABCD-1234
PRD-۱۲۳۴
PRD-123
PRD-123456789
ساخت Regex برای استخراج تاریخ ISO
Requirement:
تاریخهایی با قالب YYYY-MM-DD را از متن استخراج کن.
Pattern اولیه:
\b[0-9]{4}-[0-9]{2}-[0-9]{2}\b
این Pattern قالب را تشخیص میدهد، اما معتبر بودن تقویمی را تضمین نمیکند:
2026-99-45
روش مناسب:
- Regex قالب را استخراج کند.
- کتابخانه تاریخ مقدار را Parse و اعتبارسنجی کند.
from datetime import date
value = "2026-07-20"
parsed = date.fromisoformat(value)
Regex نباید وظیفه Parser تخصصی تاریخ را بهطور کامل بر عهده بگیرد.
ساخت Regex برای استخراج Placeholder
متن:
سلام {{customer_name}}، سفارش {{order_id}} آماده است.
Pattern:
\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}
نتایج:
customer_name
order_id
در Python:
import re
pattern = re.compile(
r"\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}"
)
values = pattern.findall(
"سلام {{customer_name}}، "
"سفارش {{order_id}} آماده است."
)
print(values)
ساخت Regex برای شماره موبایل ایران
قبل از تولید Pattern باید Scope مشخص شود.
فرمتهای احتمالی:
09121234567
989121234567
+989121234567
00989121234567
آیا همه این قالبها معتبرند یا فقط قالب داخلی؟
اگر Requirement فقط این باشد:
شماره با 09 شروع شود و در مجموع 11 رقم لاتین داشته باشد.
Pattern:
^09[0-9]{9}$
این Pattern فقط قالب را بررسی میکند. تعریف کاملتر باید بر اساس نیاز واقعی سامانه انجام شود و نباید قالبهای جدید بدون تصمیم محصول اضافه شوند.
ساخت Regex برای ایمیل
اعتبارسنجی کامل تمام حالتهای استاندارد ایمیل با یک Regex ساده مناسب نیست. برای بسیاری از فرمها یک کنترل قالب عمومی کافی است:
^[^@\s]+@[^@\s]+\.[^@\s]+$
اما برای سیستم واقعی بهتر است:
- Trim انجام شود.
- طول کنترل شود.
- آدرس Normalize شود.
- Parser یا کتابخانه مناسب استفاده شود.
- تأیید عملی آدرس با جریان محصول انجام شود.
هدف Regex باید «بررسی قالب پایه» باشد، نه اثبات وجود یا قابل استفاده بودن آدرس.
ساخت پروژه AI Regex Generator
ابزار ما این ورودی را دریافت میکند:
{
"description": "شناسه با ORD- شروع و بعد از آن شش رقم لاتین باشد",
"dialect": "python",
"match_mode": "fullmatch",
"positive_examples": [
"ORD-123456",
"ORD-000001"
],
"negative_examples": [
"ord-123456",
"ORD-12345",
"ORD-۱۲۳۴۵۶"
]
}
خروجی:
{
"pattern": "^ORD-[0-9]{6}$",
"flags": [],
"explanation": [],
"test_results": [],
"all_tests_passed": true
}
ایجاد پروژه
mkdir ai-regex-generator
cd ai-regex-generator
python -m venv .venv
فعالسازی در Linux و macOS:
source .venv/bin/activate
فعالسازی در Windows:
.venv\Scripts\Activate.ps1
نصب وابستگیها:
pip install \
openai \
python-dotenv \
pydantic \
fastapi \
uvicorn \
regex
ساخت پوشهها:
mkdir regex_generator output
فایلهای زیر را ایجاد کنید:
regex_generator/__init__.py
regex_generator/schemas.py
regex_generator/generator.py
regex_generator/tester.py
regex_generator/repair.py
regex_generator/examples.py
main.py
تنظیم API درواره
فایل .env:
DARVAREH_API_KEY=YOUR_API_KEY
DARVAREH_MODEL=MODEL_ID_DARVAREH
فایل .gitignore:
.env
.venv/
__pycache__/
output/
برای دریافت API Key در درواره ثبتنام کنید. مدل مناسب را از صفحه مدلهای درواره انتخاب کنید.
تعریف Schemaها
فایل regex_generator/schemas.py:
from typing import Literal
from pydantic import BaseModel, Field
RegexDialect = Literal[
"python",
"javascript",
]
MatchMode = Literal[
"search",
"match",
"fullmatch",
]
RegexFlag = Literal[
"IGNORECASE",
"MULTILINE",
"DOTALL",
"VERBOSE",
]
class RegexRequest(BaseModel):
description: str = Field(
min_length=5,
max_length=3000,
)
dialect: RegexDialect
match_mode: MatchMode
positive_examples: list[str] = Field(
min_length=1,
max_length=100,
)
negative_examples: list[str] = Field(
min_length=1,
max_length=100,
)
extraction_groups: list[str] = Field(
default_factory=list
)
constraints: list[str] = Field(
default_factory=list
)
class RegexPartExplanation(BaseModel):
part: str
meaning: str
class GeneratedRegex(BaseModel):
dialect: RegexDialect
pattern: str
flags: list[RegexFlag] = Field(
default_factory=list
)
match_mode: MatchMode
explanation: list[
RegexPartExplanation
]
assumptions: list[str] = Field(
default_factory=list
)
limitations: list[str] = Field(
default_factory=list
)
python_example: str
javascript_example: str
class RegexTestResult(BaseModel):
value: str
expected_match: bool
actual_match: bool
passed: bool
matched_text: str | None = None
groups: dict[str, str | None] = Field(
default_factory=dict
)
error: str | None = None
class RegexResponse(BaseModel):
generated: GeneratedRegex
test_results: list[
RegexTestResult
]
all_tests_passed: bool
repair_attempts: int
warnings: list[str] = Field(
default_factory=list
)
تولید Regex با API درواره
فایل regex_generator/generator.py:
import json
import os
from dotenv import load_dotenv
from openai import OpenAI
from pydantic import ValidationError
from regex_generator.schemas import (
GeneratedRegex,
RegexRequest,
)
load_dotenv()
api_key = os.getenv("DARVAREH_API_KEY")
model = os.getenv("DARVAREH_MODEL")
if not api_key:
raise RuntimeError(
"DARVAREH_API_KEY is not configured."
)
if not model:
raise RuntimeError(
"DARVAREH_MODEL is not configured."
)
client = OpenAI(
api_key=api_key,
base_url="https://api.darvareh.ir/v1",
)
SYSTEM_PROMPT = """
تو یک متخصص Regular Expression هستی.
وظیفه:
بر اساس Requirement و Test Caseها یک Regex تولید کن.
قواعد:
- Pattern باید برای Dialect درخواستی معتبر باشد.
- Match Mode را دقیق رعایت کن.
- تمام نمونههای مثبت باید Match شوند.
- تمام نمونههای منفی نباید Match شوند.
- اگر فقط ارقام لاتین لازماند از [0-9] استفاده کن.
- قابلیت خارج از Dialect مقصد استفاده نکن.
- Pattern را بیش از حد عمومی نساز.
- Requirement جدید اختراع نکن.
- گروههای استخراجی فقط در صورت درخواست ساخته شوند.
- مثالهای Python و JavaScript را تولید کن.
- خروجی فقط JSON معتبر باشد.
"""
OUTPUT_TEMPLATE = {
"dialect": "python",
"pattern": "^ORD-[0-9]{6}$",
"flags": [],
"match_mode": "fullmatch",
"explanation": [
{
"part": "^",
"meaning": "ابتدای رشته",
},
{
"part": "ORD-",
"meaning": "پیشوند ثابت",
},
{
"part": "[0-9]{6}",
"meaning": "دقیقاً شش رقم لاتین",
},
{
"part": "$",
"meaning": "انتهای رشته",
},
],
"assumptions": [],
"limitations": [],
"python_example": "string",
"javascript_example": "string",
}
def generate_regex(
request: RegexRequest,
) -> GeneratedRegex:
response = client.chat.completions.create(
model=model,
temperature=0,
messages=[
{
"role": "system",
"content": SYSTEM_PROMPT,
},
{
"role": "user",
"content": (
"درخواست:\n\n"
+ request.model_dump_json(
indent=2
)
+ "\n\nقالب خروجی:\n"
+ json.dumps(
OUTPUT_TEMPLATE,
ensure_ascii=False,
indent=2,
)
),
},
],
)
raw_output = (
response.choices[0]
.message.content
)
if not raw_output:
raise RuntimeError(
"The model returned an "
"empty regex."
)
try:
parsed = json.loads(raw_output)
except json.JSONDecodeError as error:
raise RuntimeError(
f"Invalid JSON from model: "
f"{error}"
) from error
try:
generated = (
GeneratedRegex
.model_validate(parsed)
)
except ValidationError as error:
raise RuntimeError(
f"Generated regex failed "
f"validation: {error}"
) from error
if generated.dialect != request.dialect:
raise RuntimeError(
"Generated dialect does not "
"match requested dialect."
)
if (
generated.match_mode
!= request.match_mode
):
raise RuntimeError(
"Generated match mode does not "
"match requested mode."
)
return generated
تبدیل Flagها به Python Regex Flags
فایل regex_generator/tester.py:
import regex
from regex_generator.schemas import (
GeneratedRegex,
RegexRequest,
RegexTestResult,
)
REGEX_TIMEOUT_SECONDS = 0.05
def build_flags(
flag_names: list[str],
) -> int:
flags = 0
mapping = {
"IGNORECASE": regex.IGNORECASE,
"MULTILINE": regex.MULTILINE,
"DOTALL": regex.DOTALL,
"VERBOSE": regex.VERBOSE,
}
for flag_name in flag_names:
flags |= mapping[flag_name]
return flags
def execute_match(
compiled,
value: str,
match_mode: str,
):
if match_mode == "search":
return compiled.search(
value,
timeout=REGEX_TIMEOUT_SECONDS,
)
if match_mode == "match":
return compiled.match(
value,
timeout=REGEX_TIMEOUT_SECONDS,
)
if match_mode == "fullmatch":
return compiled.fullmatch(
value,
timeout=REGEX_TIMEOUT_SECONDS,
)
raise ValueError(
f"Unsupported match mode: "
f"{match_mode}"
)
def test_generated_regex(
request: RegexRequest,
generated: GeneratedRegex,
) -> list[RegexTestResult]:
flags = build_flags(
generated.flags
)
try:
compiled = regex.compile(
generated.pattern,
flags,
)
except regex.error as error:
return [
RegexTestResult(
value="",
expected_match=True,
actual_match=False,
passed=False,
error=(
f"Regex compile error: "
f"{error}"
),
)
]
cases = [
(value, True)
for value in (
request.positive_examples
)
]
cases.extend(
(value, False)
for value in (
request.negative_examples
)
)
results: list[
RegexTestResult
] = []
for value, expected_match in cases:
try:
match = execute_match(
compiled,
value,
request.match_mode,
)
actual_match = (
match is not None
)
groups = {}
if match is not None:
groups = {
key: group_value
for key, group_value
in match.groupdict().items()
}
results.append(
RegexTestResult(
value=value,
expected_match=(
expected_match
),
actual_match=actual_match,
passed=(
actual_match
== expected_match
),
matched_text=(
match.group(0)
if match
else None
),
groups=groups,
)
)
except TimeoutError:
results.append(
RegexTestResult(
value=value,
expected_match=(
expected_match
),
actual_match=False,
passed=False,
error=(
"Regex evaluation "
"exceeded timeout."
),
)
)
return results
کتابخانه regex امکان Timeout برای Match را فراهم میکند. این محدودیت برای جلوگیری از مصرف طولانی CPU روی Pattern یا ورودی نامناسب مفید است.
چرا Pattern را با Runtime واقعی تست میکنیم؟
ممکن است مدل Pattern مربوط به JavaScript بسازد:
(?<code>[A-Z]+)
و آن را برای Python پیشنهاد دهد. در Python، Named Group متداول به شکل زیر است:
(?P<code>[A-Z]+)
Compile کردن Pattern در Runtime مقصد، خطاهای Dialect را پیش از استفاده آشکار میکند.
در نمونه آموزشی، اجرای تست با Python انجام میشود. برای اطمینان از Regex جاوااسکریپت باید Pattern در Node.js نیز Compile و تست شود.
اصلاح Regex شکستخورده
اگر نمونهها Pass نشوند، نتیجه واقعی را به مدل برمیگردانیم.
فایل regex_generator/repair.py:
import json
from regex_generator.generator import (
OUTPUT_TEMPLATE,
SYSTEM_PROMPT,
client,
model,
)
from regex_generator.schemas import (
GeneratedRegex,
RegexRequest,
RegexTestResult,
)
REPAIR_PROMPT = """
Regex قبلی برخی Test Caseها را پاس نکرده است.
فقط بر اساس Requirement و نتایج واقعی تست، Pattern را اصلاح کن.
قواعد:
- نمونه مثبت شکستخورده باید Match شود.
- نمونه منفی شکستخورده نباید Match شود.
- نمونههای قبلاً موفق را خراب نکن.
- Requirement جدید اضافه نکن.
- Pattern را بیش از حد عمومی نکن.
- Dialect و Match Mode را تغییر نده.
- خروجی فقط JSON معتبر باشد.
"""
def repair_regex(
request: RegexRequest,
generated: GeneratedRegex,
results: list[RegexTestResult],
) -> GeneratedRegex:
failed_results = [
result.model_dump()
for result in results
if not result.passed
]
payload = {
"request": request.model_dump(),
"previous_regex": (
generated.model_dump()
),
"failed_tests": failed_results,
}
response = client.chat.completions.create(
model=model,
temperature=0,
messages=[
{
"role": "system",
"content": (
SYSTEM_PROMPT
+ "\n"
+ REPAIR_PROMPT
),
},
{
"role": "user",
"content": (
json.dumps(
payload,
ensure_ascii=False,
indent=2,
)
+ "\n\nقالب خروجی:\n"
+ json.dumps(
OUTPUT_TEMPLATE,
ensure_ascii=False,
indent=2,
)
),
},
],
)
raw_output = (
response.choices[0]
.message.content
)
if not raw_output:
raise RuntimeError(
"The model returned an "
"empty repaired regex."
)
repaired = (
GeneratedRegex.model_validate(
json.loads(raw_output)
)
)
if repaired.dialect != request.dialect:
raise RuntimeError(
"Repair changed the dialect."
)
if (
repaired.match_mode
!= request.match_mode
):
raise RuntimeError(
"Repair changed match mode."
)
return repaired
ساخت Orchestrator
فایل regex_generator/service.py:
from regex_generator.generator import (
generate_regex,
)
from regex_generator.repair import (
repair_regex,
)
from regex_generator.schemas import (
RegexRequest,
RegexResponse,
)
from regex_generator.tester import (
test_generated_regex,
)
MAX_REPAIR_ATTEMPTS = 2
def build_and_test_regex(
request: RegexRequest,
) -> RegexResponse:
generated = generate_regex(
request
)
repair_attempts = 0
while True:
test_results = (
test_generated_regex(
request,
generated,
)
)
all_tests_passed = all(
result.passed
for result in test_results
)
if all_tests_passed:
break
if (
repair_attempts
>= MAX_REPAIR_ATTEMPTS
):
break
generated = repair_regex(
request,
generated,
test_results,
)
repair_attempts += 1
warnings = []
if not all_tests_passed:
warnings.append(
"Regex هنوز تمام Test Caseها "
"را پاس نکرده است و نباید بدون "
"بررسی استفاده شود."
)
if (
len(request.positive_examples)
< 3
):
warnings.append(
"تعداد نمونههای مثبت برای "
"ارزیابی قابل اتکا کم است."
)
if (
len(request.negative_examples)
< 3
):
warnings.append(
"تعداد نمونههای منفی برای "
"ارزیابی قابل اتکا کم است."
)
return RegexResponse(
generated=generated,
test_results=test_results,
all_tests_passed=(
all_tests_passed
),
repair_attempts=(
repair_attempts
),
warnings=warnings,
)
تعداد تلاش اصلاح محدود است. اگر بعد از دو مرحله Regex درست نشد، سیستم باید از کاربر نمونه یا توضیح بیشتری بخواهد.
ساخت API با FastAPI
فایل main.py:
from fastapi import (
FastAPI,
HTTPException,
)
from regex_generator.schemas import (
RegexRequest,
RegexResponse,
)
from regex_generator.service import (
build_and_test_regex,
)
app = FastAPI(
title="Darvareh AI Regex Generator",
version="1.0.0",
)
@app.get("/health")
def health_check():
return {
"status": "ok",
}
@app.post(
"/generate",
response_model=RegexResponse,
)
def generate_regex_endpoint(
request: RegexRequest,
):
overlapping_examples = (
set(request.positive_examples)
& set(request.negative_examples)
)
if overlapping_examples:
raise HTTPException(
status_code=422,
detail=(
"The same value cannot be both "
"positive and negative: "
+ ", ".join(
sorted(
overlapping_examples
)
)
),
)
try:
return build_and_test_regex(
request
)
except Exception as error:
raise HTTPException(
status_code=500,
detail=(
"Regex generation failed."
),
) from error
اجرای API
uvicorn main:app --reload
مستندات تعاملی:
http://127.0.0.1:8000/docs
آزمایش با curl
curl -X POST \
http://127.0.0.1:8000/generate \
-H "Content-Type: application/json" \
-d '{
"description": "کل رشته باید با ORD- شروع شود و پس از آن دقیقاً شش رقم لاتین باشد",
"dialect": "python",
"match_mode": "fullmatch",
"positive_examples": [
"ORD-123456",
"ORD-000001",
"ORD-999999"
],
"negative_examples": [
"ord-123456",
"ORD-12345",
"ORD-1234567",
"ORD-۱۲۳۴۵۶",
"XORD-123456"
],
"extraction_groups": [],
"constraints": [
"فاصله مجاز نیست",
"فقط رقم لاتین مجاز است"
]
}'
پاسخ مورد انتظار:
{
"generated": {
"dialect": "python",
"pattern": "^ORD-[0-9]{6}$",
"flags": [],
"match_mode": "fullmatch",
"explanation": [
{
"part": "^",
"meaning": "ابتدای رشته"
},
{
"part": "ORD-",
"meaning": "پیشوند ثابت"
},
{
"part": "[0-9]{6}",
"meaning": "دقیقاً شش رقم لاتین"
},
{
"part": "$",
"meaning": "انتهای رشته"
}
],
"assumptions": [],
"limitations": [],
"python_example": "import re\n...",
"javascript_example": "const pattern = /^ORD-[0-9]{6}$/;"
},
"all_tests_passed": true,
"repair_attempts": 0,
"warnings": []
}
استفاده در Python
import re
ORDER_ID_PATTERN = re.compile(
r"^ORD-[0-9]{6}$"
)
def is_valid_order_id(
value: str,
) -> bool:
return (
ORDER_ID_PATTERN.fullmatch(
value
)
is not None
)
آزمایش:
assert is_valid_order_id(
"ORD-123456"
)
assert not is_valid_order_id(
"ORD-۱۲۳۴۵۶"
)
استفاده در JavaScript
const orderIdPattern = /^ORD-[0-9]{6}$/;
function isValidOrderId(value) {
return orderIdPattern.test(value);
}
console.log(isValidOrderId("ORD-123456"));
console.log(isValidOrderId("ORD-۱۲۳۴۵۶"));
اگر Pattern دارای Flag g باشد، استفاده مکرر از test میتواند بهدلیل تغییر lastIndex رفتار متفاوتی داشته باشد. برای Validation معمولاً Flag سراسری لازم نیست.
ساخت Named Group
Requirement:
شناسه فاکتور با قالب INV-YYYY-NNNNNN است.
سال و شماره را جداگانه استخراج کن.
Python:
^INV-(?P<year>[0-9]{4})-(?P<number>[0-9]{6})$
استفاده:
import re
pattern = re.compile(
r"^INV-(?P<year>[0-9]{4})-"
r"(?P<number>[0-9]{6})$"
)
match = pattern.fullmatch(
"INV-2026-000125"
)
if match:
print(match.groupdict())
خروجی:
{
"year": "2026",
"number": "000125",
}
JavaScript:
^INV-(?<year>[0-9]{4})-(?<number>[0-9]{6})$
استفاده از Raw String در Python
بهتر است Patternها با Raw String نوشته شوند:
pattern = r"\d+\.\d+"
بهجای:
pattern = "\\d+\\.\\d+"
Raw String خوانایی را بهتر میکند و تداخل Escapeهای Python با Regex را کاهش میدهد.
Regex Verbose برای خوانایی
Pattern پیچیده:
import re
pattern = re.compile(
r"""
^
(?P<prefix>[A-Z]{3})
-
(?P<year>[0-9]{4})
-
(?P<number>[0-9]{6})
$
""",
re.VERBOSE,
)
در حالت Verbose فاصله و Commentهای بیرون Character Class معمولاً نادیده گرفته میشوند. این قابلیت برای نگهداری Patternهای پیچیده مناسب است.
Test Suite مستقل برای Regex
import re
import pytest
PATTERN = re.compile(
r"^ORD-[0-9]{6}$"
)
@pytest.mark.parametrize(
"value",
[
"ORD-123456",
"ORD-000001",
"ORD-999999",
],
)
def test_valid_order_ids(value):
assert PATTERN.fullmatch(value)
@pytest.mark.parametrize(
"value",
[
"ord-123456",
"ORD-12345",
"ORD-1234567",
"ORD-۱۲۳۴۵۶",
"XORD-123456",
" ORD-123456",
"ORD-123456 ",
"",
],
)
def test_invalid_order_ids(value):
assert not PATTERN.fullmatch(
value
)
Regex باید مانند هر منطق دیگری در Test Suite پروژه قرار گیرد.
تست Property-based برای Regex
با Hypothesis میتوان داده بیشتری تولید کرد:
pip install hypothesis
نمونه:
import re
from hypothesis import (
given,
strategies as st,
)
PATTERN = re.compile(
r"^ORD-[0-9]{6}$"
)
@given(
number=st.integers(
min_value=0,
max_value=999999,
)
)
def test_accepts_all_six_digit_order_ids(
number,
):
value = f"ORD-{number:06d}"
assert PATTERN.fullmatch(value)
این Test تضمین میکند تمام اعداد ششرقمی قالببندیشده پذیرفته شوند.
ساخت Regex برای Search and Replace
هدف:
فاصلههای چندگانه را به یک فاصله تبدیل کن.
Pattern:
[ \t]+
جایگزین:
یک فاصله
Python:
import re
cleaned = re.sub(
r"[ \t]+",
" ",
text,
)
اگر Line Break باید حفظ شود، استفاده از \s+ مناسب نیست؛ زیرا \s میتواند Newline را نیز Match کند.
Greedy و Lazy
متن:
<b>اول</b><b>دوم</b>
Greedy:
<b>.*</b>
ممکن است کل بخش زیر را Match کند:
<b>اول</b><b>دوم</b>
Lazy:
<b>.*?</b>
Matchهای جداگانه تولید میکند.
بااینحال برای پردازش HTML پیچیده بهتر است از Parser استفاده شود، نه Regex.
Lookahead و Lookbehind
مثال: عددی که بعد از price= آمده است:
(?<=price=)[0-9]+
اما Lookbehind در Dialectها و Runtimeهای مختلف محدودیتهایی دارد. راه سادهتر با Capture Group:
price=([0-9]+)
تا جای ممکن Pattern قابلحمل و قابلفهم را ترجیح دهید.
تشخیص Pattern بیش از حد عمومی
Pattern:
.*123.*
ممکن است نمونه مثبت را Match کند، اما احتمالاً نمونههای منفی زیادی نیز میپذیرد.
برای کاهش Overfitting و Underfitting:
- نمونههای منفی مشابه نمونه مثبت بسازید.
- یک کاراکتر را در هر نمونه تغییر دهید.
- طول کمتر و بیشتر را آزمایش کنید.
- فاصله ابتدا و انتها را آزمایش کنید.
- Unicode را آزمایش کنید.
- حروف کوچک و بزرگ را آزمایش کنید.
- متن اضافه قبل و بعد را آزمایش کنید.
تولید خودکار Test Case با AI
پرامپت:
برای Requirement و Regex زیر Test Case تولید کن.
دستهها:
- Valid Normal
- Minimum Boundary
- Maximum Boundary
- One Character Too Short
- One Character Too Long
- Wrong Prefix
- Wrong Case
- Leading Whitespace
- Trailing Whitespace
- Unicode Digit
- Extra Suffix
- Empty String
قواعد:
- نتیجه مورد انتظار هر مورد را مشخص کن.
- Test Case تکراری تولید نکن.
- Requirement جدید اختراع نکن.
Testهای تولیدشده نیز باید بازبینی شوند؛ زیرا ممکن است مدل نتیجه مورد انتظار را اشتباه تعیین کند.
استفاده از Regex برای استخراج، نه Parse کامل
Regex برای الگوهای محلی مناسب است:
- شناسه
- Token
- Placeholder
- بخش مشخص Log
- قالب ساده تاریخ
- Search and Replace
برای ساختارهای پیچیده بهتر است Parser استفاده شود:
- JSON
- XML
- HTML پیچیده
- کد برنامهنویسی
- SQL
- آدرس کامل
- تاریخ معتبر تقویمی
- فرمتهای دارای Grammar تو در تو
بررسی عملکرد Regex
برخی Patternها روی ورودی کوتاه سریعاند، اما روی متن طولانی زمان زیادی مصرف میکنند.
Patternهای دارای تکرار تو در تو نیازمند توجهاند:
(a+)+$
روشهای کاهش مشکل عملکردی:
- Pattern را ساده کنید.
- Anchor اضافه کنید.
- ورودی را محدود کنید.
- از تکرار تو در تو اجتناب کنید.
- Timeout بگذارید.
- روی ورودی نزدیک به حالت شکست Benchmark بگیرید.
- Regex را یکبار Compile و دوباره استفاده کنید.
Benchmark ساده
import time
import regex
pattern = regex.compile(
r"^ORD-[0-9]{6}$"
)
samples = [
"ORD-123456",
"ORD-999999",
"ORD-12345X",
] * 10_000
started_at = time.perf_counter()
for sample in samples:
pattern.fullmatch(
sample,
timeout=0.05,
)
elapsed = (
time.perf_counter()
- started_at
)
print(f"Elapsed: {elapsed:.4f}s")
Benchmark باید روی داده شبیه ورودی واقعی انجام شود.
پشتیبانی از JavaScript در ابزار
برای تست واقعی Pattern جاوااسکریپت، میتوان یک Runner Node.js ساخت:
const fs = require("fs");
const input = JSON.parse(
fs.readFileSync(0, "utf8")
);
const regex = new RegExp(
input.pattern,
input.flags
);
const results = input.cases.map((item) => ({
value: item.value,
expected: item.expected,
actual: regex.test(item.value),
}));
process.stdout.write(
JSON.stringify(results)
);
Backend داده تست را از stdin ارسال و خروجی JSON را دریافت میکند. Runner باید Timeout داشته باشد و در محیط محدود اجرا شود.
ساخت کتابخانه Patternهای تأییدشده
بهجای تولید دوباره Regexهای پرتکرار، Patternهای تأییدشده را ذخیره کنید:
{
"name": "internal_order_id",
"version": 2,
"dialect": "python",
"pattern": "^ORD-[0-9]{6}$",
"match_mode": "fullmatch",
"flags": [],
"test_suite": {
"positive": [],
"negative": []
},
"status": "approved"
}
مزایا:
- نسخهبندی
- استفاده مجدد
- تست Regression
- ثبت Requirement
- جلوگیری از تولید Pattern متفاوت
- امکان مهاجرت Dialect
ارزیابی AI Regex Generator
Dataset مرجع:
- شناسه ساده
- Prefix اختیاری
- طول متغیر
- Named Group
- Unicode
- Multiline
- Search
- Full Match
- Search and Replace
- Pattern ناممکن با Requirement متناقض
- تفاوت Python و JavaScript
- نمونههای مثبت و منفی مشابه
معیارها:
| معیار | توضیح |
|---|---|
| Compile Rate | درصد Patternهای قابل Compile |
| Positive Recall | نمونههای مثبت پذیرفتهشده |
| Negative Rejection | نمونههای منفی ردشده |
| Dialect Accuracy | سازگاری با Runtime مقصد |
| Group Accuracy | استخراج صحیح گروهها |
| Requirement Alignment | تطابق با توضیح |
| Repair Success | موفقیت چرخه اصلاح |
| Performance | زمان Match |
| Explanation Accuracy | توضیح درست Pattern |
| Human Acceptance | درصد Patternهای پذیرفتهشده |
انتخاب مدل مناسب
مدل مناسب باید در این موارد عملکرد خوبی داشته باشد:
- پیروی دقیق از Requirement
- شناخت Regex Dialect
- تولید JSON معتبر
- درک نمونههای مثبت و منفی
- توضیح Pattern
- اصلاح بر اساس نتیجه تست
- حفظ Constraintها
برای Patternهای ساده، مدل سریع و اقتصادی کافی است. برای الگوهای چندگروهی و تبدیل میان Dialectها، مدل قویتر ممکن است نتیجه بهتری بدهد.
فهرست مدلها و قیمتهای بهروز را در صفحه مدلهای درواره بررسی کنید.
اشتباهات رایج
درخواست Regex بدون مثال
حداقل چند نمونه مثبت و منفی ارائه دهید.
مشخصنکردن Dialect
Regex Python و JavaScript در برخی قابلیتها متفاوتاند.
استفاده از \d برای رقم لاتین
اگر فقط رقم لاتین لازم است، [0-9] بنویسید.
استفاده از Search برای Validation
برای اعتبارسنجی معمولاً Full Match مناسبتر است.
اعتماد به ظاهر Pattern
Regex باید Compile و روی Test Suite اجرا شود.
تلاش برای Parse ساختار پیچیده
برای HTML، JSON یا کد از Parser استفاده کنید.
نبود محدودیت طول ورودی
حتی Pattern ساده نیز باید روی ورودی کنترلشده استفاده شود.
اصلاح نامحدود با مدل
تعداد تلاشها باید محدود و Failureها به کاربر گزارش شوند.
ذخیرهنکردن Requirement
Pattern بدون توضیح و تست در آینده قابل نگهداری نیست.
نقشه راه Production
مرحله اول: Generator دستی
Requirement و Test Case وارد و Pattern نمایش داده شود.
مرحله دوم: اجرای Test
تمام نمونهها در Runtime مقصد اجرا شوند.
مرحله سوم: Repair محدود
فقط Testهای شکستخورده برای اصلاح به مدل برگردند.
مرحله چهارم: Approval
Pattern پس از بازبینی ذخیره شود.
مرحله پنجم: Versioning
هر تغییر Pattern نسخه جدید داشته باشد.
مرحله ششم: CI
Test Suite Patternهای تأییدشده در CI اجرا شود.
چکلیست Regex تولیدشده
- Dialect مشخص است.
- Match Mode مشخص است.
- Requirement دقیق است.
- نمونه مثبت کافی وجود دارد.
- نمونه منفی مشابه وجود دارد.
- مرزهای طول آزمایش شدهاند.
- فاصله ابتدا و انتها بررسی شده است.
- رفتار Unicode مشخص است.
- Pattern در Runtime مقصد Compile میشود.
- تمام Test Caseها Pass شدهاند.
- Groupهای استخراجی بررسی شدهاند.
- عملکرد روی ورودی بلند آزمایش شده است.
- Pattern و Test Suite نسخهبندی شدهاند.
- توضیح Pattern ذخیره شده است.
- API Key فقط در Backend قرار دارد.
پرسشهای متداول
Regex چیست؟
Regex یا Regular Expression زبانی برای تعریف الگوهای متنی است و برای جستوجو، استخراج، جایگزینی و اعتبارسنجی قالب متن استفاده میشود.
آیا هوش مصنوعی میتواند Regex بسازد؟
بله. اگر Requirement، Dialect و نمونههای مثبت و منفی را ارائه دهید، مدل میتواند Pattern تولید کند. نتیجه باید در Runtime مقصد آزمایش شود.
چگونه Regex تولیدشده را تست کنیم؟
Pattern را Compile و روی مجموعهای از ورودیهای معتبر، نامعتبر و مرزی اجرا کنید. نتیجه واقعی باید با انتظار هر Test Case مقایسه شود.
تفاوت Regex در Python و JavaScript چیست؟
Named Group، Flagها، Full Match و برخی قابلیتها در این دو محیط متفاوتاند. Dialect باید هنگام تولید مشخص شود.
چرا \d ارقام فارسی را Match میکند؟
در برخی Runtimeها از جمله Python، \d میتواند ارقام Unicode را بپذیرد. برای فقط رقم لاتین از [0-9] استفاده کنید.
آیا میتوان با Regex ایمیل را کاملاً اعتبارسنجی کرد؟
Regex ساده برای بررسی قالب پایه مناسب است، اما برای اعتبارسنجی کامل بهتر است از Parser و جریان تأیید مناسب محصول استفاده شود.
آیا میتوان Pattern تولیدشده را مستقیم در Production استفاده کرد؟
خیر. ابتدا Compile، Test Case، ورودی طولانی، Dialect و رفتار مرزی را بررسی و Pattern را نسخهبندی کنید.
بهترین مدل برای تولید Regex چیست؟
مدل باید در پیروی از Constraint، شناخت Dialect و تولید خروجی ساختاریافته مناسب باشد. مدلهای موجود را در صفحه مدلهای درواره مقایسه کنید.
API درواره چگونه متصل میشود؟
در Backend، base_url را روی https://api.darvareh.ir/v1 قرار دهید و Requirement و Test Caseها را برای مدل ارسال کنید. Pattern در Backend Compile و آزمایش میشود.
جمعبندی
هوش مصنوعی میتواند ساخت و توضیح Regex را بسیار سریعتر کند، اما Pattern تولیدشده فقط زمانی قابل استفاده است که با Requirement روشن و Test Caseهای کافی همراه باشد.
روش مناسب این است که ابتدا Dialect، Match Mode، نمونههای مثبت، نمونههای منفی و Constraintها مشخص شوند. مدل Pattern و توضیح آن را تولید کند، سپس Backend آن را در Runtime واقعی Compile و آزمایش کند. اگر تستی شکست خورد، فقط نتیجه واقعی همان تستها برای اصلاح محدود به مدل برگردانده شود.
در پروژه این مقاله یک AI Regex Generator با Python، FastAPI، Pydantic، کتابخانه regex و API درواره ساختیم. این ابزار Regex را تولید، با Timeout اجرا، نتیجه نمونهها را مقایسه و حداکثر در دو مرحله اصلاح میکند.
برای شروع، در درواره ثبتنام و API Key دریافت کنید. سپس مدل مناسب را از صفحه مدلهای درواره انتخاب کرده و ابزار را ابتدا با Patternهای ساده و Test Caseهای دقیق آزمایش کنید.
مقالات مرتبط
- ساخت دستیار برنامهنویسی اختصاصی برای شرکت
- بهترین مدل هوش مصنوعی برای برنامهنویسی
- بهترین ابزارهای برنامهنویسی با هوش مصنوعی؛ بخش اول
- بهترین ابزارهای برنامهنویسی با هوش مصنوعی؛ بخش دوم
- آموزش Structured Outputs و JSON Schema
- آموزش ارزیابی مدلهای هوش مصنوعی و Evals
- چگونه API هوش مصنوعی را به نرمافزار خود اضافه کنیم؟
- راهنمای ساخت API هوش مصنوعی آماده Production
برای مطالعه شرایط استفاده و محدودیتهای مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.