January 12, 2006

הגיע לפלאש Regular Expressions

As3 תומכת ב-Regular expressions (מעתה: regex) בואו נתחיל מזה.
יש למפתחים עכשיו מחלקה שלמה שכל יעודה הוא לטפל בתבניות מחרוזתיות, העונה לשם RegExp, ואפילו לא צריכים לייבא אותה במיוחד, היא כבר פה לשימוש מיידי.
החלטתי לכתוב על הנושא מאחר וזו מחלקה מאוד שימושית ולדעתי ראוי שכל מפתח פלאש יהיה מודע לקיומה בגרסה הנוכחית ולאפשרויות הטמונות בה.

מה זה regex?
זו למעשה תבנית חיפוש על מחרוזות, אבל משודרגת. לא, לא מדובר בפעולה הפשוטה של splite(),join() שלא ממש נותנת אפשרויות כמו שימוש ב-wildcards . את התבניות הללו ניתן לנצל בשלוש מתודות משמעותיות של המחלקה String:



replace ()
match ()
search ()

בכל אחת מהמתודות הללו ניתן לתת regex כתבנית אותה מחפשים, בין אם לשם החיפוש בלבד, להתאמה או להחלפה.

מה הקטע?
למעשה, מגדירים משתנה שהוא מופע של RegExp ובתוכו מציבים שני פרמטרים:
1. re (regular expression), שזו למעשה התבנית אותה אנו מחפשים.
2. flags, שהם למעשה מייצגים את החוקיות בחיפוש.

מאוחר יותר נשתמש במופע התבנית שיצרנו בתוך אחת מהמתודות של String המצויינות לעיל. הדוגמה הכי בסיסית היא לחפש אם במחרוזת מסויימת מופיעה האות “a”. שימו לב לשימוש ב-flag "i” בכדי לבטל את ה-case sensitivity:



var a_re:RegExp = new RegExp ("A", "i");
var my_str:String = "Chuck Norris ate pizza last night";
trace (my_str.search(a_re)); // Displays 13


כמו indexOf() אנחנו נקבל את האינדקס של התו הראשון שנמצא מתאים, אם אין התאמה בכלל, אנחנו נקבל 1-. כלומר, שאם נוריד את ה-flag של “i”, אנחנו נקבל 1- מפני שאין "A” במחרוזת:



var a_re:RegExp = new RegExp ("A");
var my_str:String = "Chuck Norris ate pizza last night";
trace (my_str.search(a_re)); // Displays -1


יגידו הספקנים "אבל זה בקטנה, זה", ויצדקו. אין כאן שום יכולת מיוחדת, אבל!
בהגדרת התבנית ניתן לשלב תוים אשר מבצעים פעולות יותר מורכבות מסתם חיפוש תו. אפשר להגדיר את התבנית לטוח של תוים, או לתו מסויים רק אחרי שבא לפניו לפחות תו אחד וכיו"ב. האפשרויות כיד הדימיון ויותר חשוב מכך, כיד הצורך.
כך למשל נוכל לבנות תבנית עבור כל התוים בין a ל-z, ולהעביר לפונקציה התטפל ב-replace שלהם. אם נעבור על כל הארגומנטים שהיא מקבלת, ששיכים ל-String (שימו לב למילה is המחליפה את instanceof) אז נראה את כל ההתאמות:



protected function test ():Void {
var atoz_re:RegExp = new RegExp ("[a-z]");
var my_str:String = "abc1234 ~! sd 243 ^$4 a";
var result:String = my_str.replace (atoz_re, replace);
}
protected function replace ():String {
for (var item in arguments) {
if (arguments[item] is String) {
trace (arguments[item]);
}
}
}

// displays
a
abc1234 ~! sd 243 ^$4 a
b
abc1234 ~! sd 243 ^$4 a
c
abc1234 ~! sd 243 ^$4 a
s
abc1234 ~! sd 243 ^$4 a
d
abc1234 ~! sd 243 ^$4 a
a
abc1234 ~! sd 243 ^$4 a


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



public function RegularExpressionExample() {
trace ("Match:", matchString ("mymail@mymail.co.il"));
// Valid
trace ("Match:", matchString ("@mymail.co.il"));
// NOT Valid
trace ("Match:", matchString ("aaaaaamymail.co.il"));
// NOT Valid
trace ("Match:", matchString ("aaaaaa@my.co.il"));
// NOT Valid
trace ("Match:", matchString ("aaaaaa@micdl.a"));
// NOT Valid
}
// -----
protected function matchString (stringToMatch:String):Boolean {
var mail_re:RegExp = new RegExp ("^.+@[a-z]{3,}\..{2,}$", "i")
var results:Array = stringToMatch.match(mail_re)
if (results == null) {
return false
} else {
return true;
}
}


נחמד, לא?
משם זה יכול להמשיך לוולידציות ל-IP, מספרי כרטיס אשראי וכיו"ב.

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

2 comments:

gadi said...

אכן כלי חזק. אני מניח שהוא הגיע רק בשלב זה לפלאש בעקבות המעבר ל-AVM2. כבר יצא לי מספר פעמים להתקע עם הודעת "player is running slow" אחרי parsing וחיפוש על מחרוזות של 20 תווים...

FlashMattic said...

אני לא חושב שה-AVM2 אחראי לשינוי, אלא יותר השאיפה להיות ECMA-4 מצד as.
ה-AVM2 הופך את זה ליעיל הרבה יותר, ללא ספק.