טיפ רובי - החלפת טקסט מתוך Hash

24/02/2025

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

1. המקרה הפשוט

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

> 'hello big world'.gsub(/ /, '-')
 => "hello-big-world"

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

 > 'hello big world...'.gsub(/\W/, {' ' => '-', '.' => '!'})
 => "hello-big-world!!!"

2. החלפת טוקנים

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

3.1.1 :034 > text = 'name: {{name}}, email: {{email}}, phone: {{phone}}'
 => "name: {{name}}, email: {{email}}, phone: {{phone}}"
3.1.1 :035 > data = {'{{name}}' => 'ynon', '{{email}}' => 'testmail', '{{phone}}' => '0521111111' }
 => {"{{name}}"=>"ynon", "{{email}}"=>"testmail", "{{phone}}"=>"0521111111"}
3.1.1 :036 > text.gsub(/{{\w+}}/, data)
 => "name: ynon, email: testmail, phone: 0521111111"

3. מה עוד אפשר

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

data = {'name' => 'ynon', 'email' => 'testmail', 'phone' => '0521111111' }
 => {"name"=>"ynon", "email"=>"testmail", "phone"=>"0521111111"}

במצב כזה אפשר להפעיל map כדי לשנות את שמות המפתחות ואז to_h כדי לחזור ל Hash, אבל אולי יותר קל לתקן את הביטוי הרגולארי. בעזרת Lookarounds אני יכול לכתוב ביטוי שיחפש את סימני הסוגריים המסולסלים הכפולים אבל לא "יתפוס" אותם וכך ההתאמה תהיה רק מול המילה עצמה (name, email או phone):

3.1.1 :044 > text.gsub(/(?<={{)\w+(?=}})/, data)
 => "name: {{ynon}}, email: {{testmail}}, phone: {{0521111111}}"