תרגיל ב-Python לשמות לתינוקות

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

הקבצים של התרגיל הזה נמצאים בספרייה "babynames" בתוך google-python-exercises (הורד את google-python-exercises.zip אם עדיין לא עשית זאת, לקבלת פרטים, ניתן לעיין בהגדרה). הוסף את הקוד שלך ב-Babynames.py. הקבצים Baby1990.htmlinfant1992.html ... מכילים html גולמי, בדומה למה שקיבלת בעת ביקור באתר של הביטוח הלאומי שלמעלה. כדאי לעיין ב-HTML ולחשוב איך אתם יכולים לגרד את הנתונים ממנו.

חלק א'

בקובץ Babynames.py, מטמיעים את הפונקציה generate_names(filename) . הפונקציה הזו לוקחת את שם הקובץ של file*.html ומחזירה את הנתונים מהקובץ כרשימה אחת – מחרוזת השנה בתחילת הרשימה ואחריה מחרוזות של דרגות שמות בסדר אלפביתי. ['2006', 'Aaliyah 91', 'Abagail 895', 'Aaron 57', ...]. יש לשנות את main() כך שתתבצע קריאה לפונקציה shortcuts_names() ומדפיסים את מה שהיא מחזירה (בגרסה הראשית כבר יש את הקוד לניתוח הארגומנט של שורת הפקודה). אם תתקשו להבין את הביטויים הרגולריים לשנה ולכל שם, דפוסי הביטויים הרגולריים של הפתרון מוצגים בסוף המסמך הזה. שימו לב: ביטויים רגולריים לא עושים עבודה טובה בניתוח דפי אינטרנט באופן כללי, אבל הפורמט של דפי אינטרנט האלה הוא פשוט ועקבי.

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

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

הדפסת הנתונים שצברתם בסוף אבן דרך אחת תעזור לכם לחשוב איך לשנות את מבנה הנתונים לאבן הדרך הבאה. Python מתאים מאוד לסגנון הזה של פיתוח מצטבר. לדוגמה, קודם צריך להביא אותו לנקודה שבה הוא שולף ומדפיס את השנה וקורא אל sys.exit(0). הנה כמה הצעות לאבני דרך:

  • מחלצים את כל הטקסט מהקובץ ומדפיסים אותו
  • מחפשים, מחלצים את השנה ומדפיסים אותה
  • מחלצים את השמות, מדרגים מספרים ומדפיסים אותם
  • הפקת נתוני השמות והדפסתם
  • יצירת הרשימה [שנה, 'דירוג שם', ... ] והדפסתה
  • תיקון main() כדי להשתמש ברשימה extractNames

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

צריך להגדיר ל-main() קריאה לחילוץ_names() לכל arg של שורת פקודה, ולהדפיס סיכום טקסט. כדי להפוך את הרשימה לטקסט סיכום שנראה הגיוני, אפשר להשתמש בצורה חכמה ב-join: 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 ביי*.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>'