ترجم مرة واحدة، ثم طابق
اكتب الأنماط كنصوص خام بين علامتي الاقتباس المائلتين. في النص العادي بين علامتي اقتباس مزدوجتين يجب مضاعفة كل شرطة مائلة عكسية ("\\d+")، وهذا يصير غير مقروء بسرعة.
تسبّب regexp.MustCompile حالة panic إذا كان النمط غير صالح، وهذا ما تريده لنمط في شيفرتك المصدرية: يفشل خطأ الكتابة فورًا عند بدء التشغيل، لا عند أول طلب. للأنماط القادمة من المستخدمين أو الإعدادات استخدم regexp.Compile وعالج الخطأ:
re, err := regexp.Compile(userPattern)
if err != nil {
return fmt.Errorf("bad pattern: %w", err)
}
ترجم مرة واحدة. الترجمة أغلى بكثير من المطابقة. regexp.MustCompile داخل دالة تُنفَّذ لكل طلب أو لكل سطر تكرّر هذا العمل كل مرة. ضع *regexp.Regexp المترجم في var على مستوى الحزمة أو في حقل بنية. والتعبير النمطي المترجم آمن للاستخدام من goroutines كثيرة معًا.
تترجم regexp.MatchString(pattern, s) وتطابق في استدعاء واحد. لا بأس بها لفحص عابر، وهي هدر في حلقة.
إيجاد المطابقات
تتبع أسماء التوابع نمطًا: Find + All? + String? + Submatch? + Index?.
| الجزء | المعنى |
|---|---|
All | كل مطابقة غير متداخلة؛ يأخذ حدًا n (-1 للكل) |
String | يعمل على string؛ ومن دونه يأخذ التابع []byte ويعيده |
Submatch | يعيد مجموعات الالتقاط أيضًا |
Index | يعيد إزاحات البايتات بدل النص |
تعيد FindString القيمة "" عندما لا توجد مطابقة، ولا يمكن تمييز ذلك عن مطابقة نص فارغ. عندما يمكن للنمط مطابقة نص فارغ استخدم FindStringIndex (تعيد nil عند عدم المطابقة) أو MatchString أولًا. وتعيد صيغ All القيمة nil عندما لا يطابق شيء.
مجموعات الالتقاط
الأقواس تلتقط. تعيد FindStringSubmatch المطابقة كاملة في الفهرس 0، ثم مدخلًا لكل مجموعة:
تحقّق دائمًا من nil قبل فهرسة النتيجة؛ عند عدم المطابقة تسبّب m[1] حالة panic.
يجمّع (?:...) دون التقاط، للتناوب أو التكرار: (?:ab)+. وتُكتب المجموعات المسمّاة (?P<name>...)، ومنذ Go 1.22 أيضًا (?<name>...).
الاستبدال
فخ كلاسيكي مع مراجع المجموعات: "$1x" تُقرأ كمجموعة اسمها 1x، وهي غير موجودة، فتتوسّع إلى نص فارغ. اكتب "${1}x".
للنص الثابت تكون strings.ReplaceAll وstrings.Contains وstrings.Split أبسط وأسرع من تعبير نمطي. لجأ إلى regexp عندما يكون للنص الذي تبحث عنه شكل لا قيمة ثابتة.
مرجع سريع للصياغة
تستخدم Go صياغة RE2، التي تغطّي الميزات المألوفة بأسلوب Perl:
| الصياغة | تطابق |
|---|---|
. | أي حرف عدا السطر الجديد (ومع (?s) السطر الجديد أيضًا) |
\d \w \s | رقم، حرف كلمة [0-9A-Za-z_]، مسافة بيضاء (ASCII فقط) |
\D \W \S | النفي لكل منها |
[abc] [^abc] [a-z] | أصناف الأحرف |
\pL \p{Greek} | أصناف Unicode: أي حرف، أي حرف يوناني |
* + ? {n,m} | التكرار، بشراهة |
*? +? ?? | التكرار، بكسل |
^ $ | بداية النص ونهايته (بداية السطر ونهايته مع (?m)) |
\b | حدّ كلمة (ASCII) |
a|b | التناوب |
(?i) | عدم تمييز حالة الأحرف من تلك النقطة حتى نهاية المجموعة المحيطة؛ ويُكتب عادة في بداية النمط |
لا يطابق \d و\w إلا ASCII. لـ "أي حرف في أي لغة" استخدم \pL، ولأي رقم Unicode استخدم \p{Nd}. تهرّب regexp.QuoteMeta(s) كل حرف خاص في s، وهذا ما تحتاجه عند بناء نمط من مدخلات المستخدم.
ما لا تستطيعه RE2
يضمن regexp في Go أن المطابقة تستغرق وقتًا خطيًا بطول المدخل. الميزات التي تكسر هذا الضمان غير مدعومة:
- لا lookahead ولا lookbehind:
(?=...)و(?!...)و(?<=...)و(?<!...)أخطاء ترجمة. ولأن Go 1.22 بدأت تقبل(?<name>...)للمجموعات المسمّاة، صار الـ lookbehind يفشل برسالة مربكة هيinvalid named capture، كما يُظهر البرنامج التالي. - لا مراجع خلفية:
(\w)\1لمطابقة حرف مضاعف غير ممكنة. - لا محدِّدات تكرار استحواذية ولا مجموعات ذرّية.
الحل البديل هو نفسه تقريبًا دائمًا: التقط أكثر قليلًا مما تحتاجه، ثم صفِّ أو اقتطع في Go. والمكسب أن تعبيرًا نمطيًا في Go لا يمكن دفعه إلى تراجع كارثي. نمط مثل (a+)+$ قد يجمّد محرّك PCRE مع مدخل قصير يعمل هنا في وقت خطي، وهذا مهم عندما يأتي النمط أو المدخل من الخارج.
أخطاء شائعة
- الترجمة داخل حلقة أو معالج. ترجم مرة واحدة إلى متغيّر على مستوى الحزمة.
- أنماط بين علامتي اقتباس مزدوجتين.
"\d"ليس حتى نصًا صالحًا في Go؛ استخدم علامتي الاقتباس المائلتين. - نسيان المثبّتات في التحقّق. يطابق
\d{5}داخل"abc123456xyz". استخدم^\d{5}$. - فهرسة نتيجة مجموعات فرعية دون فحص
nil. - توقّع أن يفهم
\wأو\bالنصوص غير ASCII. استخدم أصناف Unicode مثل\pL. - استخدام regexp للنصوص الثابتة. الحزمة
stringsأوضح وأسرع.
الأسئلة الشائعة
كيف أتحقّق من مطابقة نص لتعبير نمطي في Go؟
ترجم النمط مرة واحدة بـ regexp.MustCompile، واكتبه كنص خام بين علامتي الاقتباس المائلتين كي لا تحتاج الشرطات المائلة العكسية إلى هروب، ثم استدعِ re.MatchString(s). دون مثبّتات (^ و$) تعيد MatchString القيمة true إذا طابق النمط في أي مكان من النص.
هل يدعم regexp في Go الـ lookahead والـ lookbehind؟
لا. يستخدم regexp في Go صياغة RE2، التي لا تملك lookahead ولا lookbehind ولا مراجع خلفية. في المقابل تعمل المطابقة في وقت خطي بحجم المدخل، فلا يستطيع نمط أو مدخل عدائي تجميد برنامجك. استخدم مجموعات الالتقاط وقليلًا من شيفرة Go بدلًا من ذلك، أو قسّم الفحص إلى تعبيرين نمطيين.
ما الفرق بين regexp.Compile وregexp.MustCompile؟
تعيد Compile النمط المترجم وخطأ. أما MustCompile فتسبّب panic مع النمط غير الصالح بدلًا من ذلك. استخدم MustCompile للأنماط المكتوبة في شيفرتك المصدرية، وعادة في متغيّر على مستوى الحزمة، ليفشل خطأ الكتابة عند بدء التشغيل. واستخدم Compile للأنماط القادمة من المستخدمين أو ملفات الإعدادات.
كيف أحصل على مجموعات الالتقاط من تعبير نمطي في Go؟
استخدم FindStringSubmatch، التي تعيد شريحة الفهرس 0 فيها هو المطابقة كاملة والفهارس 1 و2 ... هي المجموعات، أو nil إذا لم توجد مطابقة. ولكل المطابقات استخدم FindAllStringSubmatch(s, -1). ويمكن البحث عن المجموعات المسمّاة (?P<year>\d{4}) بـ re.SubexpIndex("year").