هل من الممكن استخدام "أرجف" يونيكود؟
-
12-09-2019 - |
سؤال
أنا أكتب غلاف صغير لتطبيق يستخدم الملفات كوسائط.
يجب أن يكون Wrapper في Unicode، لذلك أنا أستخدم Wchar_T للحصول على الشخصيات والسلاسل لدي. الآن أجد نفسي في مشكلة، أحتاج إلى حجج البرنامج في مجموعة من wchar_t's وفي سلسلة wchar_t.
هل هو ممكن؟ أنا أعرف main
وظيفة
int main(int argc, char *argv[])
يجب أن أستخدم wchar_t ل argv
?
شكرا جزيلا لك، لا يبدو لي أن أجد معلومات مفيدة حول كيفية استخدام Unicode بشكل صحيح في C.
المحلول
بشكل عام، لا. سيعتمد على O / S، لكن المعيار C يقول أن الحجج إلى "الرئيسية ()" يجب أن تكون "الرئيسية (int argc، archv)" أو ما يعادلها، لذلك ما لم تكن شار و wchar_t هي نفس النوع الأساسي ، لا يمكنك أن تفعل ذلك.
بعد القول أنه يمكنك الحصول على سلاسل وسيطة UTF-8 في البرنامج، وتحويلها إلى UTF-16 أو UTF-32، ثم استمر في الحياة.
على جهاز Mac (10.5.8، ليوبارد)، حصلت على:
Osiris JL: echo "ï€" | odx
0x0000: C3 AF E2 82 AC 0A ......
0x0006:
Osiris JL:
هذا كل شيء UTF-8 المشفرة. (odx هو برنامج تفريغ عرافة).
أنظر أيضا: لماذا يتم استخدام ترميز UTF-8 عند التفاعل مع بيئة UNIX / Linux
نصائح أخرى
رمز المحمولة لا يدعم ذلك. يدعم Windows (على سبيل المثال) باستخدام wmain
بدلا من main
, في هذه الحالة يتم تمرير Argv كحرف واسعة.
على ويندوز، يمكنك استخدام GetCommandLineW()
و CommandLineToArgvW()
لإنتاج نمط Argv wchar_t[]
صفيف، حتى إذا لم يتم تجميع التطبيق ل Unicode.
على ويندوز على أي حال، يمكنك الحصول على wmain()
بالنسبة لبناء Unicode. غير محمول رغم ذلك. أنا dunno إذا توفر منصات دول مجلس التعاون الخليجي أو يونيكس / لينكس أي شيء مماثل.
على افتراض أن بيئة Linux الخاصة بك تستخدم ترميز UTF-8 ثم تعد التعليمات البرمجية التالية برنامجك لسهولة علاج Unicode في C ++:
int main(int argc, char * argv[]) {
std::setlocale(LC_CTYPE, "");
// ...
}
التالي، نوع wchar_t هو 32 بت في لينكس، مما يعني أنه يمكن أن يحمل نقاط رمز Unicode الفردية ويمكنك استخدام نوع WSTRING بأمان لمعالجة السلسلة الكلاسيكية في C ++ (حرف حسب الحرف). مع مكالمة SetLocale أعلاه، سيقوم إدراج WCOUT تلقائيا بترجمة الإخراج الخاص بك إلى UTF-8 واستخراج من WCIN تلقائيا إشراف إدخال UTF-8 في UTF-32 (حرف واحد = 1 رمز رمز). المشكلة الوحيدة التي تظل هي أن سلاسل Argv [i] لا تزال تشفير UTF-8.
يمكنك استخدام الوظيفة التالية لتشغيل UTF-8 في UTF-32. إذا كانت سلسلة الإدخال تالفة، فسوف تعيد الأحرف المحولة بشكل صحيح حتى يتم كسر المكان الذي تم فيه كسر قواعد UTF-8. يمكنك تحسينه إذا كنت بحاجة إلى المزيد من التقارير الأخطاء. ولكن بالنسبة لبيانات Argv، يمكن للمرء أن يفترض بأمان أنه صحيح UTF-8:
#define ARR_LEN(x) (sizeof(x)/sizeof(x[0]))
wstring Convert(const char * s) {
typedef unsigned char byte;
struct Level {
byte Head, Data, Null;
Level(byte h, byte d) {
Head = h; // the head shifted to the right
Data = d; // number of data bits
Null = h << d; // encoded byte with zero data bits
}
bool encoded(byte b) { return b>>Data == Head; }
}; // struct Level
Level lev[] = {
Level(2, 6),
Level(6, 5),
Level(14, 4),
Level(30, 3),
Level(62, 2),
Level(126, 1)
};
wchar_t wc = 0;
const char * p = s;
wstring result;
while (*p != 0) {
byte b = *p++;
if (b>>7 == 0) { // deal with ASCII
wc = b;
result.push_back(wc);
continue;
} // ASCII
bool found = false;
for (int i = 1; i < ARR_LEN(lev); ++i) {
if (lev[i].encoded(b)) {
wc = b ^ lev[i].Null; // remove the head
wc <<= lev[0].Data * i;
for (int j = i; j > 0; --j) { // trailing bytes
if (*p == 0) return result; // unexpected
b = *p++;
if (!lev[0].encoded(b)) // encoding corrupted
return result;
wchar_t tmp = b ^ lev[0].Null;
wc |= tmp << lev[0].Data*(j-1);
} // trailing bytes
result.push_back(wc);
found = true;
break;
} // lev[i]
} // for lev
if (!found) return result; // encoding incorrect
} // while
return result;
} // wstring Convert
على Windows، يمكنك استخدام Tchar.h و _tmain، والتي سيتم تحويلها إلى WMAIN إذا تم تعريف رمز _unicode في وقت ترجمة، أو غير ذلك. سيتم توسيع Thar * Argv [] بالمثل وفقا لشركة Wchr * Argv [] إذا تم تعريف Unicode، والشار * Argv [] إن لم يكن.
إذا كنت ترغب في الحصول على منصة عرض أسلوبك الرئيسي، فيمكنك تحديد وحدات الماكرو الخاصة بك بنفس التأثير.
يحتوي Tchar.H على عدد من وحدات ماكرو للتحويل بين Wchar و Char.