זה נושא דיון מלווה לערך המקורי ב- https://www.tocode.co.il/bundles/python/lessons/regexp-lab
זה נושא דיון מלווה לערך המקורי ב- https://www.tocode.co.il/bundles/python/lessons/regexp-lab
תשובה לתרגיל 1
"""
Answer 26-1
"""
import re
import sys
import os.path
#Cheek if argument is ok
if len(sys.argv) <3:
sys.exit("Error: You Must to set minimum 2 argument: 1: setting file name, 2:key of the setting to get the value ")
[_,setting_file,setting_key]=sys.argv
if not os.path.isfile(setting_file):
sys.exit("The file '{}' issnot exist".format(setting_file))
with open(setting_file,"r") as f:
for line in f:
res = re.search(r'(\w+)\s*=\s*(\w+)', line)
if res is not None and res.group(1)==setting_key:
print res.group(2)
תרגיל 2 - כאשר מריץ זה לא מצליח
"""
Answer 26-2
"""
import re
import sys
def toCamelCase(text):
res=re.sub(r'\b[a-z]',lambda m: m.group(1).upper(),text)
res=re.sub(r'_','',res)
return res
while True:
line=sys.stdin.readline()
if line=='':break
print toCamelCase(line)
אני חושב שהביטוי הרגולרי לא נכון,
ובנוסף בשביל להשתמש ב group צריך שיהיו סוגריים עגולים בביטוי (שיתאימו ל group שאתה רוצה לשלוף)
פתרון שלי לתרגיל 1:
import sys,re
(_,path,key)=sys.argv[:3]
def findkv(key,text):
res = re.search(r'#?\s*(\w+)\s*=\s*(\w+)',text)
if res is not None:
if key==res.group(1):
return res.group(2)
with open(path,"r") as fin:
for line in fin :
val= findkv(key,line)
if val is not None:
print val
פתרון שלי לתרגיל 2:
import re
def toCamelCase(text):
res=re.search(r'(\w+)\_?',text)
if res is not None:
text=re.sub(r'\_',' ',text)
text = re.sub(r'(\b\w)', lambda m: m.group(0).upper(),text)
print text
def revertToCamelCase(text):
res=re.search(r'(\b\w)',text)
if res is not None:
text = re.sub(r'(\b\w)', lambda m: m.group(0).lower(),text)
text=re.sub(' ','_',text)
print text
revertToCamelCase('C C Hello Mani')
מדוע זה לא עובד לי פתרון לתרגיל 3:
import re,csv,sys
(csvpath)=sys.argv[1]
def csvSub2Col(line):
res =re.search(r'(\w+)\,+(\w+)\,\w+\@\w+\.\w+',line)
#print line
if res is not None:
line= re.sub(res.group(1),res.group(2),line)
return line
with open(csvpath, 'rb') as csvfile:
spamreader = csv.reader(csvfile, delimiter=',')
textline=''
for row in spamreader:
#print row
for val in row:
val+=','
textline+= val
print csvSub2Col(textline[:-1])
textline = ''
val= ''
קשה לדעת - יש פה הרבה קוד ואין ״נקודות ביקורת״. כמה הערות והצעה:
-
בפייתון נוהגים לכתוב שמות של פונקציות ומשתנים באותיות קטנות בלבד. אם יש כמה מילים מפרידים אותן בקו תחתי. אפשר ורצוי לקרוא עוד על סטדנרטים בפייתון כאן:
https://www.python.org/dev/peps/pep-0008/ -
אני הייתי משתמש אך ורק ב csvreader בתרגיל הזה ללא ביטויים רגולאריים. אני חושש שהביטוי הרגולארי כאן רק מפריע.
-
במצבים כאלה שדברים לא עובדים צריך לזהות מה בדיוק לא עובד, כלומר קודם כל לזהות באיזה מנגנון או איזה שורה הבעיה. אני אוהב להוסיף הדפסה כמעט אחרי כל שורה ולהציג את ערך המשתנים (למשל row, val, textline ובתוך הפונקציה להדפיס מהי line, מהו הביטוי הרגולרי ומה התוצאה אחרי ההחלפה). אחרי שתראה את כל המידע מול העיניים יהיה יותר קל להתמקד ולהתקדם
הפתרון הסופי שלי לתרגיל 3:
import re,csv,sys
(csvpath)=sys.argv[1]
def csv_sub_2col(line,*args):
res =re.search(r'(\w+)\,+(\w+)\,\w+\@\w+\.\w+',line)
#print line
str1= args[0]
str2= args[1]
if res is not None:
return multiple_replace(line, {str1:str2, str2:str1})
def multiple_replace(string, rep_dict):
pattern = re.compile("|".join([re.escape(k) for k in sorted(rep_dict,key=len,reverse=True)]), flags=re.DOTALL)
return pattern.sub(lambda x: rep_dict[x.group(0)], string)
with open(csvpath, 'rb') as csvfile:
spamreader = csv.reader(csvfile, delimiter=',')
textline=''
listw=[]
for row in spamreader:
for val in row:
val+=','
textline+= val
listw.append(val)
g1=listw[0]
g2=listw[1]
print csv_sub_2col(textline[:-1],g1,g2)
textline = ''
val= ''
listw = []
ניסתי לפתור את התרגיל קודם כל בידע שאני יודע מפה אבל זה לא הצליח אז מחפשים
קצת באינטרנט stackoverflow ואז כמו שכבר הבנת מצאתי לי תפונקציה def multiple_replace שאני לא ממש יודע מה כל שורה עושה שם אבל היא עובדת ומחליפה שני מחרוזות שמעבירים לה כאובייקט,אני לא בא להמציא תגלגל אבל זה מתסכל אותי שאני לא מבין לעומק תשורות שם.
חתיכת פונקציה…
בוא ננסה לקרוא אותה לאט יחד והכי טוב דרך דוגמא. נניח שנפעיל אותה עם:
>>> multiple_replace('hello world', { 'o': '0', 'l': '1', 'e': '3' })
עכשיו מה קורה?
המבנה הראשון שנרצה להבין הוא:
sorted(rep_dict,key=len,reverse=True)
rep_dict
זה המילון שהעברנו כפרמטר שני לפונקציה ולכן הפונקציה מחזירה את:
['o', 'l', 'e']
בעברית נגיד שהיא לוקחת את כל המפתחות במילון וממיינת אותם לפי אורך. במקרה שלנו זה קל כי כל המחרוזות באותו אורך אבל במקרים יותר מורכבים אם המפתחות באמת היו מילים באורכים שונים היינו מקבלים את המילים הארוכות בהתחלה ואז ממשיכים למיין לפי האורך בסדר יורד.
החשיבות של זה תהיה ברורה כשנראה איפה משתמשים במילון. אני מרחיב את השורה ומסתכל עכשיו על:
"|".join([re.escape(k) for k in sorted(rep_dict,key=len,reverse=True)])
בשביל שיהיה יותר קל להסתכל אני מוריד בינתיים את הפקודה re.escape
ומסתכל על הקוד כאילו היה כתוב שם:
"|".join([k for k in sorted(rep_dict,key=len,reverse=True)]),
הפקודה join מחברת אלמנטים במערך ויוצרת מהם מחרוזת אחת ארוכה וכשאני ממשיך עם אותו מילון שהעברתי קודם אני יכול לראות שהתוצאה היא עכשיו:
>>> rep_dict = { 'o': '0', 'l': '1', 'e': '3' }
>>> "|".join([k for k in sorted(rep_dict,key=len,reverse=True)])
'o|l|e'
כלומר קיבלתי ביטוי רגולרי שמורכב מ-3 המחרוזות שהעברתי בתור מפתחות למילון מופרדות בסימן |
. סימן זה אני מזכיר מציין ״או״ בביטויים רגולריים. חיבור מספר מחרוזות באמצעותו מייצר ביטוי רגולרי שיתאים או ל o, או ל l או ל e.
עכשיו אפשר להתקדם לשורה השניה בפונקציה:
return pattern.sub(lambda x: rep_dict[x.group(0)], string)
השורה תרוץ על הביטוי ותחפש דברים שמתאימים לו, במקרה שלנו את האות o, האות l או האות e. כל פעם שהיא מוצאת התאמה היא תחליף את ההתאמה שמצאה בדבר שמתאים לה מתוך המילון המקורי. הפניה לקבוצה 0 אומרת שאנחנו מסתכלים על המילה שנמצאה (בדרך כלל היית רואה group כשיש בביטוי סוגריים ואז המספור מתחיל מ-1).
האם זה עוזר? אם כן אני שולח אותך להמשיך לשחק עם זה כדי לענות על שתי שאלות:
-
למה הם סידרו את המילים לפי האורך בסדר יורד? מה היה קורה בלי כזה סידור? יכול לתת דוגמא לקלט שעבורו הקוד נכשל כשאין את המיון?
-
מה עושה הפקודה
re.escape
? למה צריך אותה? יכול לתת דוגמא לקלט שנכשל בלעדיה?
זה טוב לקבל כיוונים מהרשת ולחפש קודים שעוזרים לך. חשוב גם לדבר עליהם אחרי שאתה מוצא וכן להבין אותם עד האות הקטנה ביותר. אני כאן ושמח לעזור בזה.