• בלוג
  • טיפ פייתון: החלפה והרצת קוד בתוך ביטוי רגולארי

טיפ פייתון: החלפה והרצת קוד בתוך ביטוי רגולארי

24/06/2019

אחד הדברים הנחמדים שאנחנו מקבלים משימוש בביטויים רגולאריים בתוך שפת תכנות הוא היכולת להריץ קוד כחלק מתהליך החלפת הטקסט שביטוי רגולארי זיהה.

בפייתון הפונקציה re.sub היא שעוזרת לנו להחליף את הטקסט שהתאים לביטוי רגולארי מסוים בטקסט אחר. למשל הפונקציה הבאה מקבלת טקסט עם סימן קו תחתי שמפריד בין המילים והופכת כל קו תחתי לרווח:

import re

def underscore_to_spaces(text):
    pat = re.compile('_')
    return pat.sub(' ', text)

אבל מה אם נרצה בנוסף גם להחליף את האות הראשונה בכל מילה באות גדולה? פה יש בעיה כי כל מילה יכולה להתחיל באות אחרת.

בדיוק בשביל זה הפונקציה re.sub מספקת לנו גם נקודת התערבות בדיוק אחרי שהיא מוצאת התאמה ומאפשרת לנו להחליף את ההתאמה שנמצאה בתוצאת הפעלת פונקציה.

אותה פונקציה מקבלת כפרמטר אוביקט שנקרא Match Object. אוביקט זה יודע לספר לנו כל מיני דברים לגבי ההתאמה שנמצאה, למשל איפה היתה ההתאמה ומה היה הטקסט שהתאים. באמצעות שימוש ב Match Object אנחנו יכולים בצורה דינמית לחשב את הטקסט שנרצה לכתוב במקום ההתאמה.

בדוגמא שלנו בשביל לכתוב את האות הבאה במילה כאות גדולה נוכל להשתמש בפונקציה capitalize של פייתון. הביטוי הבא מחליף כל מילה (שבאה אחרי קו תחתי) באותה מילה אחרי הפעלת capitalize עליה:

def almost_uppercase_words(text):
    pat = re.compile('_')
    return pat.sub(lambda m: m.group().capitalize(), text)

זה עדיין לא מספיק בשביל לכתוב אות גדולה בתחילת כל אחת מהמילים מאחר והערך של m.group כולל גם את הקו התחתי.

דרך קלה להתגבר על זה היא להחליף קודם את כל הקווים התחתיים בסימן רווח, ואחרי זה להחליף את האות הראשונה בכל מילה לאות גדולה:

import re

def ucfirst_each_word(text):
    each_word = re.compile(r'(\w+)')
    return each_word.sub(lambda m: m.group().capitalize(), re.sub('_', ' ', text))

print(ucfirst_each_word("mad_mad_world"))

וכמובן אם פונקציית ה lambda מתחילה להיות ארוכה תמיד אפשר להגדיר אותה בצורה חיצונית ולהעביר את הפונקציה כפרמטר.