none
Is there a way to programmatically get Unicode character classification for a given character ? RRS feed

  • שאלה

  • נושא הוא כיווניות של טקסט ויכולת לברר כיווניות של אות (לפי הגדרת הUnicode).

    הדבר מאוד פשוט להשיג בJava:

    String str = "hello world";
    String dir = "";
    for (int i = 0; i < str.length(); i++) {
    	byte directionality = Character.getDirectionality(str.charAt(i));
    	if (directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT
    			|| directionality ==    
                                   Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) {
    				dir = "RTL";
    				break;
    	} else if (directionality == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
    				dir = "LTR";
    				break;
            }
    }
    


    אך בMicrosoft אני לא מצאתי כלים מתאימים.

    יום שלישי 11 פברואר 2014 11:13

תשובות

  • אתה יכול להכין מתודה זהה של getDirectionality שתבדוק את הכיווניות בכמה דקות. אתה יכול לכתוב הרחבה למחלקה של STRING אם אתה רוצה שתכלול את המתודה הזו. כל מה שצריך זה להכין רשימה מסודרת או רשימת תווכים של כל התווים של השפות שהן RTL ולבצע בדיקה כשרוצים בעזרת מתודה getDirectionality. זה לא אמור להיות משהו שלוקח יותר מכמה דקות להערכתי.

    * אני לא מכיר משהו מובנה והזמן לכתוב קצר יותר מלחפש בגוגל אני חושב (אם יודעים איזה תווים שייכים לשפות RTL תחילה).


    [Personal Site] [Blog] [Facebook]signature

    • נערך על-ידי pituachMVP, Moderator יום שלישי 11 פברואר 2014 14:25
    • סומן כתשובה על-ידי Eran Sharvit יום ראשון 16 פברואר 2014 12:49
    יום שלישי 11 פברואר 2014 14:16
    מנחה דיון

כל התגובות

  • אתה יכול להכין מתודה זהה של getDirectionality שתבדוק את הכיווניות בכמה דקות. אתה יכול לכתוב הרחבה למחלקה של STRING אם אתה רוצה שתכלול את המתודה הזו. כל מה שצריך זה להכין רשימה מסודרת או רשימת תווכים של כל התווים של השפות שהן RTL ולבצע בדיקה כשרוצים בעזרת מתודה getDirectionality. זה לא אמור להיות משהו שלוקח יותר מכמה דקות להערכתי.

    * אני לא מכיר משהו מובנה והזמן לכתוב קצר יותר מלחפש בגוגל אני חושב (אם יודעים איזה תווים שייכים לשפות RTL תחילה).


    [Personal Site] [Blog] [Facebook]signature

    • נערך על-ידי pituachMVP, Moderator יום שלישי 11 פברואר 2014 14:25
    • סומן כתשובה על-ידי Eran Sharvit יום ראשון 16 פברואר 2014 12:49
    יום שלישי 11 פברואר 2014 14:16
    מנחה דיון
  • דוגמא לאיך לעשות זאת בWin32:

    LOCALP(BOOL) is_ltr_char( char c ) 
    {
    	WORD charType;
    	char buf[] = {c};
    	GetStringTypeA (LOCALE_SYSTEM_DEFAULT, CT_CTYPE2, buf, 1, &charType);
    
    	return C2_LEFTTORIGHT == charType;
    }
    
    STDEXPORTP(BOOL) is_rtl_char( char c ) 
    {
    	WORD charType;
    	char buf[] = {c};
    	GetStringTypeA (LOCALE_SYSTEM_DEFAULT, CT_CTYPE2, buf, 1, &charType);
    
    	return C2_RIGHTTOLEFT == charType;
    }

    כל מה שלא LTR וגם לא RTL נחשב לNEUTRAL כגון סימני פיסוק וכו'.

    אני לא בטוח עד כמה שיטה זו מדויקת לגבי ספרות ערביות. בכל מקרה Win32 היא רמה נמוכה מדי עבור ישום ב.NET.

    יום שלישי 11 פברואר 2014 16:21
  • אתה עושה שימוש בפונקציה שהיא Deprecated. ההמלצה של מייקרוסופט היא לעשות שימוש בפונקציות GetStringTypeW וכן GetStringTypeEx.

    בכל מקרה לא הייתי פונה לכיוון כזה בכלל בטכנולוגיית דוט-נט אלא כותב מתודה שלי שממפה את התווים ישירות, כפי שכתבתי מעל. זה היה נותן לי 100% ביטחון לכל שפה. פשוט ממפים את התווים ואם תקלה מתקנים אותה. לא תמיד צריך להשקע לחפש דברים מוכנים אם פיתוח לבד יכול להיות יותר מהיר ולתת לנו תוצאות זהות או יותר טובות למקרה המסויים שלנו :-)
    לדוגמה, הרבה פעמים מחלקות מוכנות עושות שימוש באפשרויות רבות ואנחנו צריכים למשל מתודה מסויימת בלבד. במקרים כאלה כדאי לחשוב אם לא כדאי לעבוד עם מחלקה שלנו. דוגמה ספציפית היא שימוש במתודה SPLIT בעבודה עם SQL CLR, זו מתודה טובה שמגיע כחלק ממחלקה מורכבת, אבל בפיתוח לבד אפשר לפתח מתודה הרבה יותר יעילה לשימוש תחת SQL וSET בכלל (אדם מקרניק מציג כתב דוגמה של מתודה כזו).


    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 11 פברואר 2014 16:54
    מנחה דיון
  • אכן מימוש טיפה יותר מלא ומומלץ הוא כדלקמן:

    STDEXPORTP(BOOL) bIsRightToLeftTextDir(LPCSTR lpString, WORD wCurrentTextDirection)
    {
    	if (wCurrentTextDirection == 0) 
    		wCurrentTextDirection = lpA->wTextDirection;
    					
    	if ((lpString == NULL) || (wCurrentTextDirection != CONTEXTUAL_TEXT_DIRECTION))
    		return (wCurrentTextDirection != LTR_TEXT_DIRECTION);
    	else
    	{
    		int i,iLen = strlen(lpString);
    		for (i = 0; i < iLen; i++) 
    		{
    			if (is_ltr_char(lpString[i]))
    				return FALSE;
    			else if (is_rtl_char(lpString[i]))
    				return TRUE;
    		}
    		return FALSE;
    	}
    }
    
    LOCALP(BOOL) is_ltr_char( char c ) 
    {
    WORD charType;
    char buf[] = {c};
    GetStringTypeEx (LOCALE_SYSTEM_DEFAULT, CT_CTYPE2, buf, 1, &charType);
    
    return C2_LEFTTORIGHT == charType;
    }
    
    STDEXPORTP(BOOL) is_bidi_char( char c ) 
    {
    WORD charType;
    char buf[] = {c};
    GetStringTypeEx (LOCALE_SYSTEM_DEFAULT, CT_CTYPE2, buf, 1, &charType);
    
    return C2_RIGHTTOLEFT == charType;
    }
    
    

    מיפוי ידני של אותיות בוודאות לא הדרך. המיפוי הוא תלוי בUnicode סטנדרט שמתשנה ובכל מקרה מהווה מאגר עצום - מספר MB של טבלאות טקסט - אנא תסתכל כיצדCharacter.getDirectionality ממומש בJava. שום בית תוכנה רציני לא צריך להמציא גלגלים. קודם כל כיוון שזה עולה כסף רב להמציא בפעם ראשונה  וגם בגלל שזה עולה עוד יותר לתחזק אותו לאורך הזמן :-)).

    אני הייתי מצפה שהדבר אפשרי בMicrosoft מבחינת API כיוון פנימית הם תומכים בכיוון טקסט Contextual או FirstStrong או Auto:

    א. Windows Phone 8  - התנהגות ברירת מחדל של כל שדה קלט

    ב. Outlook  - אופציה של קונפיגורציה (LTR או RTL או Contextual).

    יום שלישי 11 פברואר 2014 18:59
  • או רשימת תווכים של כל התווים של השפות שהן RTL

    שוב פעם תומר אני לא מבין מהיכן אתה מביא את הנתונים שלך שהן לחלוטין לא נכונים.

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

    גם בשביל לשמור את כל התווים אפשר לבצע זאת בצורה פשוטה (אם זה, הרי שזה לא מה שהצעתי וזה לא יעיל).

    בחישוב גס מאוד ולא מדוייק אולי, על פי הבנתי UNICODE מאפשר עבודה עם 17 תוכניות של 65,536 תווים אפשריים (code points) זה נותן לנו בסך הכל 1,114,112 תווים אפשריים תיאורטית. נכון לרגע זה יש אולי שימוש ב 10% מכמות זו. UTF-8 מאפשר יותר תוכניות אבל חייב לעמוד בחוקיות שלמגבילה אותו בסיום לאותו סדר גודל.

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

    UTF-8 עושה שימוש בבייט בודד עד 4 בייטים, מה שאומר ששמירה של 2 נתונים עבור תווך ערכים מסויים מצריך בסך הכל 8 בייט! (UTF-32 מצריך יותר מקום מכיוון ששומר 4 בייטים תמיד).

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

    אני שמח שקיבלת את ההצעה שלי לעבוד לשימוש ב GetStringTypeEx, הקוד האחרון שלך ניראה יותר טוב לדעתי ואמור לתמוך יותר טוב גם במערכות חדשות יותר (לא הרצתי אותו, אבל במבט כללי הוא עושה רושם טוב).

    הערה: אתה ממהר מאוד למצוא פתרונות native. זה דווקא ייתרון בדרך כלל ויכול להוביל למיטוב העבודה, אבל (1) פחות מתקשר לפורום של C#, כמו כן (2) מעלה אצלי  השאלה למה לא לפתח ב C++ אם זה יותר מוכר לך (שאלה שאתה צריך להיתמוד איתה כמובן ולא אנחנו). כשיש את היכולת לעבוד בטכנולוגיות/שפות שונות האפשרויות כמובן עולות וניתן להגיע לפתרונות נוספים מחוץ לסקופ הפשוט של שפה מסויימת.

    * לגבי הצעת הייעול או הערת הייעול, אתה יכול לפתוח CONNECT לגבי השיפורים שאתה רוצה. מה גם שאף אחד לא אמר שזה לא קיים (אני אמרתי שאני לא מכיר... יש הרבה דברים שאני לא מכיר, ועדיין קיימים).
    http://connect.microsoft.com

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

    בהצלחה בפרוייקט :-)

    אתה מוזמן לפרסם את התובנות שלך בסיום בבלוג מסודר :-)


    [Personal Site] [Blog] [Facebook]signature

    • נערך על-ידי pituachMVP, Moderator יום רביעי 12 פברואר 2014 09:03
    • הוצע כתשובה על-ידי Eran Sharvit יום רביעי 12 פברואר 2014 11:23
    יום רביעי 12 פברואר 2014 08:12
    מנחה דיון
  • מה שאותי מעניין, זה כמה שפות RTL יש?!?

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


    [Personal Site] [Blog] [Facebook]signature

    יום רביעי 12 פברואר 2014 16:43
    מנחה דיון
  • יש כמה שפות... http://en.wikipedia.org/wiki/Right-to-left

    רובם חסרי חשיבות (אופ סליחה אם אני מעליב לאום כל שהוא).


    • נערך על-ידי לומדים יום רביעי 12 פברואר 2014 18:21
    יום רביעי 12 פברואר 2014 18:19
  • תודה :-)

    18 שפות אם ספרתי נכון (לפי מה שאני רואה חלקן סתם שפות סיפרותיות ולא פעילות) אבל טוב לדעת סדר גודל.

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


    [Personal Site] [Blog] [Facebook]signature

    יום רביעי 12 פברואר 2014 18:28
    מנחה דיון