Python: التعبيرات العادية

التعبير العادي (regex) هو لغة خاصة لوصف أنماط النص. سطر واحد من regex يمكنه فعل ما يتطلبه عشرات الأسطر من الكود اليدوي لمطابقة واستخراج النص. إنه موجود في كل مكان في تنظيف البيانات، تحليل السجلات، والتحقق من صحة النماذج.


1. ما هو التعبير العادي

التعبير العادي يستخدم رموزاً خاصة لوصف "أي نوع من السلاسل النصية أبحث عنه."

PYTHON
import re

# أبسط تعبير عادي: طابق سلسلة مباشرة
pattern = r"hello"
text = "hello world"

result = re.search(pattern, text)
if result:
    print("Found!")                 # Found!
    print(result.group())           # hello
    print(result.start())           # 0 (موضع البداية)
    print(result.end())             # 5 (موضع النهاية)
⚠️ دائماً اسبق سلاسل التعبير العادي بـ r (سلسلة أولية). r"\n" هي شرطة مائلة + حرف n، وليس سطراً جديداً. التعبيرات العادية تستخدم الشرطات المائلة العكسية بكثرة؛ بدون r، ستحتاج لكتابة \\n، وهو أمر مؤلم.



2. الطرق الشائعة

PYTHON
import re

text = "My email is alice@example.com, also bob@test.com"

# search() — ابحث عن أول تطابق
result = re.search(r"\w+@\w+\.\w+", text)
print(result.group())               # alice@example.com

# findall() — ابحث عن جميع التطابقات
emails = re.findall(r"\w+@\w+\.\w+", text)
print(emails)                       # ['alice@example.com', 'bob@test.com']

# match() — طابق من البداية
print(re.match(r"My", text))        # تطابق (في البداية)
print(re.match(r"email", text))     # None (ليس في البداية)

# sub() — استبدال
masked = re.sub(r"\w+@", "***@", text)
print(masked)                       # My email is ***@example.com, also ***@test.com


3. مرجع سريع للرموز الوصفية

الرمز المعنى مثال يطابق
. أي حرف واحد (باستثناء السطر الجديد) h.t hat, hot, hit
\d رقم \d{3} 123, 456
\w حرف/رقم/شرطة سفلية \w+ hello, abc123
\s مسافة بيضاء \s مسافة، تبويب، سطر جديد
* 0 أو أكثر مما قبله ab*c ac, abc, abbc
+ 1 أو أكثر مما قبله ab+c abc, abbc (ليس ac)
? 0 أو 1 مما قبله colou?r color, colour
{n} بالضبط n مرة \d{4} 2026, 1990
{n,m} من n إلى m مرة \d{2,4} 23, 456, 2026
^ بداية السلسلة ^Hello Hello...
$ نهاية السلسلة end$ ...end
[] مجموعة أحرف [aeiou] أي حرف علة
` ` أو `cat

▶ مثال: التحقق من صحة رقم الهاتف (الصعوبة ⭐⭐)

PYTHON
import re

def is_valid_phone(phone):
    """تحقق من رقم هاتف محمول صيني (11 رقماً، يبدأ بـ 1)"""
    pattern = r"^1[3-9]\d{9}$"
    return bool(re.match(pattern, phone))

phones = ["13800138000", "12345678901", "010-12345678", "1380013800a"]
for p in phones:
    print(f"{p}: {'✅' if is_valid_phone(p) else '❌'}")

# استخرج جميع أرقام الهواتف من النص
text = "Contact: 13800138000, backup: 13912345678, landline: 010-12345678"
phones = re.findall(r"1[3-9]\d{9}", text)
print(f"Found phones: {phones}")
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Function defined successfully


4. التقاط المجموعات

استخدم الأقواس () لتقسيم المحتوى المطابق إلى أجزاء متعددة:

PYTHON
import re

# استخرج اسم المستخدم والنطاق من البريد الإلكتروني
email = "alice@example.com"
pattern = r"(\w+)@(\w+\.\w+)"
result = re.search(pattern, email)

if result:
    print(f"Full match: {result.group(0)}")    # alice@example.com
    print(f"Username: {result.group(1)}")      # alice
    print(f"Domain: {result.group(2)}")        # example.com

# استخرج معلومات من سجل
log = "2026-06-23 15:30:45 ERROR Database connection timeout"
pattern = r"(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (\w+) (.+)"
result = re.search(pattern, log)
print(f"Date: {result.group(1)}")           # 2026-06-23
print(f"Time: {result.group(2)}")           # 15:30:45
print(f"Level: {result.group(3)}")          # ERROR
print(f"Message: {result.group(4)}")        # Database connection timeout

▶ مثال: محلل URL (الصعوبة ⭐⭐⭐)

PYTHON
import re

def parse_url(url):
    """حلل URL لاستخراج البروتوكول والنطاق والمسار ومعاملات الاستعلام"""
    pattern = r"(https?)://([^/]+)(/[^?]*)?(?:\?([^#]*))?"
    result = re.search(pattern, url)
    if not result:
        return None
    
    return {
        "protocol": result.group(1),
        "domain": result.group(2),
        "path": result.group(3) or "/",
        "query": result.group(4) or ""
    }

urls = [
    "https://www.example.com/path/page.html?id=123&name=test",
    "http://localhost:8080/api/users",
    "https://google.com"
]

for url in urls:
    info = parse_url(url)
    if info:
        print(f"\nURL: {url}")
        for key, value in info.items():
            print(f"  {key}: {value}")
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Function defined successfully

▶ مثال: استبدال النص والتعتيم (الصعوبة ⭐⭐)

PYTHON
import re

text = "User Alice's phone is 13800138000, email is alice@example.com, ID 110101199001011234"

phone_masked = re.sub(r"(1[3-9]\d)\d{4}(\d{4})", r"\1****\2", text)
print(f"Phone masked: {phone_masked}")

email_masked = re.sub(r"(\w{2})\w+(@\w+\.\w+)", r"\1***\2", text)
print(f"Email masked: {email_masked}")

id_masked = re.sub(r"(\d{4})\d{10}(\d{4})", r"\1**********\2", text)
print(f"ID masked: {id_masked}")

template = "Hello, {name}! Order {order_id} has been shipped."
data = {"name": "Alice", "order_id": "ORD2024001"}
result = re.sub(r"\{(\w+)\}", lambda m: data.get(m.group(1), m.group(0)), template)
print(f"Template result: {result}")
▶ جرّب الكود

المخرجات:

TEXT 📖 للعرض فقط
Phone masked: User Alice's phone is 138****8000, email is alice@example.com, ID 110101199001011234
Email masked: User Alice's phone is 13800138000, email is al***@example.com, ID 110101199001011234
ID masked: User Alice's phone is 13800138000, email is alice@example.com, ID 1101**********1234
Template result: Hello, Alice! Order ORD2024001 has been shipped.


5. المطابقة الجشعة مقابل الكسولة

افتراضياً، * و + هما جشعان — يطابقان أكبر قدر ممكن. إضافة ? تجعلهما كسولين — يطابقان أقل قدر ممكن:

PYTHON
import re

text = "<h1>Title</h1><p>Paragraph</p>"

# الوضع الجشع — يطابق أكبر قدر ممكن
greedy = re.search(r"<.+>", text)
print(greedy.group())               # <h1>Title</h1><p>Paragraph</p>

# الوضع الكسول — يطابق أقل قدر ممكن (أضف ?)
lazy = re.search(r"<.+?>", text)
print(lazy.group())                 # <h1>
💡 .*? (كسول) مقابل .* (جشع): عند العمل مع محتوى منظم مثل HTML أو JSON، الوضع الكسول أكثر شيوعاً. الوضع الجشع غالباً "يتجاوز" ليطابق محتوى لا ينبغي له. إذا كنت غير متأكد، ابدأ بالكسول.



6. حالات الاستخدام الشائعة



❓ أسئلة شائعة

س ماذا تعني البادئة r في التعبير العادي؟
ج r تشير إلى سلسلة أولية. في سلسلة عادية، \n هو سطر جديد؛ في سلسلة أولية، \n هو مجرد شرطة مائلة + حرف n. التعبيرات العادية تستخدم الشرطات المائلة العكسية بكثرة (مثل \d, \w)؛ بدون r، ستحتاج لكتابة \\d، وهو أمر مؤلم جداً.
س ما أداء التعبيرات العادية؟
ج سريعة بما يكفي لمعظم الحالات. لكن الأنماط المكتوبة بشكل سيئ (مثل الكميات المتداخلة (.*)*) يمكن أن تسبب "تراجعاً كارثياً" — يستغرق دقائق لنص بسيط. الحلول: تجنب الكميات المتداخلة، استخدم الوضع الكسول، واستخدم re.compile() للأنماط المستخدمة frequently.
س التعبير العادي المعقد صعب القراءة. أي نصائح؟
ج ① أضف تعليقات — الوضع re.VERBOSE يسمح بمسافات وتعليقات في regex. ② قسمه إلى أنماط بسيطة متعددة. ③ استخدم أدوات عبر الإنترنت مثل regex101.com للتصحيح. Regex هو الكلاسيكي "ممتع في الكتابة، مؤلم في القراءة" — لا تحاول حل كل شيء بـ regex واحد.

📖 ملخص


📝 تمارين

  1. أساسي (الصعوبة ⭐): اكتب دالة is_valid_email(email) تستخدم regex للتحقق من صلاحية عنوان البريد الإلكتروني (يحتوي على @، غير فارغ على كلا الجانبين، له لاحقة نطاق).

  2. متوسط (الصعوبة ⭐⭐): اكتب دالة extract_numbers(text) تستخرج جميع الأرقام (بما في ذلك الأعداد الصحيحة والعشرية) من سلسلة وتُرجع مجموعها. مثال: "Price is 19.99, shipping 5, coupon -10" ← تُرجع 14.99.

  3. تحدي (الصعوبة ⭐⭐⭐): اكتب "محرك قوالب بسيط." بالنظر إلى القالب "Hello, {name}! Your order {order_id} has been shipped, arriving in {days} days." وقاموس {"name": "Alice", "order_id": "2024001", "days": 3}، استخدم regex لاستبدال جميع العناصر النائبة {variable} بالقيم الفعلية. تلميح: استخدم re.sub() مع دالة استدعاء عكسي.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%