עבור לתוכן

זיהוי קידוד הקובץ

Featured Replies

פורסם

צהריים טובים.

אני כותב עכשיו עורך טקסט (ב GTK+, שפת C) ואני נתקל בבעיה קשה - קידודים.

תיבת הטקסט של GTK+ מקבלת רק קידודי UTF-8, ולכן אני צריך להמיר כל קובץ שנפתח ל UTF-8.

זה פשוט מאוד: אני פותח קובץ, קורא את כל התווים שלו למחרוזת (שהוקצתה דינמית בהתאם לאורך הקובץ), ממיר את התווים ל UTF-8 וכותב אותם לתוך תיבת הטקסט.

כאן אני נתקל בבעיה: קובת בקידוד UTF-8 שמומר לקידוד UTF-8 עושה בעיות.

השאלה שלי היא איך אני יכול לדעת מה קידוד הקובץ (ובהתאם לכך לדעת האם להמיר את הקובץ) ?

אשמח מאוד לעזרה,

יוסף אור

פורסם

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

http://stackoverflow.com/questions/377294/howto-identify-utf-8-encoded-strings

שים לב לתשובה הראשונה, הוא נותן שם לינק להרבה חבילות (אני אישית לא מכיר חבילות כאלו, אז קשה לי להמליץ על משהו ספציפי).

חוץ מזה, שים לב שזה לא מובטח ב-100%...

פורסם
  • מחבר

תודה רבה על העזרה :-)

בסופו של דבר מצאתי את התשובה ממש מתחת לאף שלי:

אני משתמש בספרייה GTK+, ויש לה מספר ספריות נלוות, ובינם ספרייה בשם glib.

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

למשל: הפונקציה fopen של stdio.h לא מסוגלת לפתוח קובץ לפי נתיב מלא, אלא רק ממיקום קובץ הריצה.

לעומת זאת, הפונקציה g_fopen של glib יודעת לפתוח קבצים גם לפי נתיב מלא.

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

בינם יש פונקציות שעוסקות בקידודי קבצים.

הפונקציה הבאה מחזירה TRUE אם המחרוזת שנשלחה אליה היא בקידוד UTF-8, אחרת היא תחזיר FALSE.

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

gboolean g_utf8_validate(const gchar *str, gssize max_len, const gchar **end);

כאשר str צריך להצביע למערך תווים, max_len צריך להיות כמספר הבתים של אורך str או -1 אם str זה מחרוזת שמסתיימת ב NULL ו end הוא משתנה שלא הבנתי מה מטרתו.

TRUE ו FALSE הם קבועים שערכיהם 0 ו 1, בהתאם.

gboolean זה בעצם int,

gchar זה char

ו gssize זה signed long.

התיעוד של פונקציה זו: http://developer.gnome.org/glib/2.29/glib-Unicode-Manipulation.html#g-utf8-validate

הספרייה מומלצת מאוד שימוש במקום stdio, stdlib, malloc, string ושאר הספריות הסטנדרטיות של C.

ניתן להשיגה ב gtk.org.

אמנם אני אישית צריך גם פונקציה שמקבלת מצביע למבנה מסוג FILE ומחזירה TRUE אם הקובץ הוא קובץ טקסט או לא, ופונקציה שמחזירה מחרוזת המכילה את קידוד המחרוזת שהיא קיבלה, אבל זה עדיף מכלום (ואני מניח שיש פונקציות כאלה בספרייה glib).

מקווה שעזרתי למישהו שחיפש בגוגל תשובה לשאלה הזאת,

יוסף אור

פורסם

סחתיין על התשובה.

אני תמיד שמח לראות שיש כאן בפורום אנשים בעלי תושיה וששמחים לחלוק את מה שהם מצאו.

אגב, מוזר לי מה שאמרת לגבי fopen... הוא אמור להיות מסוגל לקבל כתובת אבסולוטית של קובץ, בסגנון "C:\\blabla\\bla.txt".

פורסם
  • מחבר

גם לי מוזר שהפונקציה fopen לא יודעת לפתוח קבצים לפי נתיב מלא.

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

דוגמה נוספת ליעילותה של הספרייה glib:

בספרייה זו יש פונקציה בשם g_sprintf המקבילה לפונקציה sprintf של stdio, ונוסף לה פונקציה בשם g_strdup_printf שעובדת בצורה הרבה יותר טובה ויותר חכמה:

הצהרת הפונקציה:

gchar *g_strdup_printf(const gchar *format, ...);

הפונקציה פועלת בדיוק כמו printf של stdio, רק שבמקום להדפיס את המחרוזת שנוצרת למסך שורת - הפקודה, היא מחזירה אותה בהקצאת זיכרון דינמית, וכמובן יש צורך בהמשך לשחרר את הזיכרון שהוקצה (אפשרי באמצעות g_free במקום free ואף מומלץ).

תיעוד הפונקציה הנ"ל: http://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strdup-printf

glib היא ספרייה מתועדת היטב וממש יעילה. מומלצת במיוחד.

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

יוסף אור

פורסם

גם לי מוזר שהפונקציה fopen לא יודעת לפתוח קבצים לפי נתיב מלא.

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

אתה בטוח שהשתמשת בה נכון? מוזר מאוד מה שאתה אומר... מה הקוד שניסית?

פורסם
  • מחבר

אני בטוח שהשתמשתי בה נכון.

תיצור לך קובץ בכונן C בשם "main.c" ותשווה את הפלט בין שתי התכניות הבאות:

תכנית ראשונה - עם fopen של stdio:

#include <stdio.h>

int main()
{
FILE *fin;

fin = fopen("C:\\main.c", "rt");

if(fin != NULL)
{
printf("Open the file has been successful !");

fclose(fin);
}
else
{
printf("Failed to open file !");
}

getchar();

return 0;
}

אני מניח שהתכנית הנ"ל תפלוט למסך את המחרוזת "Failed to open file !".

התכנית הבאה, שבכדי להדר אותה תצטרך את הספרייה glib, תפלוט למסך את המחרוזת "Open the file has been successful !", כמובן בתנאי שקיים קובץ בשם "main.c" בכונן C:

#include <glib/gstdio.h>

int main()
{
FILE *fin;

fin = g_fopen("C:\\main.c", "rt");

if(fin != NULL)
{
printf("Open the file has been successful !");

fclose(fin);
}
else
{
printf("Failed to open file !");
}

getchar();

return 0;
}

אני מבין מזה שהפונקציה fopen של stdio לא יודעת לפתוח קבצים לפי נתיב, בניגוד מוחלט ל g_fopen של glib.

וכן, הרצתי את שתי התכניות כשהיה לי קובץ בשם "main.c" בכונן C...

ד.א:

מפתח תיעוד הפונקציות של הספרייה glib:

http://developer.gnome.org/glib/2.28/api-index-full.html

מקווה שהבהרתי,

יוסף אור

פורסם

אצלי זה עובד בלי בעיה... כנראה שמדובר בבעיה אחרת (הרשאות אולי?)

פורסם
  • מחבר

אם יש בעיה מסוימת, הפונקציה g_fopen של glib פותרת אותה, בניגוד לפונקציה fopen של stdio.

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

דיונים חדשים