How to extract text from HTML

איך ניתן לחלץ טסקט מתוך HTML

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

כשניגשתי למשימה, בניגוד לרגיל, לא קבעתי לעצמי מראש מה בדיוק קטע הקוד שאני כותב אמור לעשות, במקום זה התחלתי ממה שהוא וודאי אמור לעשות, ואז שיפרתי עד שקיבלתי את התוצאה שרציתי. בגדול, מה שהפונקציה צריכה לעשות הוא לדלג על כל הקטעים בתוכן שנמצאים בין התו < לבין התו > שאלו הם התגים לדוגמה ב: '<span dir="rtl">abc</span>' יישאר רק 'abc'.

ככל שהתקדמתי בכתיבת הקוד והרצת בדיקות מולו, גיליתי שיש בעיות נוספות שעלי לפתור על מנת להגיע להמרה איכותית. עוד...

קטגוריות: .NET

שימושיות ואבטחה בLogout

השאלה המתבקשת היא: זה Logout, מה כבר יכול להשתבש?! - אז מסתבר שלא מעט. מדובר בדברים פשוטים וברורים מאליהם עד כדי כך, שפשוט לא חושבים עליהם.

את לינק היציאה (או logout) תמצאו ברוב האתרים על הMasterPage. הלינק מוצג רק למשתמשים שמזוהים באתר ע"י ביצוע כניסה (או login), שכן רק עבורם שייכת פעולה זו. השאלה המעניינת היא, מה מתרחש כשלוחצים על הלינק?

ניתן לממש logout בכמה דרכים:

  • כמטפל לאירוע הClick בCode Behind של הMasterPage עצמו.
  • ע"י הפנייה לדף מיוחד (נקרא לו Logout.aspx) שכל מטרתו היא לבצע logout.

בשני המקרים מתחילים מקריאה למתודה FormsAuthentication.SignOut() שמבצעת עבורנו את השמדת העוגיות וכדו'. עד כאן הכל פשוט. הבעיה מתעוררת בדף שיוחזר למשתמש.

במקרה של מימוש ע"י מטפל אירוע Click בMasterPage יש שתי בעיות פוטנציאליות:

  1. מטפלי האירועים מבוצעים בשלב מאוחר במחזור חיי הדף. ולכן, תכנים רבים שאמורים להיות מוצגים רק למשתמשים מזוהים, עדיין יוצגו בדף בפעם הראשונה שהדף ייטען לאחר הlogout.
  2. היות ומדובר בMasterPage, ייתכן שהדף שממנו בוצע הlogout נגיש למשתמשים מזוהים בלבד. כתוצאה, לאחר הlogout המשתמש יוקפץ מיידית לדף הכניסה (או login)!!

על אף שלכל אחת מהבעיות הנ"ל קיימים פתרונות פשוטים, אני בחרתי בדרך השנייה: הפנייה לדף נפרד שכל מטרתו היא ביצוע logout. עוד...

קטגוריות: .NET
תגיות: ,

שימוש בWeb.sitemap לשמירת מידע SEO

מפת אתרכולם מכירים את הSiteMap בתור מפת אתר עבור מנגנון הניווט של ASP.NET. אבל, מה אם היה אפשר להוציא ממנו יותר?

במאמר זה אדגים שימוש בWeb.sitemap לשמירת תכנים עבור תגיות המטא description וkeywords. גישה זו תאפשר ניהול נוח של מידע meta של האתר, תוך הפרדה מוחלטת בין לוגיקה ומידע.

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

קטגוריות: .NET
תגיות: , , , ,

הכירו את IIS URL Rewrite 2.0

URL Rewriteתהיתם פעם איך ניתן לשפר את חווית המשתמש ודירוגו של אתר קיים בנועי החיפוש בלי לבצע שינויים נרחבים לאתר כולו? איך לשמר כתובות ישנות של דפים שלאחר שדרוג עברו לכתובת חדשה בלי לזהם את הקוד החדש במידע אודות הכתובות הישנות?

הכירו את IIS URL Rewrite 2.0! בשונה מהגרסה הקודמת, שידעה בעיקר לתרגם כתובות מתחת לפני השטח, הגרסה החדשה מהווה חבילת פתרונות שיכתוב וניתוב עשירה עם ממשק ניהול מוטמע בממשק הIIS. כעת, נדרשים רק קליקים ספורים כדי לבצע פעולות שיכולות לשדרג משמעותית את האתר, הן עבור הגולשים – שיקבלו כתובות URL הגיוניות, והן מבחינת מנועי החיפוש ע"י ביטול תוכן כפול, והכנסת מילות מפתח לURL עצמו. עוד...

קטגוריות: .NET | .NET 4.0 | IIS | Tools

איך ניתן לבדוק האם המחרוזת היא עברית?

לפעמים כשאנחנו שולפים טקסט מהמסד נתונים אנו מוצאים את עצמינו מתלבטים האם להציג אותו בדף כltr או כrtl.

כמובן, ניתן לבדוק:

אבל כל זה עדיין לא ייתן מענה למחרוזות מעורבות כדוגמת אלו:

  • האות הראשונה בא"ב האנגלי היא 'a'.
  • 'a' היא האות הראשונה בא"ב האנגלי.
  • the first latter of the hebrew abc is 'א'.
  • 'א' is the first latter of the hebrew abc.

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

הסיבוכיות של האלגוריתם קטנה מO(n) שכן, הוא מסתיים ברגע שניתן להוכיח רוב תווים לצד זה או אחר, לדוגמה במחרוזת "אבגab" התוים "ab" כלל לא ייבדקו כי גם אם הן לא עבריות המחרוזת כבר מוכחת כעברית.

המתודה:

 public  static  bool  IsHebrewString(this  string  value)
 {
     int  balance = 0;
     int  firstLetter = 0;
 
     for  (int  i = 0; i < value.Length; i++)
     {
         if  (char .IsLetter(value[i]))
         {
             if  ((value[i] >= (char )0x5D0) && (value[i] <= (char )0x5EA))
                 balance++;
             else 
                 balance--;
 
             if  (firstLetter == 0)
             {
                 firstLetter = balance > 0 ? 1 : -1;
             }
         }
 
         if  ((value.Length - (i + 1)) < Math .Abs(balance))
             break ;
     }
 
     if  (balance == 0)
         return  firstLetter > 0;
 
     return  balance > 0;
 }
 

הנה כמה דוגמאות ליעילות האלגוריתם:

 bool  test1 = "האות הראשונה בא\"ב האנגלי היא 'a'." .IsHebrewString(); // true 
 bool  test2 = "'a' היא האות הראשונה בא\"ב האנגלי." .IsHebrewString(); // true 
 bool  test3 = "the first latter in hebrew abc is 'א'." .IsHebrewString(); // false
 bool  test4 = "'א' is the first latter in hebrew abc." .IsHebrewString(); // false 
 bool  test5 = "אבגabc" .IsHebrewString(); // true 
 bool  test6 = "abcאבג" .IsHebrewString(); // false 
 bool  test7 = "()!^." .IsHebrewString(); // false 
 
קטגוריות: .NET | .NET 4.0 | Tools

חישוב גודל התגיות ב"ענן תגיות"

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

מה שחסר כאן זה ניסוח מתמטי פשוט:

Untitled-2_1

  • score -  הוא ערך "הניקוד" של התגית
  • minScore – הוא הערך של הניקוד הקטן ביותר שקיים
  • maxScore - הוא הערך של הניקוד הגבוה ביותר שקיים
  • minSize – הוא הערך של הפונט הקטן ביותר שתרצה להציג (הוא יוצב לתגית בעלת הניקוד הנמוך ביותר)
  • maxSize - הוא הערך של הפונט הגדול ביותר שתרצה להציג (הוא יוצב לתגית בעלת הניקוד הגבוה ביותר)

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

הקוד הבא הוא מימוש של המשוואה הזו בC# 4.0: (לVS2008 ראה בהמשך)

 public  static  double  CalculateTagSize(double  score, double  minScore, double  maxScore, double  minSize, double  maxSize)
 {
     Contract .Requires<ArgumentOutOfRangeException >(minScore < maxScore, 
         "minScore must be smaller than maxScore." );
     Contract .Requires<ArgumentOutOfRangeException >(minSize < maxSize, 
         "minSize must be smaller than maxSize." );
     Contract .Requires<ArgumentOutOfRangeException >(score > minScore && score < maxScore, 
         "score must be greater than minScore and smaller than maxScore." );
 
     return  minSize + ((maxSize - minSize) * (score - minScore)) / (maxScore - minScore);
 }

בVS2008 של ניתן לעשות את הבדיקות באמצעות הContracts אז נשתמש במשפטי if וזריקת חריגות:

 public  static  double  CalculateTagSize(double  score, double  minScore, double  maxScore, double  minSize, double  maxSize)
 {
     if  (!(minScore < maxScore))
         throw  new  ArgumentOutOfRangeException ("minScore must be smaller than maxScore." );
     if  (!(minSize < maxSize))
         throw  new  ArgumentOutOfRangeException ("minSize must be smaller than maxSize." );
     if  (score < minScore || score > maxScore)
         throw  new  ArgumentOutOfRangeException ("score must be greater than minScore and smaller than maxScore." );
 
     return  minSize + ((maxSize - minSize) * (score - minScore)) / (maxScore - minScore);
 }

תיוג נעים לכולכם…

קטגוריות: .NET | .NET 4.0
תגיות: ,

העברת נתונים בין אפליקציית Flash לASP.NET באמצעות LoadVars

מסתבר, שאחת הדרכים המוכרות והפשוטות ביותר לשליחת וקבלת מידע ע"י פלאש היא באמצעות המחלקה LoadVars של ActionScript. למעשה, המימוש של LoadVars דומה יותר לטעינת קובץ מקומי מאשר למימוש תקשורת על גבי פרוטוקול HTTP, כשהקשר היחיד ביניהם הוא אירוע onHTTPStatus, שמחזיר את קוד המצב של הHTTP כשזה משתנה.

המחלקה LoadVars מסוגלת לבצע שאילתות GET וPOST, ולקבל נתונים בפורמט application/x-www-form-urlencoded שזה בעצם אותו פורמט הנתונים שמשמש אותנו למסירת פרמטרים בURL, וכן להעברת תגיות הFORM על גבי פרוטוקול HTTP בשאילתות POST. המעלה הברורה כאן היא הפשטות, כשהחיסרון, הבולט לא פחות, הוא הצורך לקודד הכל ובכך להכפיל את כמות התעבורה ברשת. חיסרון נוסף הוא היעדר אפשרות מובנית לביטוי הירארכיה (כמו JSON או XML), אך זה ניתן לתיקון ע"י יצירת פורמט נתונים מותאם אישית. אך לא על זה באתי לדבר.

במאמר הזה באתי לתאר פתרון שכתבתי לצורך תקשורת יעילה בין אפליקציית Web בASP.NET לבין אפליקציית Flash באמצעות המחלקה LoadVars. עוד...

קטגוריות: .NET | Flash | AspNetFlashExtensions
תגיות: , ,

Validator עבור שדות תאריך לידה

(Birth date fields validator)

נשאלה השאלה, איך אני מאגד את שלשת השדות של תאריך הלידה (יום, חודש ושנה) לערך אחד עבור ואלידציה (Validation)?

במצב הקיים, צריך להשתמש בשלש ואלידאטורים (Validators) מסוג RequiredFieldValidator ועוד 3 מסוג RangeValidator עבור טווח הערכים (למשל ימי החודש הם מ1 עד 31), וכל זה עדיין לא יעזור אם נרצה לבדוק טווח עבור כל התאריך בשלמות ולא עבור כל חלק שלו בנפרד. לפתרון לבעיה זו כתבתי WebControl שיורש מ – BaseCompareValidator בשם DateFieldsValidator.

DateFieldsValidator פותר את כל הבעיות שהזכרתי,

  • מכיל מאפיינים עבור 3 שדות (גם TextBoxים וגם DropDownListים ובעצם, כל דבר שנתמך ע"י הואלידאטורים הסטנדרטיים) אחד עבור כל חלק בתאריך
  • מכיל מאפיינים MinimumValue וMaximumValue לבדיקת טווח עבור התאריך בשלמותו.
  • לא תלוי בCulture מסויים (CultureInvariant).
  • מבצע וולידציה הן בצד לקוח (ללא רענון הדף), והן בצד שרת (במקרה שJavaScript מבוטל או לא נתמך בלקוח).
  • וכן תומך גם בכל הפיצ'רים האחרים של פקדי הואלידאציה הסטנדרטיים בFramework. עוד...
קטגוריות: .NET
תגיות: ,

טעינה של Xhtml דרך XmlDocument

במאמר זה נביא מספר טיפים לשימוש במחלקות ממרחב שמות System.Xml מול תוכן Xhtml. וכן פתרונות לבעיות תאימות בין התקנים. הבעיות שנסקור כאן הם: איך לגרום לקורא Xml לא להתעלם מרווחים בין התגים, ואיך לקצר את זמן הטעינה על ידי דילוג על Validation מול www.w3.org.

דבר ראשון, נשים לב לבעיה קטנה שתצוץ בכל פעם שננסה לפתוח תוכן Xhtml ע"י מחלקות ממשפחת System.Xml, כל הרווחים שבין התגים ייעלמו לדוגמה השורה הבאה: עוד...

קטגוריות: .NET
תגיות: , ,

אזורי זמן ושעון קיץ: פתרונות מעשיים

במאמר הזה נציע מספר פתרונות מעשיים למקרים בהם צריך להציג שעה מסוימת למשתמשים באזורי זמן שונים.

ניקח לדוגמה מערכת פורום. דוד, מזין הודעה בשעה 13:00 ממחשב בישראל (GMT +2), אלי שגר באנגליה בגריניץ' (GMT) יראה בשעה 11:00 אצלו את ההודעה שזה עתה נוספה לפורום - בעוד שעתיים בשבילו. זה יקרה במקרה שהשרת כשירשום את ההודעה למסד הנתונים, יצרף אליה את שדה "שעת יצירה" לפי שעון ישראל. למרות שגם אם השרת ירשום את השעה לפי שעון גריניץ' עדיין תהיה אי נוחות לדוד לראות שהודעתו צורפה שעתיים לפני שהוא צירף אותה בפועל.

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

קטגוריות: .NET