تطابق بسيط لـ C regex من Rob Pike in Go

آب (أغسطس) 2022

في عام 1998 ، كتب روب بايك ، المشهور بـ Go و Plan 9 ، مقارن تعبير عادي بسيط لـ C لـ The Practice of Programming ، وهو كتاب شارك في تأليفه مع زميله Unix Hacker Brian Kernighan. إذا لم تكن قد قرأت "تفسير" Kernighan لهذا الرمز ، فمن المؤكد أنه يستحق 30 دقيقة من الاستثمار الذي تستغرقه لتصفحه ببطء.

من خلال تراث Go's C (وتأثير Pike على لغة Go) ، اعتقدت أنني سأرى مدى جودة ترجمة C البرمجية إلى Go ، وما إذا كانت لا تزال أنيقة. النسخة الأصلية C

لنلقِ نظرة على رمز المطابقة الأصلي لبايك أولاً. إنه يتعامل فقط مع عدد صغير من الأحرف الأولية للتعبير العادي ، مثل. ، * ، ^ ، و $ ، لكنه مجموعة فرعية مختارة جيدًا ، وفقًا لـ Kernighan ، "تمثل 95٪ من جميع مثيلات" استخدامها بسهولة يوميًا. < / ص>

أنا فقط grep .bash_history الخاص بي لاستخدام grep (كيف meta!) والنسبة المئوية الخاصة بي متشابهة ، على الرغم من أنني أستخدم أيضًا أحرف أولية تم تجاوزها (عادةً \.) في حوالي 10٪ من الاستخدامات.

هنا هو المطابق الأصلي 35 سطرًا ج: / * match: ابحث عن التعبيرات العادية في أي مكان في النص * / تطابق int (char * regexp ، char * text) { إذا (التعبير العادي [0] == '^') إرجاع المطابقة (regexp + 1 ، نص) ؛ يجب {/ * البحث حتى إذا كانت السلسلة فارغة * / إذا (matchhere (regexp ، text)) العودة 1 ؛ } while (* text ++! = '\ 0') ؛ إرجاع 0 ؛ } / * matchhere: البحث عن التعبير العادي في بداية النص * / int matchhere (char * regexp، char * text) { إذا (regex [0] == '\ 0') العودة 1 ؛ إذا (تعبير عادي [1] == '*') إرجاع matchstar (regexp [0] ، regexp + 2 ، نص) ؛ إذا (regexp [0] == '$' && regexp [1] == '\ 0') إرجاع * النص == '\ 0' ؛ if (* text! = '\ 0' && (regexp [0] == '.' || regexp [0] == * text)) إرجاع المطابقة (التعبير العادي + 1 ، النص + 1) ؛ إرجاع 0 ؛ } / * matchstar: ابحث عن c * regexp في بداية النص * / int matchstar (int c ، char * regex ، char * text) { فعل {/ * a * يطابق صفرًا أو أكثر من المثيلات * / إذا (matchhere (regexp ، text)) العودة 1 ؛ } while (* text! = '\ 0' && (* text ++ == c || c == '.')) ؛ إرجاع 0 ؛ }

جميلة ، أليس كذلك؟ لن أشرح هذا الرمز هنا ؛ يقوم Kernighan بعمل أفضل بكثير مما أفعله في مقالته "A Regular Expression Matcher".

ترجمة |

لا تستخدم السلاسل النصية في Go مؤشرات char ، بالطبع ، لكن عمليات فهرسة السلسلة وتقطيع السلاسل مثل النص [1:] متطابقة تمامًا (إذا جاز التعبير).

كما يشير Kernighan ، فإن "do-while" نادر جدًا في C ، ولكنه ضروري هنا. على الأرجح للأفضل ، ليس لدى Go وقت ، لذلك أستخدم عبارة if داخل الحلقة وأعود مبكرًا بدلاً من ذلك. أيضًا ، لن تساعدنا ميزة "do-while" هنا لأننا ما زلنا غير قادرين على استخدام تعبيرات الجلب والزيادة مثل * text ++.

هناك عدد من الأشياء تشغل سطورًا أكثر في Go ، ويرجع ذلك جزئيًا إلى عدم وجود "وقت" ، ولكن أيضًا لأنك لا تستطيع فعل عبارات على سطر بدون أقواس. ومع ذلك ، فقد قمت بتحويل سلسلة عبارات if في matchHere إلى مفتاح تبديل بسيط ، مما يجعل هذه الوظيفة موجزة تقريبًا مثل إصدار C.

بعض الأشياء تكون أسهل مع السلاسل في Go ، على سبيل المثال regexp [0] == '$' && regexp [1] == '\ 0' تصبح regexp == "$".

لذلك بدون مزيد من اللغط ، ها هو إصدار Go الخاص بي:

آب (أغسطس) 2022

في عام 1998 ، كتب روب بايك ، المشهور بـ Go و Plan 9 ، مقارن تعبير عادي بسيط لـ C لـ The Practice of Programming ، وهو كتاب شارك في تأليفه مع زميله Unix Hacker Brian Kernighan. إذا لم تكن قد قرأت "تفسير" Kernighan لهذا الرمز ، فمن المؤكد أنه يستحق 30 دقيقة من الاستثمار الذي تستغرقه لتصفحه ببطء.

من خلال تراث Go's C (وتأثير Pike على لغة Go) ، اعتقدت أنني سأرى مدى جودة ترجمة C البرمجية إلى Go ، وما إذا كانت لا تزال أنيقة. النسخة الأصلية C

لنلقِ نظرة على رمز المطابقة الأصلي لبايك أولاً. إنه يتعامل فقط مع عدد صغير من الأحرف الأولية للتعبير العادي ، مثل. ، * ، ^ ، و $ ، لكنه مجموعة فرعية مختارة جيدًا ، وفقًا لـ Kernighan ، "تمثل 95٪ من جميع مثيلات" استخدامها بسهولة يوميًا. < / ص>

أنا فقط grep .bash_history الخاص بي لاستخدام grep (كيف meta!) والنسبة المئوية الخاصة بي متشابهة ، على الرغم من أنني أستخدم أيضًا أحرف أولية تم تجاوزها (عادةً \.) في حوالي 10٪ من الاستخدامات.

هنا هو المطابق الأصلي 35 سطرًا ج: / * match: ابحث عن التعبيرات العادية في أي مكان في النص * / تطابق int (char * regexp ، char * text) { إذا (التعبير العادي [0] == '^') إرجاع المطابقة (regexp + 1 ، نص) ؛ يجب {/ * البحث حتى إذا كانت السلسلة فارغة * / إذا (matchhere (regexp ، text)) العودة 1 ؛ } while (* text ++! = '\ 0') ؛ إرجاع 0 ؛ } / * matchhere: البحث عن التعبير العادي في بداية النص * / int matchhere (char * regexp، char * text) { إذا (regex [0] == '\ 0') العودة 1 ؛ إذا (تعبير عادي [1] == '*') إرجاع matchstar (regexp [0] ، regexp + 2 ، نص) ؛ إذا (regexp [0] == '$' && regexp [1] == '\ 0') إرجاع * النص == '\ 0' ؛ if (* text! = '\ 0' && (regexp [0] == '.' || regexp [0] == * text)) إرجاع المطابقة (التعبير العادي + 1 ، النص + 1) ؛ إرجاع 0 ؛ } / * matchstar: ابحث عن c * regexp في بداية النص * / int matchstar (int c ، char * regex ، char * text) { فعل {/ * a * يطابق صفرًا أو أكثر من المثيلات * / إذا (matchhere (regexp ، text)) العودة 1 ؛ } while (* text! = '\ 0' && (* text ++ == c || c == '.')) ؛ إرجاع 0 ؛ }

جميلة ، أليس كذلك؟ لن أشرح هذا الرمز هنا ؛ يقوم Kernighan بعمل أفضل بكثير مما أفعله في مقالته "A Regular Expression Matcher".

ترجمة |

لا تستخدم السلاسل النصية في Go مؤشرات char ، بالطبع ، لكن عمليات فهرسة السلسلة وتقطيع السلاسل مثل النص [1:] متطابقة تمامًا (إذا جاز التعبير).

كما يشير Kernighan ، فإن "do-while" نادر جدًا في C ، ولكنه ضروري هنا. على الأرجح للأفضل ، ليس لدى Go وقت ، لذلك أستخدم عبارة if داخل الحلقة وأعود مبكرًا بدلاً من ذلك. أيضًا ، لن تساعدنا ميزة "do-while" هنا لأننا ما زلنا غير قادرين على استخدام تعبيرات الجلب والزيادة مثل * text ++.

هناك عدد من الأشياء تشغل سطورًا أكثر في Go ، ويرجع ذلك جزئيًا إلى عدم وجود "وقت" ، ولكن أيضًا لأنك لا تستطيع فعل عبارات على سطر بدون أقواس. ومع ذلك ، فقد قمت بتحويل سلسلة عبارات if في matchHere إلى مفتاح تبديل بسيط ، مما يجعل هذه الوظيفة موجزة تقريبًا مثل إصدار C.

بعض الأشياء تكون أسهل مع السلاسل في Go ، على سبيل المثال regexp [0] == '$' && regexp [1] == '\ 0' تصبح regexp == "$".

لذلك بدون مزيد من اللغط ، ها هو إصدار Go الخاص بي:

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow