طريقة Sane (r) للحصول على ترميز شخصية CLI في Mac OS X؟
-
28-09-2019 - |
سؤال
كنت أكتب أداة CLI لـ Mac OS X (10.5+) يجب أن تتعامل مع وسائط خط الأوامر التي من المحتمل جدًا أن تحتوي على أحرف غير ASCII.
لمزيد من المعالجة ، أقوم بتحويل هذه الوسائط باستخدام +[NSString StringWithCstring: الترميز:].
مشكلتي هي أنني لم أتمكن من العثور على معلومات جيدة حول كيفية تحديد ترميز الشخصية المستخدمة من قبل الصدفة التي يتم فيها تشغيل CLI-Tool.
ما توصلت إليه كحل هو ما يلي:
NSDictionary *environment = [[NSProcessInfo processInfo] environment];
NSString *ianaName = [[environment objectForKey:@"LANG"] pathExtension];
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(
CFStringConvertIANACharSetNameToEncoding( (CFStringRef)ianaName ) );
NSString *someArgument = [NSString stringWithCString:argv[someIndex] encoding:encoding];
أجد ذلك خامًا قليلاً - مما يجعلني أعتقد أنني فاتني شيئًا واضحًا ... لكن ماذا؟
هل هناك طريقة SANER/أنظف لتحقيق نفس الشيء؟
شكرا مقدما
د
المحلول 3
حسنًا ، يبدو أنه لا يوجد شيء!
كما أشار Yuji ، فإن الترميز الأساسي لأسماء الملفات هو UTF-8 ، بغض النظر عن ماذا. لذلك ، يحتاج المرء للتعامل مع سيناريوهين:
- الوسيطات التي يتم كتابتها في ، شخصية للشخصية ، من قبل المستخدم.
- الوسيطات التي يتم استكمال علامة التبويب أو إخراج أوامر مثل
ls
, ، لأنهم لا يحولون أي أحرف.
تتم تغطية الحالة الثانية ببساطة بافتراض UTF-8.
الحالة الأولى ، مع ذلك ، هي مشكلة:
- على MAC OS 10.6 ، يحتوي $ LANG على اسم IANA NAME من التشفير المستخدم مثل
de_DE.IANA_NAME
. - قبل الثلج الفهد ، ليست هذه هي القضية إلى عن على charsets غير UTF-8!
لم أختبر كل شارت التي يمكن أن أفكر فيها ، لكن لم يتم تضمين أي من الأوروبيين. بدلاً من ذلك ، كان $ lang فقط محطًا اللغة (de_DE
في حالتي)!
منذ نتائج الاتصال +[NSString stringWithCString:encoding:]
مع تشفير غير صحيح غير محددة, ، لا يمكنك أن تفترض بأمان أنه سيعود nil
في هذه الحالة* (إذا كان على سبيل المثال ، فهو Ascii فقط ، فقد يعمل بشكل جيد تمامًا!).
ما يضيف إلى الفوضى الكلية هو ذلك $LANG
لا ينسجم لتكون موجودًا ، على أي حال: هناك خانة اختيار في تفضيلات terminal.app ، والتي تمكن المستخدم من عدم تعيينه $LANG
على الإطلاق (لا تتحدث عن X11.APP الذي لا يبدو أنه يتعامل مع أي مدخلات غير ASCII ...).
إذن ما تبقى:
- تحقق من وجود
$LANG
. إذا لم يتم تعيينه ، goto: 4! - تحقق فيما لو
$LANG
يحتوي على معلومات حول الترميز. إذا لم يحدث ، goto: 4! - تحقق مما إذا كان الترميز الذي تجده هناك UTF-8. إذا كان Goto: 6 ، آخر ...
- إذا
argc
أكبر من 2 و[[NSString stringWithCString: argv[0] encoding: NSUTF8StringEncoding] isEqualToString: yourForceUTFArgumentFlag]
, ، طباعة أنك تجبر UTF-8 الآن و Goto 6. إذا لم يكن الأمر كذلك: - افترض أنك لا تعرف أي شيء ، فأصدر تحذيرًا بأنه يجب على المستخدم تعيين الجهاز الترميز على UTF-8 وقد يفكر في المرور
yourForceUTFArgumentFlag
كحجة أولى و خروج(). - افترض UTF-8 وافعل ما عليك ...
يبدو غزر؟ هذا لأنه كذلك ، لكن لا يمكنني التفكير في أي شيء سانر طريقة للقيام بذلك.
ملاحظة أخرى على الرغم من ذلك: إذا كنت تستخدم UTF-8 كترميز ، stringWithCString: الترميز: إرجاع NIL كلما واجهت أحرف غير ASCII في سلسلة C ليس مشفرة في UTF-8.)
نصائح أخرى
الجواب يعتمد على ما يأتي منه عدم الأوعية.
- في OS X ، متغير البيئة
LANG
يفعل ليس تعكس اختيار اللغة في واجهة المستخدم الرسومية. قلة قليلة من الناس سوف يضعونLANG
في سطر الأوامر. - يتم تخزين اختيار "ترميز النظام" في واجهة المستخدم الرسومية
~/.CFUserTextEncoding
, ويمكن الحصول عليها بواسطةCFStringGetSystemEncoding
, ، انظر الى هذا Apple Doc. - ومع ذلك ، فإن هذا "ترميز النظام" هو نادرا ما تستخدم إلا في برامج قديمة للغاية ، غير unicode. يستخدم أي برنامج عاقل الكاكاو يونيكود فقط ولا شيء آخر.
على وجه الخصوص ، يتم تشفير مسار الملف على مستوى الكاكاو دائمًا في (متغير) UTF-8. لذلك ، للحصول على
NSString
من سلسلة C ، استخدمNSString*string=[NSString stirngWithCString:cString encoding:NSUTF8Encoding];
وللحصول على سلسلة C لمسار الملف من
NSString
, ، استعمالchar*path=[string fileSystemRepresentation];
هنا يوصى بعدم استخدام فقط
[string UTF8String]
, ، بسبب الدقة ، انظر هذا Apple Doc.لذلك ، أوصيك بعدم الاهتمام بالترميز وتولي UTF-8 فقط.
- ومع ذلك ، قد يكون هناك عدد صغير جدًا من الأشخاص الذين يرقون
LANG
على سطر الأوامر ، وقد ترغب في الاعتناء بهم. ثم ، ما فعلته هو الشيء الوحيد الذي يمكنني التوصل إليه.
لا يمكنك استخدام فقط [[NSProcessInfo processInfo] arguments]
?