UTF-8 ، CSTRING و CFILE؟ (C ++ ، MFC)
سؤال
أنا أعمل حاليًا على برنامج MFC يجب أن يعمل مع UTF-8 على وجه التحديد. في مرحلة ما ، يجب أن أكتب بيانات UTF-8 في ملف ؛ للقيام بذلك ، أنا أستخدم CFILES و CSTRINGS.
عندما أحصل على كتابة بيانات UTF-8 (الأحرف الروسية ، لأكون أكثر دقة) في ملف ، يبدو أن الإخراج
Ðàñïå÷àòàíî:
Ñèñòåìà
Ïðîèçâîäñòâî
وما إلى ذلك. لقراءة هذه البيانات بشكل صحيح ، لا بد لي من تغيير إعدادات النظام الخاصة بي ؛ إن تغيير الأحرف غير ASCII إلى جدول ترميز روسي يعمل ، ولكن بعد ذلك تفشل جميع الشخصيات اللاتينية غير القائمة على ASCII. على أي حال ، هكذا أفعل ذلك.
CFile CSVFile( m_sCible, CFile::modeCreate|CFile::modeWrite);
CString sWorkingLine;
//Add stuff into sWorkingline
CSVFile.Write(sWorkingLine,sWorkingLine.GetLength());
//Clean sWorkingline and start over
هل فاتني شيء؟ هل يمكنني استخدام شيء آخر بدلاً من ذلك؟ هل هناك نوع من الصيد الذي فاتني؟ سوف يتم ضبطها من أجل حكمتك وخبرتك ، زملائك المبرمجين.
تحرير: بالطبع ، كما سألت للتو سؤالًا ، أجد أخيرًا شيئًا قد يكون مثيرًا للاهتمام ، ويمكن العثور عليه هنا. اعتقدت أنني قد أشاركها.
تحرير 2:
حسنًا ، لقد أضفت BOM إلى ملفي ، الذي يحتوي الآن على حرف Chineese ، ربما لأنني لم أحول خطي إلى UTF-8. لإضافة بوم فعلت ...
char BOM[3]={0xEF, 0xBB, 0xBF};
CSVFile.Write(BOM,3);
وبعد ذلك ، أضفت ...
TCHAR TestLine;
//Convert the line to UTF-8 multibyte.
WideCharToMultiByte (CP_UTF8,0,sWorkingLine,sWorkingLine.GetLength(),TestLine,strlen(TestLine)+1,NULL,NULL);
//Add the line to file.
CSVFile.Write(TestLine,strlen(TestLine)+1);
ولكن بعد ذلك ، لا يمكنني التجميع ، لأنني لا أعرف حقًا كيفية الحصول على طول Testline. لا يبدو أن سترلين يقبل Tchar.ثابت ، استخدمت static endenght من 1000 بدلا من ذلك.
تحرير 3:
لذا ، أضفت هذا الرمز ...
wchar_t NewLine[1000];
wcscpy( NewLine, CT2CW( (LPCTSTR) sWorkingLine ));
TCHAR* TCHARBuf = new TCHAR[1000];
//Convert the line to UTF-8 multibyte.
WideCharToMultiByte (CP_UTF8,0,NewLine,1000,TCHARBuf,1000,NULL,NULL);
//Find how many characters we have to add
size_t size = 0;
HRESULT hr = StringCchLength(TCHARBuf, MAX_PATH, &size);
//Add the line to the file
CSVFile.Write(TCHARBuf,size);
إنه يجمع بشكل جيد ، لكن عندما أذهب إلى إلقاء نظرة على ملفي الجديد ، فإنه تمامًا كما لو لم يكن لدي كل هذا الرمز الجديد (على سبيل المثال: ðàñïå ÷ àòàíî :). يبدو الأمر وكأنني لم أقم بخطوة للأمام ، على الرغم من أنني أعتقد أن شيئًا صغيرًا فقط هو ما يفصلني عن النصر.
تحرير 4:
لقد قمت بإزالة التعليمات البرمجية المضافة مسبقًا ، كما طلب نيت ، وقررت استخدام الكود الخاص به بدلاً من ذلك ، وهذا يعني أنه الآن ، عندما أتمكن من إضافة خطي ، لدي ...
CT2CA outputString(sWorkingLine, CP_UTF8);
//Add line to file.
CSVFile.Write(outputString,::strlen(outputString));
كل شيء يجمع بشكل جيد ، ولكن يتم عرض الشخصيات الروسية على أنها ؟؟؟؟؟؟؟. الاقتراب ، ولكن لا يزال ذلك. راجع للشغل ، أود أن أشكر كل من حاول/يحاول مساعدتي ، إنه موضع تقدير كبير. لقد كنت عالقًا في هذا الأمر لفترة من الوقت الآن ، لا يمكنني الانتظار حتى تختفي هذه المشكلة.
التحرير النهائي (آمل) من خلال تغيير الطريقة التي حصلت بها لأول مرة على شخصيات UTF-8 (قمت بإعادة الترميز دون أن أعرف حقًا) ، وهو ما كان خطأ في طريقتي الجديدة لإخراج النص ، حصلت على نتائج مقبولة. عن طريق إضافة UTF-8 BOM char في بداية ملفي ، يمكن قراءته كوحدة في البرامج الأخرى ، مثل Excel.
يا هلا! شكرا لكل شخص!
المحلول
عندما تقوم بإخراج البيانات التي تحتاج إلى القيام بها (هذا يفترض أنك تقوم بتجميعها في وضع Unicode ، وهو موصى به للغاية):
CString russianText = L"Привет мир";
CFile yourFile(_T("yourfile.txt"), CFile::modeWrite | CFile::modeCreate);
CT2CA outputString(russianText, CP_UTF8);
yourFile.Write(outputString, ::strlen(outputString));
إذا _UNICODE
لم يتم تعريفه (أنت تعمل في وضع متعدد البايت بدلاً من ذلك) ، فأنت بحاجة إلى معرفة صفحة الكود التي يوجد فيها نص الإدخال الخاص بك وتحويله إلى شيء يمكنك استخدامه. يوضح هذا المثال العمل مع النص الروسي الموجود بتنسيق UTF-16 ، مما يوفره إلى UTF-8:
// Example 1: convert from Russian text in UTF-16 (note the "L"
// in front of the string), into UTF-8.
CW2A russianTextAsUtf8(L"Привет мир", CP_UTF8);
yourFile.Write(russianTextAsUtf8, ::strlen(russianTextAsUtf8));
على الأرجح ، نصك الروسي موجود في صفحة رمز أخرى ، مثل KOI-8R. في هذه الحالة ، تحتاج إلى تحويل من صفحة التعليمات البرمجية الأخرى إلى UTF-16. ثم تحويل UTF-16 إلى UTF-8. لا يمكنك التحويل مباشرة من KOI-8R إلى UTF-8 باستخدام وحدات الماكرو للتحويل لأنها تحاول دائمًا تحويل النص الضيق إلى صفحة رمز النظام. لذا فإن الطريقة السهلة هي القيام بذلك:
// Example 2: convert from Russian text in KOI-8R (code page 20866)
// to UTF-16, and then to UTF-8. Conversions between UTFs are
// lossless.
CA2W russianTextAsUtf16("\xf0\xd2\xc9\xd7\xc5\xd4 \xcd\xc9\xd2", 20866);
CW2A russianTextAsUtf8(russianTextAsUtf16, CP_UTF8);
yourFile.Write(russianTextAsUtf8, ::strlen(russianTextAsUtf8));
لا تحتاج إلى BOM (إنه اختياري ؛ لن أستخدمه إلا إذا كان هناك سبب محدد للقيام بذلك).
تأكد من قراءة هذا: http://msdn.microsoft.com/en-us/library/87zae4a3(vs.80).aspx. إذا كنت تستخدم بشكل غير صحيح CT2CA
(على سبيل المثال ، باستخدام مشغل الواجب) سوف تواجه مشكلة. تعرض صفحة الوثائق المرتبطة أمثلة على كيفية الاستخدام وكيفية عدم استخدامها.
مزيد من المعلومات:
- ال ج في
CT2CA
يشيرconst
. أستخدمه عندما يكون ذلك ممكنًا ، لكن بعض التحويلات تدعم فقط الإصدار غير المؤلف (على سبيل المثالCW2A
). - ال ر في
CT2CA
يشير إلى أنك تتحول من وLPCTSTR
. وبالتالي ، سيعمل ما إذا تم تجميع الكود الخاص بك مع_UNICODE
العلم أم لا. يمكنك أيضا استخدامCW2A
(أين ث يشير إلى أحرف واسعة). - ال أ في
CT2CA
يشير إلى أنك تتحول إلى سلسلة "ANSI" (8 بت char). - أخيرًا ، المعلمة الثانية
CT2CA
يشير إلى صفحة التعليمات البرمجية التي تقوم بتحويلها إليها.
للقيام بالتحويل العكسي (من UTF-8 إلى LPCTST) ، يمكنك القيام:
CString myString(CA2CT(russianText, CP_UTF8));
في هذه الحالة ، نحن نتحول من سلسلة "ANSI" بتنسيق UTF-8 ، إلى LPCTSTR. ال LPCTSTR
يُفترض دائمًا أن يكون UTF-16 (إذا _UNICODE
تم تعريفه) أو صفحة رمز النظام الحالية (إذا _UNICODE
غير محدد).
نصائح أخرى
عليك التحويل sWorkingLine
إلى UTF-8 ثم اكتبه في الملف.
Widechartomultibyte يمكن تحويل سلاسل Unicode إلى UTF-8 إذا قمت بتحديد CP_UTF8
codepage.multibytetoWidechar يمكن تحويل chars ASCII إلى Unicode.
تأكد من أنك تستخدم Unicode (Tchar هو WCHAR_T). ثم قبل كتابة البيانات ، قم بتحويلها باستخدام وظيفة API WIDECHARTOMultiByte WIN32.