🔍 التعبيرات النمطية (RegEx) في جافا: دليل المبتدئين لفهم النصوص والبحث فيها

مرحباً بكم في عالم التعبيرات النمطية (Regular Expressions) أو ما يُعرف اختصاراً بـ RegEx! 🎯 تخيل أن لديك كومة ضخمة من النصوص وتريد البحث عن أرقام هواتف، أو عناوين بريد إلكتروني، أو حتى كلمات محددة بنمط معين. البحث اليدوي مستحيل! هنا يأتي دور RegEx كبطل خارق للبحث والتحقق من النصوص.

ببساطة، التعبير النمطي (RegEx) هو تسلسل من الرموز والحروف الخاصة يصف نمطاً (Pattern) محدداً للنص الذي نريد البحث عنه أو التحقق منه. جافا تزودنا بأدوات قوية للتعامل مع هذه التعبيرات عبر حزمة java.util.regex.


📦 المكونان الأساسيان: Pattern و Matcher

تعمل التعبيرات النمطية في جافا عبر فصل المهمة إلى جزأين:

  1. فئة Pattern (النمط): هذه الفئة مسؤولة عن تجميع (Compiling) التعبير النمطي الذي تكتبه (كـ String) وتحويله إلى كائن يمكن للجافا فهمه والتعامل معه بكفاءة. التعبير النمطي نفسه يُكتب كسلسة نصية عادية.
  2. فئة Matcher (المطابق): بمجرد أن يكون لدينا كائن Pattern، نستخدم كائن Matcher لتنفيذ عمليات المطابقة (Matching) على النص المستهدف. هو الذي يقول: "هذا النص يتطابق مع النمط" أو "هذا النص لا يتطابق".

🛠️ طريقة العمل خطوة بخطوة

لنطبق ما تعلمناه بمثال بسيط: نريد التحقق إذا كان نص معين يتكون بالضبط من ثلاث أحرف.

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class RegexExample1 {
    public static void main(String[] args) {
        // الخطوة 1: تعريف التعبير النمطي كسلسلة نصية
        // النمط هنا يعني: "أي حرف (a-z, A-Z, 0-9, _)"، ويجب أن يتكرر 3 مرات بالضبط {3}
        String regexPattern = "\\w{3}";
        
        // الخطوة 2: تجميع النمط إلى كائن Pattern
        Pattern pattern = Pattern.compile(regexPattern);
        
        // الخطوة 3: إنشاء كائن Matcher لمطابقة النمط مع نصنا المستهدف
        Matcher matcher = pattern.matcher("Cat");
        
        // الخطوة 4: إجراء المطابقة (هل النص بأكمله يطابق النمط؟)
        boolean isMatch = matcher.matches(); // يرجع true أو false
        
        System.out.println("هل 'Cat' تطابق النمط؟ " + isMatch); // الناتج: true
        System.out.println("هل 'Java' تطابق النمط؟ " + pattern.matcher("Java").matches()); // الناتج: false (أربعة أحرف)
        System.out.println("هل 'A1' تطابق النمط؟ " + pattern.matcher("A1").matches()); // الناتج: false (حرفان فقط)
    }
}

🔤 الرموز الأساسية في التعبيرات النمطية (للمبتدئين)

هذه بعض الرموز الأكثر استخداماً لتبدأ رحلتك:

  • . (النقطة): تمثل أي حرف واحد (عدا أسطر جديدة).
    • "c.t" تطابق: "cat", "cot", "c9t".
  • \d (رقم): تمثل رقم واحد (من 0 إلى 9).
    • "\d\d" تطابق: "42", "01".
  • \w (كلمة): تمثل حرف كلمة واحد (أحرف إنجليزية كبيرة/صغيرة، أرقام، الشرطة السفلية _).
    • "\w\w" تطابق: "Hi", "A1", "__".
  • \s (مسافة): تمثل مسافة بيضاء واحدة (مسافة، Tab، سطر جديد).
  • [ ] (مجموعة أحرف): تمثل أي حرف واحد من بين الأحرف الموجودة داخل الأقواس.
    • "[aeiou]" تطابق أي حرف متحرك إنجليزي صغير.
    • "[A-Z]" تطابق أي حرف إنجليزي كبير.
  • {n} (عدد التكرار): تمثل تكرار العنصر السابق بالضبط n مرة.
    • "\d{4}" تطابق أي أربعة أرقام متتالية مثل "2024".
  • + (واحد أو أكثر): تمثل تكرار العنصر السابق مرة واحدة على الأقل.
    • "\d+" تطابق: "7", "123", "9999".
  • * (صفر أو أكثر): تمثل تكرار العنصر السابق صفر مرات أو أكثر.

ملاحظة مهمة في الجافا: لأن الشرطة المائلة الخلفية \ لها معنى خاص في السلاسل النصية، يجب هربها (Escape) بشرطة أخرى عند كتابة التعبير النمطي. لذا \d تكتب "\\d"، و \w تكتب "\\w".


💡 أمثلة عملية وبسيطة جداً

مثال 1: التحقق من صحة رقم هاتف مكون من 10 أرقام

public class PhoneValidator {
    public static void main(String[] args) {
        // النمط: 3 أرقام، ثم 3 أرقام، ثم 4 أرقام (مثل 123-456-7890)
        String phonePattern = "\\d{3}-\\d{3}-\\d{4}";
        Pattern pattern = Pattern.compile(phonePattern);
        
        System.out.println("هل '123-456-7890' رقم صالح؟ " + pattern.matcher("123-456-7890").matches()); // true
        System.out.println("هل '12-3456-789' رقم صالح؟ " + pattern.matcher("12-3456-789").matches()); // false
    }
}

مثال 2: البحث عن كلمة محددة في نص طويل (باستخدام find())

طريقة matches() تتحقق من المطابقة الكاملة. أما find() فتبحث عن أي جزء في النص يطابق النمط.

public class FindExample {
    public static void main(String[] args) {
        String text = "تعلم جافا ممتع. جافا لغة قوية.";
        String regex = "جافا";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        
        System.out.println("بحث عن كلمة 'جافا':");
        while (matcher.find()) {
            System.out.println("عُثر على الكلمة في الموضع: " + matcher.start());
        }
        // الناتج:
        // عُثر على الكلمة في الموضع: 6
        // عُثر على الكلمة في الموضع: 20
    }
}

🧪 تطبيق سريع: طريقة String.matches()

توفر فئة String طريقة مختصرة للتحقق من مطابقة نمط دون الحاجة لإنشاء كائنات Pattern و Matcher صراحةً، وهي ممتازة للتحقق البسيط.

public class SimpleMatch {
    public static void main(String[] args) {
        String email = "user@example.com";
        
        // نمط بسيط جداً للتوضيح: أحرف+أرقام، ثم @، ثم أحرف، ثم .، ثم أحرف
        boolean isValid = email.matches("\\w+@\\w+\\.\\w+");
        
        System.out.println("هل البريد الإلكتروني '" + email + "' صالح؟ " + isValid); // true
        System.out.println("هل 'notAnEmail' صالح؟ " + "notAnEmail".matches("\\w+@\\w+\\.\\w+")); // false
    }
}