Lecture 02 · Words and Tokens

المحاضرة 02 · الكلمات والرموز (Tokens)

Sentence Segmentation and Regex

تقسيم الجمل والتعابير النمطية (Regex)

Slides 53–77الشرائح 53–77 P1 MUST

Finding where sentences end, and then the pattern language that does almost all the dirty work in an NLP pipeline.

كيف نعرف أين تنتهي الجملة، ثم لغة الأنماط (regex) التي تؤدي معظم العمل الخشن في أي NLP pipeline.

How to study thisكيف تذاكر هذا

Twenty-five slides, but three of them are a cheat sheet you only need to recognize. The exam-relevant core is small: what each quantifier means, what ^ does in two different places, how alternation binds, and how capture groups work. Everything else is reference.

خمس وعشرون شريحة، لكن ثلاثاً منها مجرد ورقة مراجعة تحتاج أن تتعرف عليها فقط. واللب المطلوب في الامتحان صغير: معنى كل quantifier، وما يفعله ^ في موضعين مختلفين، وكيف يرتبط alternation، وكيف تعمل capture groups. وما عدا ذلك مرجع.

Part 1: Sentence segmentation

الجزء 1: تقسيم الجمل

Before you can parse a sentence or translate it, you have to know where it starts and stops. That is the whole task on slide 53: find the sentence boundaries.

قبل أن تُعرب جملة أو تترجمها، يجب أن تعرف أين تبدأ وأين تنتهي. وهذه هي كل المهمة في الشريحة 53: إيجاد sentence boundaries.

If every sentence ended in a period and every period ended a sentence, this would be one line of code. It is not, because the period is overloaded. The same character marks an abbreviation, a decimal point, an initial, and a URL.

لو كانت كل جملة تنتهي بنقطة وكل نقطة تنهي جملة، لكان الحل سطراً واحداً من الكود. لكنه ليس كذلك، لأن النقطة محمّلة بوظائف كثيرة: فهي نفسها تعلّم الاختصار، والفاصلة العشرية، والحرف الأول من الاسم، وURL.

Dr. Smith paid $4.50 at 10 a.m. He left.
      ^                    ^       ^
      |                    |       |
  abbreviation      abbreviation   actual sentence end

Only the last period is a boundary. Three of the four are not.

يعرض المربع الجملة Dr. Smith paid $4.50 at 10 a.m. He left. مع أسهم تشير إلى النقاط. نقطة Dr. اختصار، ونقطة $4.50 عشرية، ونقطة a.m. اختصار، والأخيرة وحدها نهاية جملة فعلية. أي أن ثلاثاً من الأربع ليست حدوداً.

So the real question on these slides is: given a period, is it sentence-final or not? That is a binary decision, and slide 54 gives two families of answers.

فالسؤال الحقيقي في هذه الشرائح: إذا رأيت نقطة، هل هي نهاية جملة أم لا؟ هذا قرار ثنائي، والشريحة 54 تعطي عائلتين من الأجوبة.

Rule-based heuristics

قواعد استدلالية (Rule-based heuristics)

  • punctuation plus capitalization patterns (a period followed by a space and a capital letter is a decent first guess)

    أنماط الترقيم مع الحروف الكبيرة: نقطة تتبعها مسافة ثم حرف كبير تخمين أولي جيد.

  • abbreviation lists (a lexicon of Dr., Inc., a.m. that you check before deciding)

    قوائم الاختصارات: معجم يحتوي Dr. وInc. وa.m. تراجعه قبل أن تقرر.

  • quote and bracket balancing (do not cut inside an unclosed quote)

    موازنة علامات التنصيص والأقواس: لا تقطع داخل تنصيص لم يُغلق بعد.

Statistical approaches

مناهج إحصائية

  • learn a boundary probability from annotated data

    احتمال وجود حدّ جملة يُتعلَّم من بيانات موسومة.

  • use context features, or a neural model, around each candidate period

    استخدام context features، أو نموذج عصبي، حول كل نقطة مرشّحة.

One line from slide 53 is easy to skip and easy to examine: segmentation is often done jointly with tokenization and with abbreviation lexicons. The two tasks feed each other. You cannot decide whether a.m. is one token without deciding whether that final period ends the sentence, and vice versa.

سطر في الشريحة 53 يسهل تجاوزه ويسهل السؤال عنه: التقطيع إلى جمل يُنجَز غالباً بالتوازي مع tokenization ومع معاجم الاختصارات. المهمتان تغذي كل منهما الأخرى: لا يمكنك أن تقرر هل a.m. رمز واحد دون أن تقرر هل نقطته تنهي الجملة، والعكس صحيح.

ELIZA, and why a dumb program felt alive

ELIZA، ولماذا بدا برنامج بسيط كأنه حي

Slide 55 shows ELIZA, Weizenbaum's 1966 program that imitated a Rogerian psychotherapist. It had no understanding of anything. It was essentially a stack of regular expressions that rewrote the user's sentence back at them as a question.

تعرض الشريحة 55 برنامج ELIZA الذي كتبه Weizenbaum عام 1966 ليحاكي معالجاً نفسياً من مدرسة Rogerian. لم يكن يفهم شيئاً إطلاقاً، بل كان في جوهره كومة من regular expressions تعيد كتابة جملة المستخدم وترجعها إليه على هيئة سؤال.

user:  I am feeling sad
rule:  s/.* I am (depressed|sad) .*/I AM SORRY TO HEAR YOU ARE \1/
ELIZA: I AM SORRY TO HEAR YOU ARE SAD

يبيّن المربع قاعدة واحدة من ELIZA: المستخدم يكتب I am feeling sad، والقاعدة s/.* I am (depressed|sad) .*/I AM SORRY TO HEAR YOU ARE \1/ تلتقط الكلمة التي داخل القوسين في group 1، ثم تُدرجها مكان \1 في الرد، فيخرج I AM SORRY TO HEAR YOU ARE SAD. لا فهم، مجرد استبدال نمط.

People still formed emotional attachments to it. The slide names this:

ومع ذلك تعلّق به الناس عاطفياً. والشريحة تسمّي هذه الظاهرة:

Definitionتعريف

Eliza effect: the tendency to unconsciously assume computer behaviors are analogous to human behaviors.

Eliza effect: الميل اللاواعي إلى افتراض أن سلوك الحاسوب مشابه للسلوك البشري.

The reason this sits here, right before the regex block, is the point of the story: pattern substitution alone is enough to produce surprisingly convincing text. That is both an argument for how powerful regex is and a warning about reading understanding into surface behavior.

وسبب وجود هذه القصة هنا، قبل قسم regex مباشرة، هو مغزاها: الاستبدال بالأنماط وحده كافٍ لإنتاج نص مقنع بدرجة مفاجئة. وهذا في الوقت نفسه حجة على قوة regex، وتحذير من قراءة الفهم في سلوك سطحي.

Part 2: Why regex in NLP

الجزء 2: لماذا الـ regex في NLP

Slide 56 lists what regex is actually used for. It is not a toy, it is the first and last stage of most real pipelines.

تسرد الشريحة 56 ما يُستخدم regex فيه فعلياً. ليس لعبة، بل هو المرحلة الأولى والأخيرة في معظم المسارات الحقيقية.

And the caveat the slide ends on: regex is language- and task-dependent. A pattern tuned for English whitespace will break on Chinese, which has none. A pattern for tweets will break on legal documents.

والتحذير الذي تنتهي به الشريحة: regex يعتمد على اللغة وعلى المهمة. نمط مضبوط على المسافات في الإنجليزية ينكسر على الصينية التي لا مسافات فيها، ونمط للتغريدات ينكسر على الوثائق القانونية.

The four building blocks

لبنات البناء الأربع

Slide 57 gives the whole grammar of regex in four lines. Everything else on this page is sugar on top of these.

تعطي الشريحة 57 كل قواعد regex في أربعة أسطر. وكل ما بعدها في هذه الصفحة تحلية فوق هذه الأربعة.

BlockاللبنةWhat it doesماذا تفعلExampleمثال
Literalالحرف الحرفي (Literal)a character matches itselfالحرف يطابق نفسهa matches 'a'a يطابق 'a'
Concatenationالتسلسل (Concatenation)patterns side by side must occur in orderالأنماط المتجاورة يجب أن تظهر بالترتيبabc matches 'abc'abc يطابق 'abc'
Disjunctionالاختيار (Disjunction)either one or the otherإما هذا أو ذاكa|b matches 'a' or 'b'a|b يطابق 'a' أو 'b'
Groupingالتجميع (Grouping)parentheses define scopeالأقواس تحدد النطاق(ab)c

يسرد الجدول البنى الأربع. Literal: الحرف يطابق نفسه، فـ a يطابق a. وConcatenation: أنماط متجاورة يجب أن تظهر بالترتيب، فـ abc يطابق abc. وDisjunction: أحدهما أو الآخر، فـ a|b يطابق a أو b. وGrouping: الأقواس تحدد النطاق، كما في (ab)c.

Character classes: the square brackets

أصناف الحروف: الأقواس المربعة

Writing a|b|c|d gets old fast. Square brackets are a compact disjunction over single characters. Slides 58, 59 and 60 are three tables covering three uses of them.

كتابة a|b|c|d تصبح مملة بسرعة. والأقواس المربعة [ ] اختصار لـ disjunction على حروف مفردة. والشرائح 58 و59 و60 ثلاثة جداول تغطي ثلاثة استخدامات لها.

Plain disjunction, slide 58

الاختيار البسيط، الشريحة 58

PatternالنمطMatchesيطابقIn this stringفي هذه السلسلة
[mM]aryMary or maryMary أو mary"Mary Ann stopped by Mona's"
[abc]'a', 'b', or 'c''a' أو 'b' أو 'c'"In uomini, in soldati"
[1234567890]any one digitأي رقم واحد"plenty of 7 to 5"

يعرض جدول الشريحة 58 ثلاثة أنماط. [mM]ary يطابق Mary أو mary. و[abc] يطابق أي واحد من a أو b أو c. و[1234567890] يطابق أي رقم واحد. والقاعدة: ما داخل الأقواس المربعة يطابق حرفاً واحداً فقط، لا السلسلة كلها.

Note what the first row buys you: [mM]ary is case-insensitive only on the first letter. That is a much tighter pattern than turning on a global case-insensitive flag.

لاحظ ما يمنحك إياه السطر الأول: [mM]ary لا يبالي بحالة الحرف في الحرف الأول وحده، وهذا نمط أضيق بكثير من تشغيل علم تجاهل الحالة على النمط كله.

Ranges with a dash, slide 59

النطاقات بالشرطة، الشريحة 59

Inside brackets, a dash between two characters means "everything from here to there in the character ordering".

داخل الأقواس المربعة، الشرطة بين حرفين تعني "كل شيء من هنا إلى هناك في ترتيب الحروف".

PatternالنمطMatchesيطابقIn this stringفي هذه السلسلة
[A-Z]an upper case letterحرف كبير"we should call it 'Drenched Blossoms'"
[a-z]a lower case letterحرف صغير"my beans were impatient to be hoed!"
[0-9]a single digitرقم واحد"Chapter 1: Down the Rabbit Hole"

يعرض جدول الشريحة 59 ثلاثة مدًى: [A-Z] حرف كبير واحد، و[a-z] حرف صغير واحد، و[0-9] رقم واحد. وكلها تطابق حرفاً واحداً، والشرطة هي التي تولّد المدى.

The caret, slide 60

علامة الإقحام (^)، الشريحة 60

This slide is the single most examinable thing in the regex block, because the caret means two completely different things depending on where it sits.

هذه الشريحة أكثر ما يُسأل عنه في قسم regex كله، لأن ^ يعني شيئين مختلفين تماماً بحسب موقعه.

PatternالنمطMatches (single characters)يطابق (حروفاً مفردة)In this stringفي هذه السلسلة
[^A-Z]NOT an upper case letterليس حرفاً كبيراً"Oyfn pripetchik"
[^Ss]neither 'S' nor 's'لا 'S' ولا 's'"I have no exquisite reason for't"
[^.]not a periodليس نقطة"our resident Djinn"
[e^]either 'e' or '^'إما 'e' أو '^'"look up ^ now"
a^bthe literal pattern 'a^b'النمط الحرفي 'a^b'"look up a^b now"

جدول الشريحة 60 في خمسة أسطر، والعمود الأول هو مفتاح الفهم. [^A-Z] يعني حرفاً ليس كبيراً. و[^Ss] يعني حرفاً ليس S ولا s. و[^.] يعني حرفاً ليس نقطة. أما [e^] فيطابق إما e وإما ^ نفسها، لأن ^ هنا ليست أول حرف داخل القوسين. وa^b نمط حرفي يطابق النص a^b.

The last two rows are the trick. A caret negates only when it is the very first character inside the brackets. Anywhere else, including outside brackets in the middle of a pattern, it is either a literal caret or a line anchor.

السطران الأخيران هما الفخ. ^ ينفي فقط إذا كان أول حرف داخل الأقواس المربعة. وفي أي موضع آخر، بما في ذلك خارج الأقواس في وسط النمط، هو إما ^ حرفية وإما line anchor.

Memory hookخطاف للذاكرة

First inside the brackets, the caret bites. Anywhere else, it anchors or it is just a hat.

أول حرف داخل الأقواس المربعة يعضّ، أي ينفي. وفي أي موضع آخر يرسو كـ anchor أو يكون مجرد قبّعة.

Three faces of ^, in one line each:

ثلاثة وجوه لـ ^، كل وجه في سطر:

Aliases: the shorthand classes, slide 64

الأسماء المستعارة: الأصناف المختصرة، الشريحة 64

Some classes are so common they get a one-character name. Memorize this table. It is the one that shows up inside every real-world pattern.

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

Aliasالاسم المستعارExpands toيتوسع إلىMatchesيطابقFirst match inأول تطابق في
\d[0-9]any digitأي رقمParty of 5
\D[^0-9]any non-digitأي شيء ليس رقماًBlue moon
\w[a-zA-Z0-9_]any alphanumeric or underscoreأي حرف أو رقم أو شرطة سفليةDaiyu
\W[^\w]a non-alphanumericما ليس حرفاً أو رقماً!!!!
\s[ \r\t\n\f]whitespace (space, tab)مسافة بيضاء (مسافة، tab)in Concord
\S[^\s]non-whitespaceما ليس مسافة بيضاءin Concord

جدول الشريحة 64 يربط كل اختصار بما يتوسّع إليه. \d هو [0-9] أي أي رقم، و\D هو [^0-9] أي أي شيء غير رقم. و\w هو [a-zA-Z0-9_] أي حرف أو رقم أو شرطة سفلية، و\W هو [^\w] أي نقيضه. و\s هو [ \r\t\n\f] أي مسافة بيضاء، و\S هو [^\s] أي غير مسافة. اقرأ العمود الثاني وستحفظ الجدول كله.

The pattern is completely regular: lowercase is the class, uppercase is its complement. \d and \D partition every character between them, and so do \w/\W and \s/\S.

النمط منتظم تماماً: الحرف الصغير هو الصنف، والكبير هو مُكمّله. فـ \d و\D يقسمان كل الحروف بينهما، وكذلك \w و\W، وكذلك \s و\S.

Note that \w includes the underscore and the digits, not just letters. That surprises people. \w+ on user_id_42 matches the whole thing as one token.

ولاحظ أن \w يشمل الشرطة السفلية والأرقام، لا الحروف وحدها، وهذا يفاجئ الناس. فـ \w+ على user_id_42 يطابقها كلها كرمز واحد.

Quantifiers: how many times, slides 61 and 62

المكمِّمات (Quantifiers): كم مرة، الشريحتان 61 و62

A quantifier says how many copies of the thing before it you want. This is the second heavily examined area.

الـ quantifier يحدد كم نسخة تريد من الشيء الذي قبله. وهذه ثاني أكثر منطقة يُسأل عنها.

QuantifierالمكمِّمMeansالمعنىCan it match nothing?هل يمكن أن يطابق لا شيء؟Exampleمثال
*zero or more of the previous char or expressionصفر أو أكثر من الحرف أو التعبير السابقyesنعمab* matches 'a', 'ab', 'abbb'ab* يطابق 'a', 'ab', 'abbb'
+one or more of the previous char or expressionواحد أو أكثر من الحرف أو التعبير السابقnoلاab+ matches 'ab', 'abbb', not 'a'ab+ يطابق 'ab', 'abbb'، لا 'a'
?zero or one, that is, optionalصفر أو واحد، أي اختياريyesنعمcolou?r matches 'color' and 'colour'colou?r يطابق 'color' و'colour'
{n}exactly n occurrencesn ظهوراً بالضبطno (unless n = 0)لا (إلا إذا n = 0)\d{4} matches '2026'\d{4} يطابق '2026'
{m,n}between m and n timesبين m وn مرةonly if m = 0فقط إذا m = 0\d{2,4} matches '26', '202', '2026'\d{2,4} يطابق '26', '202', '2026'
.any single characterأي حرف واحدnoلاa.c matches 'abc', 'a7c', 'a c'a.c يطابق 'abc', 'a7c', 'a c'
.*any string of zero or more charsأي سلسلة من صفر حرف أو أكثرyesنعمa.*b matches 'a' then anything then 'b'a.*b يطابق 'a' ثم أي شيء ثم 'b'
*?lazy: as few as possible, stop at the first matchكسول (lazy): أقل ما يمكن، ويتوقف عند أول تطابقyesنعم<.*?> stops at the first ><.*?> يتوقف عند أول >

يسرد جدول الشرائح 61 و62 الـ quantifiers، والعمود الثالث (هل يمكن أن يطابق لا شيء؟) هو موضع السؤال. * صفر أو أكثر، ويمكنه أن يطابق لا شيء، فـ ab* يطابق a وab وabbb. و+ واحد أو أكثر، ولا يمكنه، فـ ab+ لا يطابق a وحدها. و? صفر أو واحد أي اختياري، فـ colou?r يطابق color وcolour. و{n} عدد مضبوط، فـ \d{4} يطابق 2026. و{m,n} بين m وn مرة، فـ \d{2,4} يطابق 26 و202 و2026. و. أي حرف واحد. و.* أي سلسلة بطول صفر أو أكثر. و*? هو lazy أي أقل قدر ممكن، فـ <.*?> يتوقف عند أول >.

The comparison that gets tested: * versus + versus ?

المقارنة التي يُختبر عليها: * مقابل + مقابل ?

All three are quantifiers, so people blur them. The real difference is just the two numbers, the floor and the ceiling.

الثلاثة كلها quantifiers، فيخلط الناس بينها. والفرق الحقيقي رقمان فقط: الحد الأدنى والحد الأعلى.

QuantifierالمكمِّمMinimumالحد الأدنىMaximumالحد الأقصىEquivalent toيكافئ
*0∞{0,}
+1∞{1,}
?01{0,1}

يختصر الجدول الفرق في رقمين. *: الأدنى 0 والأعلى لا نهائي، أي يكافئ {0,}. و+: الأدنى 1 والأعلى لا نهائي، أي {1,}. و?: الأدنى 0 والأعلى 1، أي {0,1}. عمود الحد الأدنى وحده يفصل بينها.

The consequence that matters: a pattern containing * or ? can succeed without consuming anything. That is why [0-9]* "matches" an empty string and a search for it will happily return a zero-length match at position 0. If you want at least one digit, you must write [0-9]+.

والنتيجة التي تهم: النمط الذي يحتوي * أو ? يمكن أن ينجح دون أن يستهلك أي حرف. ولهذا فإن [0-9]* "يطابق" سلسلة فارغة، والبحث به سيعيد بلا تردد مطابقة بطول صفر عند الموضع 0. وإذا أردت رقماً واحداً على الأقل فاكتب [0-9]+.

Memory hookخطاف للذاكرة

Star can skip. Plus must have one. Question mark is at most one.

النجمة * تستطيع التخطي. و+ لا بد له من واحد. و? واحد على الأكثر.

And for laziness: add a question mark to a quantifier and it becomes shy. * grabs everything it can; *? grabs the least it can get away with.

وأما الـ laziness: أضف علامة استفهام إلى أي quantifier فيصبح خجولاً. فـ * يلتقط كل ما يستطيع، و*? يلتقط أقل ما يمكنه النجاة به.

Greedy versus lazy, seen on a real string

الجشع (Greedy) مقابل الكسول (lazy)، على سلسلة حقيقية

Slide 62 names this distinction (.* versus .*?) and slide 71 gives the string that makes it obvious. Both quantifiers find a valid match. They find different valid matches.

تسمّي الشريحة 62 هذا الفرق (.* مقابل .*?)، والشريحة 71 تعطي السلسلة التي تجعله واضحاً. كلا الـ quantifier يجد مطابقة صحيحة، لكنهما يجدان مطابقتين مختلفتين.

input string < B e g i n > H e l l o W o r l d < \ E n d > greedy <.*> takes everything to the LAST > , one match of 26 characters lazy <.*?> stops at the FIRST > , so with a global flag you get two separate tag matches same pattern shape, same input, two different answers
Greedy .* swallows the text between the tags and returns one giant match. Lazy .*? returns each tag separately. Neither is wrong; they answer different questions.
النمط الجشع .* يبتلع النص بين الوسوم ويعيد تطابقاً واحداً ضخماً. والنمط الكسول .*? يعيد كل وسم على حدة. ليس أي منهما خاطئاً؛ إنهما يجيبان عن سؤالين مختلفين.

يرسم الشكل السلسلة <Begin> Hello World <\End> ثم يقارن مطابقتين. الشريط العلوي greedy للنمط <.*> يمتد على السلسلة كلها، لأنه يأخذ كل شيء حتى آخر >، فتكون مطابقة واحدة بطول 26 حرفاً. والشريطان السفليان lazy للنمط <.*?> يغطيان الوسم الأول والوسم الأخير فقط، لأنه يتوقف عند أول >، فتحصل مع علم g على مطابقتين منفصلتين. نفس شكل النمط ونفس الدخل، وجوابان مختلفان.

Workedمثال محلول

Trace both patterns against the slide 71 string, character by character.

تتبّع النمطين على سلسلة الشريحة 71 حرفاً حرفاً.

input:  <Begin> Hello World <\End>
        0123456789...                 (26 characters, last index 25)

PATTERN A:  <.*>        (greedy)
  step 1  '<' must match a literal '<'     -> matches at index 0
  step 2  '.*' is greedy, so it first takes EVERYTHING
          from index 1 to index 25
  step 3  now '>' has nothing left to match -> FAIL
  step 4  backtrack: give one character back. '.*' now ends at 24,
          next char is index 25 which is '>'  -> MATCH
  result  <Begin> Hello World <\End>        the entire string

PATTERN B:  <.*?>       (lazy)
  step 1  '<' matches at index 0
  step 2  '.*?' is lazy, so it first takes NOTHING
  step 3  '>' must match index 1, which is 'B'  -> fail,
          so '.*?' grudgingly takes one more character
  step 4  repeat until '.*?' holds "Begin" (indices 1-5)
          and index 6 is '>'                     -> MATCH
  result  <Begin>                               7 characters

PATTERN C:  <[^>]*>     (negated class, no backtracking needed)
  '[^>]*' literally cannot cross a '>', so it stops on its own.
  result  <Begin>       same answer as lazy, but faster

يتتبّع المربع ثلاثة أنماط على الدخل <Begin> Hello World <\End> وطوله 26 حرفاً وآخر فهرس فيه 25. النمط A هو <.*> وهو greedy: يطابق < عند الفهرس 0، ثم يأخذ .* كل شيء حتى 25، فلا يبقى شيء لـ > فيفشل، فيتراجع (backtrack) حرفاً واحداً فيطابق، والنتيجة السلسلة كاملة. والنمط B هو <.*?> وهو lazy: يبدأ .*? بلا شيء ثم يأخذ حرفاً حرفاً على مضض حتى يمسك Begin، فيطابق > عند الفهرس 6، والنتيجة <Begin> بسبعة أحرف. والنمط C هو <[^>]*>: الصنف [^>]* لا يستطيع عبور > أصلاً فيتوقف من نفسه، ويعطي نفس جواب lazy لكن أسرع ودون تراجع.

Pattern C is how experienced people write it. The negated character class makes the "stop here" rule part of the pattern instead of relying on backtracking, which is also the fix for the catastrophic-backtracking warning on slide 77.

النمط C هو ما يكتبه أصحاب الخبرة. فصنف الحروف المنفي يجعل قاعدة "توقف هنا" جزءاً من النمط نفسه بدل الاعتماد على backtracking، وهو أيضاً الحل لتحذير catastrophic backtracking في الشريحة 77.

Anchors, slide 63

المراسي (Anchors)، الشريحة 63

Anchors match a position, not a character. They consume nothing. That is the key idea: an anchor is an assertion about where you are.

الـ anchors تطابق موضعاً لا حرفاً، ولا تستهلك شيئاً. وهذه هي الفكرة المفتاحية: الـ anchor تأكيد على موقعك، لا على محتوى.

AnchorالمرساةAssertsماذا تؤكدConsumes characters?هل تستهلك حروفاً؟
^start of a line or stringبداية سطر أو سلسلةnoلا
$end of a line or stringنهاية سطر أو سلسلةnoلا
\ba word boundary, the seam between a word char and a non-word charحد كلمة، أي الفاصل بين حرف من حروف الكلمة وحرف ليس منهاnoلا
\Bnot a word boundaryليس حد كلمةnoلا

جدول الشريحة 63 أربعة anchors، والعمود الأخير "هل يستهلك حروفاً؟" جوابه no في الأربعة كلها، وهذا بيت القصيد. ^ يؤكد بداية سطر أو سلسلة، و$ يؤكد نهايتها، و\b يؤكد حدّ كلمة أي الخيط الفاصل بين حرف كلمة وحرف غير كلمة، و\B يؤكد عدم وجود حدّ كلمة.

The slide says these are useful for matching whole words and line-based formats. Here is why \b is needed so often:

تقول الشريحة إنها مفيدة في مطابقة الكلمات الكاملة والصيغ المبنية على الأسطر. وهذا سبب الحاجة الدائمة إلى \b:

text:    the theme of the theater

pattern  the        -> matches inside "theme" and "theater" too, 4 matches
pattern  \bthe\b    -> matches only the standalone word "the",  2 matches

يقارن المربع نمطين على النص the theme of the theater. النمط the يطابق داخل theme وtheater أيضاً، فيعطي 4 مطابقات. أما \bthe\b فيطابق الكلمة المستقلة the فقط، فيعطي مطابقتين.

And from the cheat sheet on slide 73: ^ and $ are line anchors. With the multiline flag m turned on, they apply per line rather than once per whole string.

ومن ورقة المراجعة في الشريحة 73: ^ و$ هما line anchors، أي مرساتا سطر. وبتشغيل علم multiline أي m يعملان عند كل سطر بدل مرة واحدة على السلسلة كلها.

Escaping, slides 65 and 66

الهروب (Escaping)، الشريحتان 65 و66

A metacharacter is a character regex has given a job to. If you want the character itself instead of its job, put a backslash in front of it.

الـ metacharacter حرف أعطاه regex وظيفة. وإذا أردت الحرف نفسه بدل وظيفته، فضع شرطة مائلة خلفية قبله.

Slide 65 lists the ones that need escaping:

تسرد الشريحة 65 الحروف التي تحتاج escaping:

.   ^   $   *   +   ?   (   )   [   ]   {   }   |   \

يسرد الصندوق الـ metacharacters التي تحتاج شرطة مائلة خلفية قبلها: . و^ و$ و* و+ و? و( و) و[ و] و{ و} و|، والمظلّل في آخرها هو \ نفسها.

EscapeالهروبMatchesيطابقFirst match inأول تطابق في
\*an asterisk "*"نجمة "*""K*A*P*L*A*N"
\.a period "."نقطة ".""Dr. Livingston, I presume"
\?a question markعلامة استفهام"Why don't they come and lend a hand?"
\na newlineسطر جديد
\ta tabمسافة tab
\\a literal backslashشرطة مائلة عكسية حرفية

يعرض الجدول أمثلة escaping: \* يطابق نجمة *، و\. يطابق نقطة .، و\? يطابق علامة استفهام. والسطور الثلاثة الأخيرة من النوع الآخر: \n سطر جديد، و\t مسافة tab، و\\ شرطة مائلة خلفية حرفية.

Notice the two different jobs a backslash does. In \. it removes special meaning from a metacharacter. In \n and \d it adds special meaning to an ordinary letter. Same symbol, opposite directions.

لاحظ وظيفتي الشرطة المائلة الخلفية المختلفتين. في \. هي تُزيل المعنى الخاص من metacharacter. وفي \n و\d هي تُضيف معنى خاصاً إلى حرف عادي. نفس الرمز، واتجاهان متعاكسان.

Trapفخ

An unescaped . matches almost anything. If you write a pattern for a filename as file.txt it will happily match fileXtxt and file9txt. You wanted file\.txt.

النقطة . غير المهروبة تطابق كل شيء تقريباً. فإذا كتبت نمط اسم ملف هكذا file.txt فسيطابق fileXtxt وfile9txt بلا مشكلة. والذي أردته هو file\.txt.

The related half of this trap, stated explicitly on slide 62: . does not match a newline by default in many regex flavors. So a.*b will not reach across a line break unless you turn on the dot-all flag. People write a .* expecting it to swallow a multi-line block and then spend an hour confused.

والنصف الآخر من الفخ، وتنص عليه الشريحة 62 صراحة: . لا يطابق سطراً جديداً تلقائياً في كثير من إصدارات regex. فـ a.*b لن يعبر فاصل الأسطر إلا إذا شغّلت علم dot-all. الناس يكتبون .* متوقعين أن يبتلع كتلة متعددة الأسطر، ثم يقضون ساعة في حيرة.

Precedence: why alternation needs parentheses, slide 67

الأسبقية: لماذا يحتاج الاختيار (alternation) إلى أقواس، الشريحة 67

This is the trap that catches the most people, because the broken pattern looks correct.

هذا هو الفخ الذي يسقط فيه أكبر عدد، لأن النمط الخاطئ يبدو صحيحاً.

Slide 67's rule: alternation | has low precedence. Lower than concatenation, lower than any quantifier. So the bar splits the largest possible expressions around it.

قاعدة الشريحة 67: الـ alternation أي | له أسبقية منخفضة. أقل من concatenation، وأقل من أي quantifier. فالشرطة العمودية تقسم أكبر تعبيرين ممكنين حولها.

you write        cat|dogs
regex reads      (cat) | (dogs)
you probably     cat, or dog, followed by an optional s
wanted

correct          (cat|dog)s     -> "cats" or "dogs"
                 cats|dogs      -> also fine, just verbose

يقارن المربع ما تكتبه بما يقرأه المحرك. تكتب cat|dogs، فيقرأه regex هكذا (cat) | (dogs)، أما ما أردته فهو cat أو dog متبوعة بـ s اختيارية. والصحيح (cat|dog)s ليطابق cats أو dogs، أو cats|dogs وهو سليم أيضاً لكنه أطول.

The same low precedence makes anchors behave surprisingly:

ونفس الأسبقية المنخفضة تجعل الـ anchors تتصرف بشكل مفاجئ:

you write        ^cat|dog$
regex reads      (^cat) | (dog$)
means            "starts with cat" OR "ends with dog"
you wanted       ^(cat|dog)$     "the whole line is cat or dog"

تكتب ^cat|dog$، فيقرأه المحرك (^cat) | (dog$)، أي "يبدأ بـ cat" أو "ينتهي بـ dog". وما أردته هو ^(cat|dog)$، أي "السطر كله cat أو dog".

Slide 67 also introduces the non-capturing group (?:...). It groups for precedence purposes but does not store what it matched, so it does not consume a capture-group number. Use it whenever you need parentheses purely for scope.

وتقدّم الشريحة 67 أيضاً الـ non-capturing group وصيغته (?:...). يجمّع لأجل الأسبقية لكنه لا يحفظ ما طابقه، فلا يستهلك رقم capture group. استخدمه كلما احتجت الأقواس للنطاق فقط.

Trapفخ

A quantifier applies only to the single element immediately before it, not to the whole run of characters you just typed.

الـ quantifier يُطبَّق على العنصر الواحد الذي يسبقه مباشرة، لا على كل سلسلة الحروف التي كتبتها قبله.

ab+     means  a, then one or more b      ->  'ab', 'abbb'
                NOT one or more 'ab'
(ab)+   means  one or more 'ab'           ->  'ab', 'ababab'

\d{3}   means  exactly three digits
a\d{3}  means  'a' then exactly three digits, not 'a\d' three times

يعرض المربع أربع حالات. ab+ يعني a ثم b واحدة أو أكثر، فيطابق ab وabbb، ولا يعني ab واحدة أو أكثر. أما (ab)+ فيعني ab واحدة أو أكثر، فيطابق ab وababab. و\d{3} يعني ثلاثة أرقام بالضبط. وa\d{3} يعني a ثم ثلاثة أرقام بالضبط، لا a\d ثلاث مرات.

Same story with escapes: in \d{4} the "single element" is the whole alias \d, since the backslash and the letter are one unit. But in abc* the single element is just c.

ونفس القصة مع الـ escapes: في \d{4} يكون "العنصر الواحد" هو الاختصار كله \d، لأن الشرطة المائلة والحرف وحدة واحدة. لكن في abc* يكون العنصر الواحد هو c وحدها.

Composing a real pattern, slide 68

تركيب نمط حقيقي، الشريحة 68

Slide 68's advice is process advice: design patterns by composing smaller parts, then build and test iteratively, and avoid overfitting to the examples in front of you.

نصيحة الشريحة 68 نصيحة منهجية: صمّم الأنماط بتركيب أجزاء أصغر، ثم ابنِ واختبر على دفعات، وتجنّب الإفراط في ملاءمة الأمثلة التي بين يديك.

Its example is a deliberately simplified email matcher:

ومثالها مُطابق بريد إلكتروني مبسّط بشكل متعمد:

[A-Za-z0-9._]+ @ [A-Za-z0-9._]+

يعرض الصندوق النمط [A-Za-z0-9._]+@[A-Za-z0-9._]+: صنف حروف الجزء المحلي مع +، ثم علامة @ المظلّلة كحرف حرفي، ثم نفس الصنف مع + مرة أخرى.

Read it in three chunks: one or more characters from the local-part alphabet, then a literal at-sign, then one or more characters from the same alphabet. The + on both sides is doing the real work, because it is what forces at least one character on each side of the @.

اقرأه في ثلاث كتل: حرف أو أكثر من أبجدية الجزء المحلي، ثم علامة @ حرفية، ثم حرف أو أكثر من الأبجدية نفسها. والـ + على الجانبين هو الذي يؤدي العمل الحقيقي، لأنه ما يفرض وجود حرف واحد على الأقل على كل جانب من @.

Workedمثال محلول

Run the slide's email pattern on real text and watch it half-fail. This is what "avoid overfitting" means in practice.

شغّل نمط البريد الذي في الشريحة على نص حقيقي وراقبه يفشل نصف فشل. هذا هو معنى "تجنّب الإفراط في الملاءمة" عملياً.

pattern:  [A-Za-z0-9._]+@[A-Za-z0-9._]+
input:    Contact majid.raimi@kfupm.edu.sa or ali-k@x.com today

MATCH 1
  scan from the left. At 'm' of "majid":
    [A-Za-z0-9._]+  consumes  majid.raimi      (the dot IS in the class)
    @               consumes  @
    [A-Za-z0-9._]+  consumes  kfupm.edu.sa     (stops at the space)
  result:  majid.raimi@kfupm.edu.sa             CORRECT

MATCH 2
  At 'a' of "ali-k":
    [A-Za-z0-9._]+  consumes  ali              (stops: '-' is NOT in the class)
    @               needs '@' but sees '-'     -> fail, advance start
  At 'l': same failure.   At 'i': same failure.
  At '-': '-' is not in the class at all       -> fail immediately
  At 'k':
    [A-Za-z0-9._]+  consumes  k
    @               consumes  @
    [A-Za-z0-9._]+  consumes  x.com
  result:  k@x.com                              TRUNCATED, lost "ali-"

FIX:  add the hyphen to the class, at the END so it is not read as a range
      [A-Za-z0-9._-]+@[A-Za-z0-9._-]+
      now match 2 is  ali-k@x.com

يشغّل المربع النمط [A-Za-z0-9._]+@[A-Za-z0-9._]+ على الدخل Contact majid.raimi@kfupm.edu.sa or ali-k@x.com today. المطابقة الأولى تنجح تماماً وتعطي majid.raimi@kfupm.edu.sa، لأن النقطة داخل الصنف. والمطابقة الثانية تفشل عند ali لأن الشرطة - ليست في الصنف، فيزحف المحرك ببداية البحث إلى الأمام حتى يبدأ عند k، فيعطي k@x.com مبتورة وقد ضاعت ali-. والحل: أضف الشرطة إلى الصنف في آخره حتى لا تُقرأ كمدى، فيصبح [A-Za-z0-9._-]+@[A-Za-z0-9._-]+، وتصبح المطابقة الثانية ali-k@x.com.

Two lessons here. First, the engine never gives up on the whole string after a failure; it slides the start position forward and tries again, which is exactly how you get a silently truncated match instead of a clean no-match. Second, a hyphen inside [ ] must go first or last, otherwise it is read as a range.

درسان هنا. الأول أن المحرك لا يستسلم عن السلسلة كلها بعد الفشل، بل يزحف بموضع البداية إلى الأمام ويحاول مرة أخرى، وهذا بالضبط كيف تحصل على مطابقة مبتورة بصمت بدل عدم مطابقة نظيف. والثاني أن الشرطة - داخل [ ] يجب أن تكون أولاً أو آخراً، وإلا قُرئت كمدى.

Substitution and capture groups, slide 69

الاستبدال ومجموعات الالتقاط (capture groups)، الشريحة 69

So far we have been finding text. Substitution is finding text and then rewriting it, which is where the parentheses stop being about precedence and start being about memory.

كنا حتى الآن نبحث عن نص. أما الـ substitution فهو أن تجد النص ثم تعيد كتابته، وهنا تتحول الأقواس من أداة أسبقية إلى أداة ذاكرة.

A capture group stores whatever it matched, numbered left to right by opening parenthesis, and you refer back to it in the replacement.

الـ capture group يحفظ ما طابقه، وتُرقّم الـ groups من اليسار إلى اليمين بحسب قوس الفتح، ثم تشير إليها في نص الاستبدال.

Slide 69's example reorders a date:

مثال الشريحة 69 يعيد ترتيب تاريخ:

s/(\d{4})-(\d{2})-(\d{2})/$2$3$1/

يعرض الصندوق الاستبدال s/(\d{4})-(\d{2})-(\d{2})/$2$3$1/: الجزء المظلّل هو النمط بثلاث groups، أربعة أرقام ثم رقمان ثم رقمان، تفصل بينها شرطتان حرفيتان، والجزء الأخير هو الاستبدال الذي يعيد ترتيبها.

pattern (\d{4}) - (\d{2}) - (\d{2}) group 1 group 2 group 3 exactly 4 digits, the year, stored as $1 exactly 2 digits, stored as $2 exactly 2 digits, stored as $3 the two bare hyphens are literals, not captured input 2026 - 25 - 01 output 25 / 01 / 2026 replacement: $2/$3/$1
Groups are numbered by the order of their opening parenthesis, left to right. The replacement string reorders them freely. This is the slide 71 exercise "convert 2026-25-01 to 25/01/2026".
تُرقَّم المجموعات حسب ترتيب قوس الفتح فيها، من اليسار إلى اليمين. وسلسلة الاستبدال تعيد ترتيبها بحرية. وهذا تمرين الشريحة 71: "حوّل 2026-25-01 إلى 25/01/2026".

يفكّك الرسم نمط التاريخ إلى ثلاث capture groups ملوّنة: (\d{4}) هي group 1 أي السنة وتُحفظ في $1، و(\d{2}) الأولى هي group 2 وتُحفظ في $2، و(\d{2}) الثانية هي group 3 وتُحفظ في $3، والشرطتان المجرّدتان حرفيتان ولا تُحفظان. وفي الأسفل يأخذ الرسم الدخل 2026-25-01 وتتقاطع الأسهم لتعطي الخرج 25/01/2026 حسب الاستبدال $2/$3/$1.

The cheat sheet on slide 73 adds two more group flavors. All three are worth knowing apart:

وتضيف ورقة المراجعة في الشريحة 73 نوعين آخرين من الـ groups. والثلاثة كلها تستحق أن تفرّق بينها:

SyntaxالصياغةGroups for precedence?تجمّع للأسبقية؟Stores the match?تخزّن التطابق؟Use whenاستخدمها عندما
(...)yesنعمyes, as $1, $2, ...نعم، في صورة $1, $2, ...you need the text backتحتاج النص مرة أخرى
(?:...)yesنعمnoلاyou only need the parentheses for scopeتحتاج الأقواس للنطاق فقط
(?<name>...)yesنعمyes, by nameنعم، بالاسمmany groups and numbers get confusingالمجموعات كثيرة والأرقام تصبح مربكة

يقارن الجدول ثلاث صيغ. (...) يجمّع للأسبقية ويحفظ ما طابقه كـ $1 و$2، فاستخدمه حين تحتاج النص مرة أخرى. و(?:...) يجمّع ولا يحفظ، فاستخدمه حين تحتاج الأقواس للنطاق فقط. و(?<name>...) يجمّع ويحفظ بالاسم، فاستخدمه حين تكثر الـ groups وتختلط الأرقام.

Lookaround, slide 70 and the cheat sheet

النظر حول الموضع (Lookaround)، الشريحة 70 وورقة المراجعة

A lookahead is a condition about what comes next that does not become part of the match. That last clause is the whole point and the whole exam question.

الـ lookahead شرط على ما يأتي بعدك لا يصبح جزءاً من المطابقة. وهذه الجملة الأخيرة هي كل المغزى وكل سؤال الامتحان.

SyntaxالصياغةNameالاسمMeansالمعنىExample from slide 74مثال من الشريحة 74
(?=...)positive lookaheadنظر أمامي موجب (positive lookahead)require this pattern to followاشترط أن يلي هذا النمطfoo(?=bar) matches foo only if bar followsfoo(?=bar) يطابق foo فقط إذا تلاه bar
(?!...)negative lookaheadنظر أمامي سالب (negative lookahead)forbid this pattern from followingامنع أن يلي هذا النمطfoo(?!bar) matches foo only if bar does NOT followfoo(?!bar) يطابق foo فقط إذا لم يتله bar
(?<=...)positive lookbehindنظر خلفي موجب (positive lookbehind)require this pattern to precedeاشترط أن يسبق هذا النمط(?<=#)\d+ matches digits preceded by #(?<=#)\d+ يطابق أرقاماً يسبقها #
(?<!...)negative lookbehindنظر خلفي سالب (negative lookbehind)forbid this pattern from precedingامنع أن يسبق هذا النمط

يسرد الجدول أربع صيغ lookaround. (?=...) هو positive lookahead ويشترط أن يتبع هذا النمط، فـ foo(?=bar) يطابق foo فقط إذا تبعتها bar. و(?!...) هو negative lookahead ويمنع أن يتبع، فـ foo(?!bar) يطابق foo فقط إذا لم تتبعها bar. و(?<=...) هو positive lookbehind ويشترط أن يسبق، فـ (?<=#)\d+ يطابق أرقاماً تسبقها #. و(?<!...) هو negative lookbehind ويمنع أن يسبق.

Slide 70 says lookahead is useful when you need overlapping constraints without consuming text. Make that concrete:

تقول الشريحة 70 إن الـ lookahead مفيد حين تحتاج قيوداً متقاطعة دون استهلاك نص. وهذا تجسيدها:

input:   foobar foobaz

foo(?=bar)   matches  foo    (the one in foobar)
             the matched text is "foo", 3 characters.
             "bar" was checked but NOT consumed, so the next
             scan resumes at the 'b'.

foo(bar)     matches  foobar (6 characters), with "bar" in $1.
             the match itself is longer.

foo(?!bar)   matches  foo    (the one in foobaz)

على الدخل foobar foobaz: النمط foo(?=bar) يطابق foo التي في foobar، والنص المطابَق هو foo بثلاثة أحرف فقط، لأن bar فُحصت ولم تُستهلك، فيُستأنف المسح من b. أما foo(bar) فيطابق foobar بستة أحرف وbar محفوظة في $1، أي أن المطابقة نفسها أطول. والنمط foo(?!bar) يطابق foo التي في foobaz.

Lookahead versus capture group, the real difference

النظر الأمامي مقابل مجموعة الالتقاط، الفرق الحقيقي

Both use parentheses. Both let you talk about a sub-pattern. They differ on one axis only:

كلاهما يستخدم الأقواس، وكلاهما يتيح لك الحديث عن نمط فرعي. والفرق بينهما على محور واحد فقط:

Capture group (bar)مجموعة الالتقاط (bar)Lookahead (?=bar)النظر الأمامي (?=bar)
Is "bar" part of the match?هل "bar" جزء من التطابق؟yes, it extends the matched spanنعم، يمدّ المقطع المطابَقno, the span stops before itلا، المقطع يتوقف قبله
Can you retrieve it later?هل يمكنك استرجاعه لاحقاً؟yes, as $1نعم، في صورة $1noلا
Does the scan position advance past it?هل يتقدم موضع المسح بعده؟yesنعمno, which is why overlapping matches workلا، ولهذا تنجح التطابقات المتداخلة
Typical useالاستخدام المعتادextract and rewriteالاستخراج وإعادة الكتابةfilter without changing what you grabالتصفية دون تغيير ما تلتقطه

يقارن الجدول capture group أي (bar) بـ lookahead أي (?=bar) في أربعة أسطر. هل bar جزء من المطابقة؟ نعم في الأول فيمتد المدى، ولا في الثاني فيتوقف المدى قبلها. هل يمكن استرجاعها لاحقاً؟ نعم كـ $1 في الأول، ولا في الثاني. هل يتقدم موضع المسح بعدها؟ نعم في الأول، ولا في الثاني، ولهذا تعمل المطابقات المتقاطعة. والاستخدام المعتاد: الأول للاستخراج وإعادة الكتابة، والثاني للتصفية دون تغيير ما تلتقطه.

One warning the slide gives directly: lookbehind support varies. Some engines restrict variable-length lookbehind, so (?<=ab+) may be rejected where (?<=ab) is fine.

وتحذير تقوله الشريحة مباشرة: دعم lookbehind يتفاوت. بعض المحركات تمنع lookbehind المتغيّر الطول، فقد يُرفض (?<=ab+) في محرك يقبل (?<=ab) بلا مشكلة.

The flags, slide 74

الأعلام (Flags)، الشريحة 74

FlagالعلَمNameالاسمEffectالأثر
gglobalشامل (global)keep going after the first match instead of stoppingالاستمرار بعد أول تطابق بدلاً من التوقف
mmultilineمتعدد الأسطر (multiline)^ and $ match at every line break, not just the string ends^ و$ تطابقان عند كل فاصل سطر، لا عند طرفي السلسلة فقط
icase-insensitiveغير حساس لحالة الأحرف (case-insensitive)ignore letter case throughoutتجاهل حالة الأحرف في كل مكان

يسرد جدول الشريحة 74 ثلاثة flags. العلم g هو global: استمر بعد أول مطابقة بدل التوقف. والعلم m هو multiline: يجعل ^ و$ يطابقان عند كل فاصل أسطر، لا عند طرفي السلسلة فقط. والعلم i هو case-insensitive: تجاهل حالة الحروف في النمط كله.

Slide 71's practice list is built to exercise exactly these. The group Apple Juice / apPLe Juice / Apple juice / APPLE Juice is a case-insensitivity exercise: apple juice with the i flag matches all four, while [aA]pple [jJ]uice matches only two of them. And the repeated sentence "The faster they ran, the faster we ran" is a backreference exercise: (\w+)\b.*\b\1 finds a word that occurs twice.

قائمة التدريب في الشريحة 71 مبنية لتمرين هذه الأعلام بالذات. فمجموعة Apple Juice وapPLe Juice وApple juice وAPPLE Juice تمرين على تجاهل الحالة: النمط apple juice مع علم i يطابق الأربعة كلها، بينما [aA]pple [jJ]uice يطابق اثنين منها فقط. والجملة المكرّرة The faster they ran, the faster we ran تمرين على backreference: النمط (\w+)\b.*\b\1 يجد كلمة تظهر مرتين.

Back to tokenization: the GPT-2 pre-tokenizer, slides 75 and 76

العودة إلى التقطيع: المُقطِّع المسبق في GPT-2، الشريحتان 75 و76

This is where the regex block connects to Tokenization and BPE, the previous page. Go back to it if the word "merge" is fuzzy, because the two halves only make sense together.

هنا يتصل قسم regex بصفحة Tokenization and BPE السابقة. ارجع إليها إذا كانت كلمة merge غير واضحة، لأن النصفين لا يكتمل معناهما إلا معاً.

BPE learns merges over characters inside a word. But something has to decide what a "word" is before BPE ever runs, so that merges never accidentally span a space or glue punctuation to a noun. That first split is called pre-tokenization, and in GPT-2 it is one regular expression.

يتعلّم BPE الـ merges على الحروف داخل الكلمة. لكن شيئاً ما يجب أن يقرر ما هي "الكلمة" قبل أن يعمل BPE أصلاً، حتى لا تعبر الـ merges مسافة أو تلصق ترقيماً باسم. وهذا التقسيم الأول اسمه pre-tokenization، وهو في GPT-2 تعبير نمطي واحد.

Slide 76 names what the pattern is separating:

تسمّي الشريحة 76 ما يفصله النمط:

wordsالكلمات numbersالأعداد punctuationعلامات الترقيم contractionsالاختصارات (contractions) whitespaceالمسافات البيضاء

Slide 75 shows the actual pattern, which is a long alternation. Read it as five alternatives separated by bars, because that is all it is:

تعرض الشريحة 75 النمط الفعلي، وهو alternation طويل. اقرأه كخمسة بدائل تفصلها شرطات عمودية، فهذا كل ما هو عليه:

pat = re.compile(
    r"'s|'t|'re|'ve|'m|'ll|'d"      contractions as their own tokens
    r"| ?\p{L}+"                    optional space, then Unicode letters
    r"| ?\p{N}+"                    optional space, then Unicode digits
    r"| ?[^\s\p{L}\p{N}]+"          optional space, then punctuation
    r"|\s+(?!\S)|\s+"               leftover whitespace
)

text = "We're 350 dogs! Um, lunch?"
pat.findall(text)
['We', "'re", ' 350', ' dogs', '!', ' Um', ',', ' lunch', '?']

يبيّن المربع النمط في خمسة أسطر، كل سطر بديل واحد: 's|'t|'re|'ve|'m|'ll|'d للـ contractions كرموز مستقلة، ثم  ?\p{L}+ مسافة اختيارية ثم حروف Unicode، ثم  ?\p{N}+ مسافة اختيارية ثم أرقام Unicode، ثم  ?[^\s\p{L}\p{N}]+ مسافة اختيارية ثم ترقيم، ثم \s+(?!\S)|\s+ لبقية المسافات. وعلى الدخل We're 350 dogs! Um, lunch? يعطي الخرج ['We', "'re", ' 350', ' dogs', '!', ' Um', ',', ' lunch', '?'].

Three details in that output are worth noticing, because they explain design choices you saw on the BPE page:

ثلاث تفاصيل في هذا الخرج تستحق الانتباه، لأنها تفسّر قرارات تصميم رأيتها في صفحة BPE:

Slide 76 closes with the caveat that BPE merges then operate within or across these pieces depending on design. Most implementations, GPT-2 included, forbid merges across pre-token boundaries, which is precisely what stops the model from learning a single token for dogs!.

تنتهي الشريحة 76 بالتحذير أن الـ merges في BPE تعمل بعد ذلك داخل هذه القطع أو عبرها بحسب التصميم. ومعظم التطبيقات، ومنها GPT-2، تمنع الـ merges عبر حدود الـ pre-tokens، وهذا بالضبط ما يمنع النموذج من تعلّم رمز واحد لـ dogs!.

Engineering tips, slide 77

نصائح هندسية، الشريحة 77

  1. Start simple, add cases from error analysis. Do not try to write the perfect pattern first. Write the 80 percent version, run it, look at what it got wrong, extend.

    ابدأ بسيطاً وأضف الحالات من تحليل الأخطاء. لا تحاول كتابة النمط المثالي من أول مرة. اكتب نسخة تغطي 80 بالمئة، شغّلها، انظر فيما أخطأت، ثم وسّعها.

  2. Unit-test patterns on representative text. The slide's own practice link is regex101.com, which shows you the match and the step count live.

    اختبر الأنماط على نص تمثيلي. ورابط التدريب الذي تقترحه الشريحة هو regex101.com، ويعرض لك المطابقة وعدد الخطوات مباشرة.

  3. Be explicit about Unicode. Use \p{L} style classes and normalize your text first.

    كن صريحاً في أمر Unicode. استخدم أصنافاً من نوع \p{L} وطبّق normalization على نصك أولاً.

  4. Avoid catastrophic backtracking. Nested quantifiers like (a+)+b can take exponential time on a non-matching input, because the engine tries every way of splitting the a's. Replace greedy dots with negated classes, as in pattern C of the worked example above.

    تجنّب catastrophic backtracking. الـ quantifiers المتداخلة مثل (a+)+b قد تستهلك وقتاً أسّياً على دخل غير مطابق، لأن المحرك يجرّب كل طرق تقسيم حروف a. استبدل النقاط الطمّاعة بأصناف منفية، كما في النمط C في المثال المحلول أعلاه.

Thirty-second recap

خلاصة في ثلاثين ثانية

period is ambiguous, hence sentence segmentationالنقطة غامضة، ومن هنا تقسيم الجمل Eliza effect: reading humanity into pattern rulesأثر Eliza: قراءة الإنسانية في قواعد الأنماط [^x] negates, ^x anchors[^x] ينفي، و^x يرسي * is 0+, + is 1+, ? is 0 or 1 *? is lazy*? كسول \d \w \s lowercase; \D \W \S complement\d \w \s بأحرف صغيرة؛ و\D \W \S متمماتها | has the lowest precedence, so group it| له أدنى أسبقية، فجمّعه a quantifier binds only one elementالمكمِّم يرتبط بعنصر واحد فقط (...) captures, (?:...) does not(...) يلتقط، و(?:...) لا يلتقط (?=...) checks without consuming(?=...) يتحقق دون أن يستهلك . matches newline by default. يطابق السطر الجديد افتراضياً regex does BPE pre-tokenizationالـ regex يقوم بالتقطيع المسبق في BPE

Check yourself

اختبر نفسك

What does the pattern [e^] match?

ماذا يطابق النمط [e^]؟

Slide 60 lists this case explicitly. The caret negates only when it is the first character inside the brackets. Here it is second, so it is a literal caret, and the class is a plain disjunction of 'e' and '^'. A is the tempting answer because it assumes the caret always negates; that reading would require [^e]. B confuses the in-bracket caret with the line anchor, which only happens outside brackets.

الجواب C. تسرد الشريحة 60 هذه الحالة صراحة. الـ ^ ينفي فقط إذا كان الحرف الأول داخل الأقواس المربعة. وهنا هو الثاني، فيكون ^ حرفياً، والصنف مجرد disjunction بين e و^. والجواب A مُغرٍ لأنه يفترض أن ^ ينفي دائماً، وتلك القراءة تحتاج [^e]. والجواب B يخلط بين ^ داخل الأقواس وline anchor، وهذا لا يحدث إلا خارج الأقواس.

Applied to the string <Begin> Hello World <\End>, how many characters does <.*> match?

إذا طُبّق النمط <.*> على السلسلة <Begin> Hello World <\End>، فكم حرفاً يطابق؟

.* is greedy. It consumes to the end of the string, then backtracks just far enough for the final > to match, which lands on the very last character. So the match spans the entire 26-character string. A is the answer for the lazy version <.*?>, which is exactly why the greedy/lazy distinction is worth memorizing. C is wrong because . matches any character except a newline, and a space is not a newline.

الجواب B. الـ .* طمّاع (greedy)، فيستهلك حتى نهاية السلسلة، ثم يتراجع بالقدر الكافي فقط ليطابق > الأخيرة، فتهبط على آخر حرف تماماً. فتمتد المطابقة على السلسلة كلها بطول 26 حرفاً. والجواب A هو جواب النسخة الكسولة <.*?>، ولهذا بالضبط يستحق الفرق بين greedy وlazy الحفظ. والجواب C خاطئ لأن . يطابق أي حرف إلا السطر الجديد، والمسافة ليست سطراً جديداً.

A student writes ^cat|dog$ intending "the whole line is either cat or dog". What does the regex actually mean?

طالب يكتب ^cat|dog$ قاصداً "السطر كله إما cat وإما dog". فماذا يعني هذا الـ regex فعلياً؟

Alternation has the lowest precedence of any regex operator, so the bar splits the largest expressions around it: (^cat) or (dog$). The line "catalogue" matches, and so does "hotdog". The fix is ^(cat|dog)$. B is tempting because it treats the two anchors as applying to one single alternative, but the bar separates them into two independent patterns.

الجواب D. الـ alternation أدنى أسبقية من أي عامل في regex، فالشرطة العمودية تقسم أكبر تعبيرين حولها: (^cat) أو (dog$). فيطابق السطر catalogue، ويطابق hotdog أيضاً. والإصلاح هو ^(cat|dog)$. والجواب B مُغرٍ لأنه يتعامل مع الـ anchors كأنهما على بديل واحد، لكن الشرطة العمودية تفصلهما إلى نمطين مستقلين.

Which pattern matches both "ab" and "ababab", but not "abbb"?

أي نمط يطابق ab وababab معاً، ولا يطابق abbb؟

A quantifier binds only to the single element in front of it. The parentheses in (ab)+ make the whole two-character sequence that element, so it repeats as a unit. B is the classic error: in ab+ the + attaches to b alone, so it matches "abbb" and never matches "ababab". D is wrong in the other direction, since a character class matches any mixture of a's and b's including "abbb".

الجواب A. الـ quantifier يرتبط بالعنصر الواحد الذي أمامه فقط. والأقواس في (ab)+ تجعل التسلسل ذا الحرفين كله هو ذلك العنصر، فيتكرر كوحدة. والجواب B هو الخطأ الكلاسيكي: في ab+ ترتبط + بـ b وحدها، فيطابق abbb ولا يطابق ababab أبداً. والجواب D خاطئ في الاتجاه الآخر، لأن صنف الحروف يطابق أي خليط من a وb بما فيه abbb.

For the substitution s/(\d{4})-(\d{2})-(\d{2})/$2$3$1/ applied to 2026-25-01, what is in $2?

في الاستبدال s/(\d{4})-(\d{2})-(\d{2})/$2$3$1/ المطبّق على 2026-25-01، ما الذي يوجد في $2؟

Groups are numbered by the order of their opening parenthesis, left to right, and only parenthesized parts are stored. $1 = 2026, $2 = 25, $3 = 01. B is the useful wrong answer to rule out: the hyphens are bare literals outside any parentheses, so they are matched and then discarded, which is exactly why the replacement can swap the separator to a slash.

الجواب C. تُرقّم الـ groups بترتيب قوس الفتح من اليسار إلى اليمين، ولا يُحفظ إلا ما بين الأقواس. فـ $1 = 2026 و$2 = 25 و$3 = 01. والجواب B هو الخطأ المفيد لاستبعاده: الشرطتان حرفيتان مجرّدتان خارج أي أقواس، فتُطابقان ثم تُلقى بهما، وهذا بالضبط سبب قدرة الاستبدال على تغيير الفاصل إلى شرطة مائلة.

Applied to "foobar", what text does foo(?=bar) actually return as the match?

إذا طُبّق foo(?=bar) على foobar، فما النص الذي يعيده كمطابقة فعلياً؟

A lookahead is a zero-width assertion. It checks that "bar" follows, but does not consume it, so the returned match is just "foo". A is the answer for foo(bar) or plain foobar, where the text becomes part of the span. This non-consuming property is exactly what slide 70 means by "overlapping constraints without consuming text".

الجواب B. الـ lookahead تأكيد بعرض صفر. يتحقق أن bar تتبع، لكنه لا يستهلكها، فالمطابقة المُعادة هي foo فقط. والجواب A هو جواب foo(bar) أو foobar المجرد، حيث يصبح النص جزءاً من المدى. وخاصية عدم الاستهلاك هذه هي بالضبط ما تقصده الشريحة 70 بعبارة overlapping constraints without consuming text.

Why does the GPT-2 pre-tokenizer regex use \p{L} instead of [a-zA-Z]?

لماذا يستخدم regex الخاص بـ GPT-2 pre-tokenizer النمط \p{L} بدل [a-zA-Z]؟

Slide 77 states the principle ("be explicit about Unicode behavior, \p{L} classes, normalization") and slide 75 shows it applied. A Latin-only class would push every non-Latin character into the punctuation branch of the alternation and shred multilingual text. C is nonsense: greediness is a property of quantifiers, not of character classes.

الجواب D. تنص الشريحة 77 على المبدأ، أي الصراحة في سلوك Unicode وأصناف \p{L} والـ normalization، وتعرض الشريحة 75 تطبيقه. فأي صنف لاتيني فقط سيدفع كل حرف غير لاتيني إلى فرع الترقيم في الـ alternation ويمزّق النص متعدد اللغات. والجواب C كلام فارغ: الطمع (greediness) خاصية الـ quantifiers، لا أصناف الحروف.