במנהל הביטוח הלאומי יש נתונים מסודרים לפי שנה, של השמות הפופולריים ביותר בקרב תינוקות שנולדו באותה שנה בארה"ב (ראו שמות של תינוקות בביטוח לאומי).
הקבצים לתרגיל הזה נמצאים ב"שמות תינוקות" בתוך google-python-exercises (מורידים את google-python-exercises.zip אם עדיין לא עשיתם זאת), לפרטים נוספים, ראו הגדרה). הוסף את הקוד בכתובת Babynames.py. הקבצים Baby1990.html family1992.html ... מכילים html גולמי, בדומה למה שמקבלים כשמבקרים באתר הביטוח הלאומי שלמעלה. כדאי לבדוק את קוד ה-HTML ולחשוב איך אפשר לחלץ ממנו נתונים.
חלק א'
בקובץ Babynames.py, מיישמים את הפונקציה generate_names(filename) שמקבלת את שם הקובץ של family*.html ומחזירה את הנתונים מהקובץ כרשימה אחת – מחרוזת השנה בתחילת הרשימה, ואחריה המחרוזות של דירוג השם בסדר אלפביתי. ['2006', 'Aaliyah 91', 'Abagail 895', 'Aaron 57', ...]. יש לשנות את ה-main() כך שיקרא לפונקציה extract_names() ותדפיס את מה שהיא מחזירה (בגוף הראשי כבר יש קוד לניתוח הארגומנט של שורת הפקודה). אם נתקעת בביטויים הרגולריים של השנה וכל שם, התבניות של הביטויים הרגולריים של הפתרונות מוצגים בסוף המסמך. שים לב שבניתוח של דפי אינטרנט באופן כללי, ביטויים רגולריים לא מבצעים עבודה טובה, אבל לדפי אינטרנט אלה יש פורמט פשוט ועקבי.
במקום להתייחס לשמות של ילד וילדה בנפרד, אנחנו פשוט נאחד את כולם יחד. בשנים מסוימות שם מופיע יותר מפעם אחת ב-HTML, אבל נשתמש במספר אחד לכל שם. אם רוצים, מגדירים את האלגוריתם לחכם לגבי הפנייה הזו ובוחרים את המספר הקטן מביניהם.
בונים את התוכנית כסדרה של אבני דרך קטנות, ומנסים להפעיל/להדפיס כל שלב לפני שמנסים את השלב הבא. זה הדפוס שבו משתמשים מתכנתים מנוסים – צרו סדרה של אבני דרך הדרגתיות, שכל אחת מהן צריכה לבדוק פלט כלשהו, במקום לבנות את כל התוכנית בצעד אחד ענק.
הדפסת הנתונים שיש לכם בסוף של אבן דרך אחת עוזרת לכם לחשוב איך לארגן מחדש את הנתונים האלה לאבן הדרך הבאה. Python מאוד מתאים לסגנון הזה של התפתחות מצטברת. לדוגמה, קודם צריך להעביר אותו לנקודה שבה מחלצים ומדפיסים את השנה, וקוראים ל-sys.exit(0). הנה כמה הצעות לאבני דרך:
- צריך לחלץ את כל הטקסט מהקובץ ולהדפיס אותו.
- מחפשים את השנה, מחלצים אותה ומדפיסים אותה
- צריך לחלץ את השמות ומספרי הדירוג, ולהדפיס אותם
- קבלת נתוני השמות של הכתבה והדפסה שלהם
- בניית הרשימה [year, 'name Rank', ... ] והדפסתה
- צריך לתקן את Main() כדי להשתמש ברשימה extractNames
קודם לכן השתמשנו בפונקציות כדי להדפיס אותן באופן סטנדרטי. הפונקציה יכולה *להחזיר* את הנתונים שחולצו באמצעות שימוש חוזר רבה יותר, אז המתקשר יכול לבחור להדפיס אותם או לעשות איתו פעולה אחרת. (עדיין אפשר להדפיס ישירות מתוך הפונקציות בניסויים קטנים במהלך הפיתוח).
צריך להפעיל את קריאת ה-main() בשביל כל arg של שורת פקודה ולהדפיס סיכום של הטקסט. כדי להפוך את הרשימה לטקסט סיכום שנראה הגיוני, הנה שימוש חכם בקישור: text = '\n'.join(mylist) + '\n'
טקסט הסיכום צריך להיראות כך:
2006 Aaliyah 91 Aaron 57 Abagail 895 Abbey 695 Abbie 650 ...
חלק ב'
נניח שבמקום להדפיס את הטקסט לדפוס רגיל, אנחנו רוצים לכתוב קבצים שמכילים את הטקסט. אם הדגל --summaryfile קיים, מבצעים את הפעולות הבאות: עבור כל קובץ קלט 'foo.html', במקום להדפיס לפלט סטנדרטי, כותבים קובץ חדש 'foo.html.summary'. שמכיל את טקסט הסיכום של הקובץ.
כאשר התכונה --summaryfile פועלת, מפעילים את התוכנית בכל הקבצים באמצעות * כמו בדוגמה הבאה: " ./babynames.py --summaryfile Baby*.html". הפעולה הזו יוצרת את כל הסיכומים בשלב אחד. (התנהגות רגילה של המעטפת היא שהיא מרחיבה את התבנית 'baby*.html' לרשימת שמות הקבצים התואמים, ואז המעטפת מריצה Babynames.py ומעבירה את כל שמות הקבצים האלה ברשימת sys.argv).
כשהנתונים מסודרים בקובצי סיכום, אפשר לראות דפוסים לאורך זמן באמצעות פקודות מעטפת, כמו:
$ grep 'Trinity ' *.summary $ grep 'Nick ' *.summary $ grep 'Miguel ' *.summary $ grep 'Emily ' *.summary
רמזים לביטוי רגולרי -- שנה: r'פופולריות\sin\s(\d\d\d\d)' שמות: r'<td>(\d+)</td><td>(\w+)</td>\<td>(\w+)</td>'