משתמש:Mad dr/פייתון/מודולים/re: הבדלים בין גרסאות בדף

תוכן שנמחק תוכן שנוסף
Mad dr (שיחה | תרומות)
יצירת דף עם התוכן " נושא עיבוד המידע חשוב מאוד בתכנות, ולעיתים אנו נדרשים לעבד טקסט חופשי שלא מסודר בפורמט כ..."
(אין הבדלים)

גרסה מ־22:23, 21 בספטמבר 2014

נושא עיבוד המידע חשוב מאוד בתכנות, ולעיתים אנו נדרשים לעבד טקסט חופשי שלא מסודר בפורמט כמו json או xml. לעיתים נצטרך להבין לוג או הודעת שגיאה, ולפעמים נראה לסנן את המידע החשוב כדי להשתמש בו בהמשך. (דוגמא טובה לזה נמצאת בדרך בה אפיליקציה וובית, או אתר רגיל, "קורא" את הכתובת שלו, ונגיע לזה כנלמד על טורנדו או ג'אנגו)

re היא ספריה סטנדרטית של פייתון שנותנת לנו יכולות טובות להפעיל regular expressions (או בקיצור regex - רגקס). כאשר יש מספר שיטות לשימוש ב-re. (מי שלא בקיא ברגקסים יכול להתחיל ללמוד באתר פרל בעברית http://perl.eitan.ac.il/main.php?id=00106)

search ו-match

search ו-match הן הפונקציות הבסיסיות של ביטויים רגולריים, הן מקבלות שני ערכים, הראשון הוא התבנית (pattern) והשני הוא המחרוזת (subject). ערכים נוספים שאפשר לשלוח הם נקודת התחלה, נקודת סיום ומודיפקטורים (modifiers).

במידה והתבנית מתאימה למחרוזת יחזור אובייקט מסוג re.MatchObject עליו נרחיב עוד מעט, אם לא יחזור לנו None.

ההבדלים בין search ל-match מסתכמים ב:

  1. search עובר על כל המחרוזת עד שהוא מוצא התאמה (או לא), match מחפש את התבנית בתחילת המחרוזת (במידה ונתנו נקודת התחלה שונה, הוא יחפש ממנה כמובן)
  2. ההתייחסות לשורה חדשה במצב של ריבוי שורות (מודיפקטור re.M) שונה, search מתייחס לכל שורה חדשה כהתחלה (עבור התו המיוחד ^) ואילו match מתייחס רק לתחילת המחרוזת:
>>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match
>>> m = re.search('^X', 'A\nB\nX', re.MULTILINE) # Match
>>> m.start()
4
>>> m.end()
5

האובייקט המוחזר הוא מסוג re.MatchObject, המתודות המעניינות שלו הן group() שמחזירה מחרוזות שמורות (אוגרים) ומקבלת את המזהה של האוגר (החל מ-1), אם מצויין אוגר 0, יוחזר ההתאמה המלאה (ללא התייחסות לאוגרים), ואם ינתנו מספר פרמטרים כל הערכים המתאימים יחזרו כ-Tuple. פנייה לאוגר שלא קיים יזרוק חריגה IndexError: no such group

המתודה groups() מחזירה את כל האוגרים כ-Tuple, ומקבלת מחרוזת כפרמטר שיהיה ערך ברירת המחדל עבור אוגרים שאין להם תוכן (לא מחרוזות ריקות)

>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups()     # Second group defaults to None.
('24', None)
>>> m.groups('0') # Now, the second group defaults to '0'.
('24', '0')

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

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+), (?P<profession>\w+)", "Albert Einstein, Physicist")
>>> m.groupdict()
{'first_name': 'Albert', 'last_name': 'Einstein', 'profession': 'Physicist'}

המתודות start ו-end מביאות את המיקום של ההתחלה והסוף של האוגר שניתן כפרמטר, אם לא צויין אוגר תחזור התוצאה המתאימה להתאמה המלאה (כמו במקרה של group(0))

>>> m.start()
0
>>> m.end()
26
>>> m.start(1)
0
>>> m.start(2)
7
>>> m.start(3)
17
>>> m.end(1)
6
>>> m.end(2)
15
>>> m.end(3)
26

קוד לדוגמא:

mad_dr@ubuntu:~$ cat url_parser.py
import re, sys, pprint
 
def parser(match):
    if match is None:
        print("    String doesn't match pattern")
        return
 
    template = '    group({}): {}'
    for i in range(10):
        try:
            print(template.format(i, match.group(i)))
        except IndexError:
            if i < 3:
                print(template.format(i, 'None'))
            else:
                break
 
    pprint.pprint(match.groupdict('hostname'))
 
def main():
    str = sys.argv[1]
    print(str)
    pattern = r'(?P\w+)://(?P[^\s/]+)/(?P[^\s#?]+)#?(?P[^\s?]+)?\??(?P\S+)?'
    m = re.match(pattern, str)
    parser(m)
    return 0
 
if __name__ == '__main__':
    ret_code = main()
    sys.exit(ret_code)
mad_dr@ubuntu:~$
mad_dr@ubuntu:~$
mad_dr@ubuntu:~$ python3 url_parser.py 'https://docs.python.org/3/library/re.html#re.sub'
https://docs.python.org/3/library/re.html#re.sub
    group(0): https://docs.python.org/3/library/re.html#re.sub
    group(1): https
    group(2): docs.python.org
    group(3): 3/library/re.html
    group(4): re.sub
    group(5): None
{'headline': 're.sub',
 'hostname': 'docs.python.org',
 'parameters': 'hostname',
 'path': '3/library/re.html',
 'protocol': 'https'}

וכמו שאתם רואים, יש באג עם אוגרים ריקים... אם למישהו יש הסבר הוא מוזמן לשתף בתגובות. תיעוד - [1]