التعبيرات النمطية في Rust مع أمثلة: عمليًا

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

التعبيرات النمطية في Rust مع أمثلة: عمليًا

\n\n

التعبيرات النمطية (regex) هي أداة قوية للعمل مع النصوص. في Rust، على الرغم من الكتابة الصارمة والتركيز على الأمان، فإن العمل مع التعبيرات النمطية يتم بكفاءة وسهولة بفضل crate regex. في هذه المقالة، سنشرح كيفية استخدام التعبيرات النمطية في Rust عمليًا: من التثبيت إلى سيناريوهات معالجة السلاسل النصية المعقدة.

\n\n

سنستعرض العمليات الأساسية: البحث، الاستخراج، الاستبدال، والتحقق من الصحة. جميع أمثلة الكود مكتوبة بلغة Rust وجاهزة للاستخدام.

\n\n

تثبيت وإضافة crate regex

\n\n

للعمل مع التعبيرات النمطية في Rust، يتم استخدام crate خارجي ولكنه شائع جدًا وهو regex. هذا crate غير مضمن في المكتبة القياسية، لذا يجب إضافته إلى المشروع.

\n\n

أضف التبعية إلى ملف Cargo.toml:

\n\n
[dependencies]\nregex = "1"
\n\n

بعد ذلك، يمكن استيراد الأنواع الأساسية في الكود:

\n\n
use regex::Regex;
\n\n

يقوم crate regex بترجمة التعبير النمطي إلى آلة حالة محدودة، مما يوفر أداءً عاليًا. يتم اكتشاف أخطاء ترجمة النمط في وقت التشغيل (عبر Result)، مما يجعل الكود موثوقًا.

\n\n

الأساسيات: البحث عن التطابقات في سلسلة نصية

\n\n

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

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b").unwrap();\n    let text = "تواصل معنا على البريد الإلكتروني support@example.com.";\n\n    if re.is_match(text) {\n        println!("تم العثور على البريد الإلكتروني!");\n    } else {\n        println!("لم يتم العثور على البريد الإلكتروني.");\n    }\n}
\n\n

تأخذ طريقة Regex::new سلسلة نصية تحتوي على النمط وتعيد Result. يتم استخدام unwrap() هنا للتبسيط، ولكن في كود الإنتاج يجب معالجة الأخطاء بشكل صحيح.

\n\n

للبحث عن جميع التطابقات، يتم استخدام طريقة find_iter التي تعيد مكررًا عبر كائنات Match:

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"\\d+").unwrap();\n    let text = "الأسعار: 100 و 250 و 500 روبل.";\n\n    for mat in re.find_iter(text) {\n        println!("تم العثور على رقم: {}", mat.as_str());\n    }\n}
\n\n

سيقوم هذا الكود بطباعة:

\n\n
تم العثور على رقم: 100\nتم العثور على رقم: 250\nتم العثور على رقم: 500
\n\n

استخراج البيانات باستخدام مجموعات الالتقاط

\n\n

تسمح مجموعات الالتقاط (capturing groups) باستخراج ليس فقط التطابق الكامل، بل أجزاء منه. على سبيل المثال، تحليل تاريخ بتنسيق "يوم-شهر-سنة".

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"(\\d{2})-(\\d{2})-(\\d{4})").unwrap();\n    let text = "اليوم 15-03-2024.";\n\n    if let Some(caps) = re.captures(text) {\n        println!("اليوم: {}", &caps[1]);\n        println!("الشهر: {}", &caps[2]);\n        println!("السنة: {}", &caps[3]);\n    }\n}
\n\n

يبدأ ترقيم المجموعات من 1 (المجموعة 0 هي التطابق الكامل). تعيد طريقة captures Option<Captures>. إذا تم العثور على تطابق، يمكننا الوصول إلى المجموعات عبر الفهرس.

\n\n

لاستخراج جميع التكرارات مع المجموعات، يتم استخدام captures_iter:

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"(\\w+)@(\\w+)\\.(\\w+)").unwrap();\n    let text = "البريد الإلكتروني: user@host.com, admin@site.org";\n\n    for caps in re.captures_iter(text) {\n        println!("اسم المستخدم: {}, المضيف: {}, النطاق: {}", &caps[1], &caps[2], &caps[3]);\n    }\n}
\n\n

هذا الأسلوب لا غنى عنه عند تحليل السجلات وملفات التكوين أو استخراج البيانات المنظمة من النص غير المنظم.

\n\n

استبدال النص وفقًا لنمط

\n\n

يوفر crate regex طرقًا لاستبدال النص. على سبيل المثال، إخفاء أرقام بطاقات الائتمان:

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"\\d{4}-\\d{4}-\\d{4}-\\d{4}").unwrap();\n    let text = "بطاقتي: 1234-5678-9012-3456.";\n    let result = re.replace_all(text, "****-****-****-****");\n    println!("{}", result);\n}
\n\n

سيقوم هذا الكود بطباعة:

\n\n
بطاقتي: ****-****-****-****.
\n\n

يمكن أيضًا استخدام المراجع الخلفية (backreferences) في سلسلة الاستبدال. على سبيل المثال، تغيير تنسيق التاريخ من "يوم-شهر-سنة" إلى "سنة/شهر/يوم":

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"(\\d{2})-(\\d{2})-(\\d{4})").unwrap();\n    let text = "التاريخ: 15-03-2024.";\n    let result = re.replace_all(text, "$3/$2/$1");\n    println!("{}", result);\n}
\n\n

النتيجة:

\n\n
التاريخ: 2024/03/15.
\n\n

طريقة replace تستبدل التطابق الأول فقط، بينما replace_all تستبدل جميع التطابقات.

\n\n

التحقق من صحة البيانات (Validation)

\n\n

غالبًا ما تُستخدم التعبيرات النمطية للتحقق من صحة إدخال المستخدم. على سبيل المثال، التحقق من صحة رقم الهاتف:

\n\n
use regex::Regex;\n\nfn validate_phone(phone: &str) -> bool {\n    let re = Regex::new(r"^\\+?[1-9]\\d{1,14}$").unwrap();\n    re.is_match(phone)\n}\n\nfn main() {\n    let phones = vec!["+71234567890", "12345", "+7 (123) 456-78-90"];\n    for phone in phones {\n        println!("{}: {}", phone, validate_phone(phone));\n    }\n}
\n\n

هذا الكود سيطبع:

\n\n
+71234567890: true\n12345: false\n+7 (123) 456-78-90: false
\n\n

لاحظ أن التعبير النمطي لا يتحقق من صحة الأقواس والشرطات - فهو يقبل فقط الأرقام وعلامة "+" في البداية. للتحقق من الصيغ المعقدة، يجب استخدام تعبيرات نمطية أكثر دقة.

\n\n

نصائح لتحسين الأداء

\n\n

عند العمل مع كميات كبيرة من النصوص، يجب مراعاة ما يلي:

\n\n
    \n
  • تجميع التعبير النمطي مرة واحدة: أنشئ كائن Regex خارج الحلقة وأعد استخدامه.
  • \n
  • تجنب التعبيرات النمطية المعقدة بشكل مفرط: في بعض الأحيان، يكون التحليل اليدوي للسلسلة النصية أسرع.
  • \n
  • استخدم RegexSet: إذا كنت بحاجة إلى التحقق من تطابق سلسلة نصية مع عدة تعبيرات نمطية في وقت واحد، استخدم RegexSet من crate regex.
  • \n
  • انتبه إلى التجميع غير الالتقاطي: استخدم (?:...) بدلاً من (...) إذا لم تكن بحاجة إلى حفظ المجموعة.
  • \n
\n\n

الخلاصة

\n\n

التعبيرات النمطية في Rust هي أداة قوية ومرنة لمعالجة النصوص. بفضل crate regex، يمكنك بسهولة البحث عن البيانات واستخراجها واستبدالها والتحقق من صحتها. على الرغم من أن Rust لغة صارمة، إلا أن العمل مع التعبيرات النمطية فيها لا يختلف كثيرًا عن اللغات الأخرى، مع ميزة إضافية تتمثل في الأمان والأداء العالي.

\n\n

للاستخدام اليومي، يكفي حفظ الطرق الأساسية: is_match و find_iter و captures و replace. بالنسبة للمشاريع الأكثر تعقيدًا، ادرس وثائق crate regex - ستجد هناك العديد من الميزات المفيدة.

المدونات

توصيات الكتب