איך לייעל פונקציית ריפלייס בדוט נט
-
כאשר אני מחפש מחרוזת ורוצה להחליף אותה בתוצאה של פונקציה למשל, הוא קודם כל מריץ את הפונקציה כדי לקבל ממנה את המחרוזת המבוקשת, ורק אחר כך בודק האם המחרוזת שלי מכילה את הטקסט המבוקש, מה שקורה שאם היא לא מכילה, הפונקציה עבדה סתם!
הנה דוגמא:
public static void tryfunc() { string str = "ירושלים"; str.Replace("בני ברק", Mystr()); } static string Mystr() { MessageBox.Show("שלום"); return "נתיבות"; }
אני לא אמור לראות את המסג' בוקס "שלום" למיטב הבנתי. האם יש פתרון חלק ופשוט לזה?
פורסם במקור בפורום CODE613 ב22/01/2015 11:52 (+02:00)
-
נכון מאוד, והסיבה היא בגלל שחתימת הפונקציה Replace מקבלת שתי ארגומנטים מסוג סטרינג, וממילא בשביל הפעלת הפונקציה Replace מופעלת הפונקציה Mystr() כדי לקבל את הסטירנג להעברה כארגומנט המתאים.
במילים אחרות, אם היינו רוצים שהפונקציה לא תופעל עד שיהיה בה צורך היינו צריכים להעביר אותה כפונקציה ולא כסטרינג. תוכל לממש שוב את הפונקציה Replace ולשנות/להוסיף/להעמיס בחתימתה קבלת פונקציה (למשל הטיפוס Func<String>), וכמובן זה גרוע מאוד אם תעשה ככה בכל צומת בדרכך שתהיה שם בעיית ביצועים קלה.
אתה יכול לבדוק עם IndexOf שהמופע נמצא ורק אם כן להפעיל את הפונקציה, אבל הרי גם הפונקציה לצערינו תפעיל את הפונקציה הזו שוב...
ולסיכום, הפרדת המטלות בצורה מודלרית מחייבת כפל בדיקות הכרוכים בחוסר יעילות מסויים. אתה חייב להרשות למחשב פה ושם לבצע דברים פעמיים סתם בשביל יופי חלוקת התפקידים.פורסם במקור בפורום CODE613 ב22/01/2015 13:05 (+02:00)
-
כן אני מסכים בעיקרון, אבל לפעמים לא מדובר על בעיות ביצועים, אלא על צפי לשגיאות, כשהטיפול בשגיאות הוא יותר "מלוכלך" מאשר להתעלם לגמרי מדבר שאני לא מצפה ממנו לרוץ.
הסיפור הוא שאני עושה מנוע תבנית אישי, עבור קבצי HTML שאני יוצר מהם מסמכים שונים, לכל מסמך HTML יש איפיון שונה לגמרי, אבל בשביל לערוך אותו אני מריץ את כל הריפלייסים שרק אפשר להעלות על הדעת, והתשובה מגיעה ממסד הנתונים. כאשר מסמכים מסויימים, אינם מכילים כל מידע אודות דברים שאינם קשורים אליהם (אני מתכוון לשאילתות שאנחנו עושים מול הדטה בייס) ואז במקום פשוט לדלג על זה, אני רואה שהוא מריץ את הכל וזה דורש הרבה יותר עבודה.
פורסם במקור בפורום CODE613 ב22/01/2015 13:11 (+02:00)
-
עיין פה.
https://github.com/magicode/NetFreeDataBase/blob/master/modules/mysql.js#L8
תראה שהוא עושה החלפה עם REGEX . הוא מחליף לפי שם כל מה שמתחיל ב :
לדוגמא.
אם אתה כותב :name
ואתה שולח לו מערך kay value.
אז הוא יחליף את כל מה שמופיע name הוא יחליף ב value שבמפתח name.פורסם במקור בפורום CODE613 ב22/01/2015 13:32 (+02:00)
-
אז אין מה לעשות, תפעיל לפני הביצוע תנאי אם indexOf > -1.
אבל לפי אופי הפעולה באמת אפשר לייעל את זה אחרת. לסרוק קודם את הטקסט ולמצוא בו את כל המופעים. אני מניח שהם מוקפים בסולמיות או משהו דומה, וקל למצוא את כולם בבת אחת ע"י REGEX. לסדר הכל ברשימה, להכין מילון שמכיל ערך יחודי מהרשימה ומה שאמור להחליף מהמסד, ואח"כ להחליף בלולאה כל אחד אחד מהמילון.
כך אתה חוסך את פעולות המסד אבל לא חוסך בביצועים (כי החיפוש יבוצע פעמיים: לצורך הידיעה ואח"כ לצורך ההחלפה).
בשביל להיות חסיד ביצועים עליך לפצל (לא באמת, בראש שלך) את המסמך לקטעים, כאשר הקטעים מורכבים מגוף המסמך, מפרידים, וערכים להחלפה. אח"כ למזג את הפיצולים בצורה טובה... (תוכל להציץ בעבודות של אחרים בשביל לקבל גישה. למשל מצאתי משהו שבנה פונקציית Format באופן שבמקום לתת {0} שזה טוקן מיקום אז לתת לו שם ככה: {Name} והפוקנציה יודעת למצוא מאפיין בשם Name באובייקט שינתן לה כארגומנט נוסף, ראה http://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx/ ).פורסם במקור בפורום CODE613 ב22/01/2015 13:33 (+02:00)
-
@דוד ל.ט.
במילים אחרות, אם היינו רוצים שהפונקציה לא תופעל עד שיהיה בה צורך היינו צריכים להעביר אותה כפונקציה ולא כסטרינג. תוכל לממש שוב את הפונקציה Replace ולשנות/להוסיף/להעמיס בחתימתה קבלת פונקציה (למשל הטיפוס Func<String>)
mat הביא אותי לבדוק שוב את דברי, ואכן יש בדיוק כזו פונקציה אבל לא בסטרינג כי אם בREGEX, הפונקציה נראית ככה:
Regex.Replace (text, find, m => MyStr(m.Value));
כאשר MyStr מקבלת ארגומנט סטרינג אחד ומחזירה את סטרינג בהתאם.
במקרה של mat יש לו מראש את הערכים ואז זה מתבצע בפשטות ע"י מילון:var dic = new Dictionary<string, string>(); dic["name1"] = "value1"; dic["name2"] = "value2"; dic["name3"] = "value3"; dic["name4"] = "value4"; Regex.Replace (text, find, m => dic[m.Value]);
אבל אם הבנתי את שאלתך, מילון לא יעזור כי אתה רוצה לחסוך בתשאול ערכים שאולי לא יידרשו.
לכן אתה צריך לבדוק את הערכים במהלך הפונקציה.פורסם במקור בפורום CODE613 ב22/01/2015 15:39 (+02:00)