المسارات
/
Go
Go
/
المنهج
/
التعبيرات النمطية
ال

التعبيرات النمطية في Go

1 تمرين

نبذة عن التعبيرات النمطية

توفّر الحزمة regexp دعمًا للتعبيرات النمطية في Go.

الصيغة

إن صيغة التعبيرات النمطية المقبولة هي نفس الصيغة العامة التي تستخدمها Perl وPython ولغات أخرى.

يُفسَّر كل من أنماط البحث والنصوص المُدخَلة على أنهما بترميز UTF-8.

عند استخدام علامات الاقتباس الخلفية (`) لإنشاء السلاسل النصية، لا يكون للشرطة المائلة العكسية (\) أي معنى خاص ولا تشير إلى بداية محارف خاصة مثل علامات الجدولة \t أو أسطر جديدة \n:

"\t\n" // regular string literal with 2 characters: a tab and a newline
`\t\n`// raw string literal with 4 characters: two backslashes, a 't', and an 'n'

لهذا السبب، من المستحسن استخدام علامات الاقتباس الخلفية لإنشاء التعبيرات النمطية، لأن ذلك يعني أننا لا نحتاج إلى تهريب الشرطات المائلة العكسية:

"\\" // string with a single backslash
`\\` // string with 2 backslashes

تصريف الأنماط - نوع RegExp

لاستخدام تعبير نمطي، يجب علينا أولًا تصريف النمط النصي. التصريف هنا يعني أخذ النمط النصي للتعبير النمطي وتحويله إلى تمثيل داخلي يسهُل التعامل معه. نحتاج إلى تصريف كل نمط مرة واحدة فقط، وبعد ذلك يمكننا استخدام النسخة المُصرّفة من التعبير النمطي مرات عديدة. يمثّل النوع regexp.Regexp تعبيرات نمطية مُصرّفة. يمكننا تصريف نمط نصي إلى regexp.Regexp باستخدام الدالة regexp.Compile. تُرجع هذه الدالة nil وخطأً إذا فشل التصريف:

re, err := regexp.Compile(`(a|b)+`)
fmt.Println(re, err) // => (a|b)+ <nil>
re, err = regexp.Compile(`a|b)+`)
fmt.Println(re, err) // => <nil> error parsing regexp: unexpected ): `a|b)+`

تُعدّ الدالة MustCompile بديلًا مريحًا عن Compile:

re = regexp.MustCompile(`[a-z]+\d*`)

باستخدام هذه الدالة، لا حاجة إلى معالجة خطأ.

Caution

يجب استخدام MustCompile فقط عندما نتأكد تمامًا أن النمط يُصرّف فعلًا، وإلا فسيتعطّل البرنامج.

طرق التعبيرات النمطية

هناك 16 طريقة في Regexp تُطابق تعبيرًا نمطيًا وتحدّد النص المطابق. تتطابق أسماؤها مع هذا التعبير النمطي:

Find(All)?(String)?(Submatch)?(Index)?
  • إذا كان All موجودًا، تُطابق الدالة المطابقات المتتالية غير المتداخلة للتعبيرات كاملة.
  • إذا كان String موجودًا، تكون الوسيطة سلسلة نصية؛ وإلا فهي شريحة من البايتات؛ وتُعدَّل القيم المُرجعة وفقًا لذلك.
  • إذا كان Submatch موجودًا، تكون القيمة المُرجعة شريحة تحدّد المطابقات الفرعية المتتالية للتعبير.
  • إذا كان Index موجودًا، تُحدَّد المطابقات والمطابقات الفرعية بأزواج فهارس البايتات داخل النص المُدخَل.

وهناك أيضًا طرق من أجل:

  • استبدال مطابقات التعبيرات النمطية بسلاسل نصية بديلة، و
  • تقسيم السلاسل النصية المفصولة بتعبيرات نمطية.

بشكل عام، تعرّف حزمة regexp أكثر من 40 دالة وطريقة. سنوضّح استخدام بعض الطرق فيما يلي. يُرجى الاطلاع على توثيق API لمعرفة تفاصيل هذه الدوال وغيرها.

أمثلة على MatchString

تُخبرنا الطريقة MatchString عمّا إذا كانت سلسلة نصية تحتوي على أي مطابقة لتعبير نمطي.

re = regexp.MustCompile(`[a-z]+\d*`)
b = re.MatchString("[a12]")       // => true
b = re.MatchString("12abc34(ef)") // => true
b = re.MatchString(" abc!")       // => true
b = re.MatchString("123 456")     // => false

أمثلة على FindString

تُرجع الطريقة FindString سلسلة نصية تحتوي على نص المطابقة الأكثر يسارًا للتعبير النمطي.

re = regexp.MustCompile(`[a-z]+\d*`)
s = re.FindString("[a12]")       // => "a12"
s = re.FindString("12abc34(ef)") // => "abc34"
s = re.FindString(" abc!")       // => "abc"
s = re.FindString("123 456")     // => ""

أمثلة على FindStringSubmatch

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

re = regexp.MustCompile(`[a-z]+(\d*)`)
sl = re.FindStringSubmatch("[a12]")       // => []string{"a12","12"}
sl = re.FindStringSubmatch("12abc34(ef)") // => []string{"abc34","34"}
sl = re.FindStringSubmatch(" abc!")       // => []string{"abc",""}
sl = re.FindStringSubmatch("123 456")     // => <nil>

أمثلة على ReplaceAllString

تُرجع الطريقة re.ReplaceAllString(src,repl) نسخة من src، مع استبدال مطابقات التعبير النمطي re بالسلسلة النصية البديلة repl.

re = regexp.MustCompile(`[a-z]+\d*`)
s = re.ReplaceAllString("[a12]", "X")       // => "[X]"
s = re.ReplaceAllString("12abc34(ef)", "X") // => "12X(X)"
s = re.ReplaceAllString(" abc!", "X")       // => " X!"
s = re.ReplaceAllString("123 456", "X")     // => "123 456"

أمثلة على Split

تُجزّئ الطريقة re.Split(s,n) نصًا s إلى سلاسل نصية فرعية مفصولة بالتعبير، وتُرجع شريحة من السلاسل النصية الفرعية الواقعة بين تلك المطابقات. يحدّد العدد n الحد الأقصى لعدد السلاسل النصية الفرعية المُرجعة. إذا كان n<0، تُرجع الطريقة كل السلاسل النصية الفرعية.

re = regexp.MustCompile(`[a-z]+\d*`)
sl = re.Split("[a12]", -1)      // => []string{"[","]"}
sl = re.Split("12abc34(ef)", 2) // => []string{"12","(ef)"}
sl = re.Split(" abc!", -1)      // => []string{" ","!"}
sl = re.Split("123 456", -1)    // => []string{"123 456"}

الأداء

يُضمن أن يعمل تطبيق regexp الذي توفّره هذه الحزمة في زمن خطي بحجم المُدخَل.

تحذير

تُطبّق الحزمة regexp التعبيرات النمطية RE2 (باستثناء \C). الصيغة متوافقة إلى حد كبير مع PCRE («تعبير نمطي متوافق مع Perl»)، لكن هناك بعض الاختلافات. يُرجى الاطلاع على «قسم التحذير» في هذا المقال لمعرفة التفاصيل.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة

تعلّم التعبيرات النمطية

التدريب مقفل

افتح تمرينين إضافيين لممارسة التعبيرات النمطية