كيف يمكنني استخدام CharNext API في ويندوز بشكل صحيح ؟

StackOverflow https://stackoverflow.com/questions/1235798

  •  22-07-2019
  •  | 
  •  

سؤال

لدي متعددة البايت سلسلة تحتوي على خليط من اليابانية الأحرف اللاتينية.أحاول نسخ أجزاء من هذه السلسلة إلى ذاكرة منفصلة الموقع.لأنه متعدد البايت سلسلة بعض الشخصيات يستخدم بايت واحد و الشخصيات الأخرى يستخدم اثنين.عند نسخ أجزاء من السلسلة ، يجب أن لا نسخ "نصف" الأحرف اليابانية.أن تكون قادرة على القيام بذلك بشكل صحيح ، أنا بحاجة إلى أن تكون قادرة على تحديد أين في موضوع سلسلة البايت الأحرف يبدأ وينتهي.

وكمثال على ذلك, إذا كانت السلسلة تحتوي على 3 شخصيات الأمر الذي يتطلب [2 بايت][2 بايت][1 بايت] يجب أن نسخ إما 2 أو 4 أو 5 وحدات البايت إلى مكان آخر و ليس 3 ، لأنه إذا كنت نسخ 3 وأود أن نسخ فقط نصف الحرف الثاني.

لمعرفة أين في موضوع سلسلة البايت الأحرف يبدأ وينتهي أحاول استخدام دالة API Windows CharNext و CharNextExA لكن بدون حظ.عند استخدام هذه الوظائف ، انتقل من خلال سلسلة بايت واحد في وقت واحد بدلا من حرف واحد في وقت واحد.وفقا MSDN ، CharNext المفترض أن على CharNext وظيفة باسترداد المؤشر إلى الحرف التالي في السلسلة..

هنا بعض التعليمات البرمجية لتوضيح هذه المشكلة:

#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>

/* string consisting of six "asian" characters */
wchar_t wcsString[] = L"\u9580\u961c\u9640\u963f\u963b\u9644";

int main() 
{
   // Convert the asian string from wide char to multi-byte.
   LPSTR mbString = new char[1000];
   WideCharToMultiByte( CP_UTF8, 0, wcsString, -1, mbString, 100,  NULL, NULL);

   // Count the number of characters in the string.
   int characterCount = 0;
   LPSTR currentCharacter = mbString;
   while (*currentCharacter)
   {
      characterCount++;

     currentCharacter = CharNextExA(CP_UTF8, currentCharacter, 0);
   }
}

(يرجى تجاهل تسرب الذاكرة وعدم القيام التحقق من الخطأ.)

الآن, في المثال أعلاه أتوقع أن characterCount يصبح 6, منذ ذلك عدد من الشخصيات في آسيا السلسلة.ولكن بدلا من ذلك ، characterCount يصبح 18 لأن mbString يحتوي على 18 حرفا:

門阜陀阿阻附

أنا لا أفهم كيف أنه من المفترض أن يعمل.كيف CharNext من المفترض أن يعرف ما إذا كان "é–€é" في السلسلة هو النسخة المشفرة من الشخصية اليابانية ، أو في الواقع الشخصيات é – € é?

بعض الملاحظات:

  • لقد قرأت Joels بلوق وظيفة حول كل ما يحتاج المطور إلى معرفته حول Unicode.ربما أكون قد أسأت فهم شيء في ذلك على الرغم من.
  • إذا كان كل ما أردت فعله هو عد الأحرف يمكنني الاعتماد الشخصيات في آسيا السلسلة مباشرة.نضع في اعتبارنا أن هدفي الحقيقي هو نسخ أجزاء متعددة البايت السلسلة إلى موقع منفصل.منفصلة الموقع يدعم فقط multi-byte, لا widechar.
  • إن تحويل المحتوى من mbString مرة أخرى إلى نطاق شار باستخدام MultiByteToWideChar ، أحصل على السلسلة الصحيحة (門阜陀阿阻附) ، مما يدل على أن هناك شيء خاطئ مع mbString.

تحرير:على ما يبدو فإن CharNext وظائف لا يدعم UTF-8 ولكن مايكروسوفت نسيت أن وثيقة.رميت/copiedpasted معا بلدي الروتينية التي لن الاستخدام والتي تحتاج الى تحسين.انا التخمين انه بسهولة crashable.

  LPSTR CharMoveNext(LPSTR szString)
  {
     if (szString == 0 || *szString == 0)
        return 0;

     if ( (szString[0] & 0x80) == 0x00)
        return szString + 1;
     else if ( (szString[0] & 0xE0) == 0xC0)
        return szString + 2;
     else if ( (szString[0] & 0xF0) == 0xE0)
        return szString + 3;
     else if ( (szString[0] & 0xF8) == 0xF0)
        return szString + 4;
     else
        return szString +1;
  }
هل كانت مفيدة؟

المحلول

هنا هو حقا جيدة تفسير ما يجري هنا في فرز كل بلوق: هو CharNextExA مكسورة ؟ .باختصار ، CharNext ليست مصممة للعمل مع UTF8 السلاسل.

نصائح أخرى

بقدر ما أنا يمكن تحديد (جوجل والتجريب), CharNextExA لا فعلا العمل مع UTF-8 معتمدة فقط multibyte ترميزات أن استخدام أقصر الرصاص/درب بايت أزواج أو مفردة البايت الأحرف.

UTF-8 هو منتظم إلى حد ما ترميز هناك الكثير من المكتبات التي سوف تفعل ما تريد ولكن أيضا من السهل إلى حد ما إلى لفة الخاص بك.

ألقي نظرة هنا unicode.org, ولا سيما الجدول 3-7 صالحة تسلسل الأشكال.

const char* NextUtf8( const char* in )
{
    if( in == NULL || *in == '\0' )
        return in;

    unsigned char uc = static_cast<unsigned char>(*in);

    if( uc < 0x80 )
    {
        return in + 1;
    }
    else if( uc < 0xc2 )
    {
         // throw error? invalid lead byte
    }
    else if( uc < 0xe0 )
    {
        // check in[1] for validity( 0x80 .. 0xBF )
        return in + 2;
    }
    else if( uc < 0xe1 )
    {
        // check in[1] for validity( 0xA0 .. 0xBF )
        // check in[2] for validity( 0x80 .. 0xBF )
        return in + 3;
    }
    else // ... etc.
    // ...
}

بالنظر إلى أن CharNextExA لا يعمل مع UTF-8, يمكنك تحليل ذلك بنفسك.فقط تخطي الشخصيات التي لديها 10 في أعلى اثنين بت.يمكنك ان ترى نمط في تعريف UTF-8: http://en.wikipedia.org/wiki/Utf-8

LPSTR CharMoveNext(LPSTR szString)
{
    ++szString;
    while ((*szString & 0xc0) == 0x80)
        ++szString;
    return szString;
}

هذه ليست إجابة مباشرة على سؤالك, ولكن قد تجد البرنامج التعليمي التالية مفيدة بالتأكيد.في حقيقة المعلومات المقدمة هنا هي بما فيه الكفاية التي يجب أن تكون قادرة على اجتياز متعددة البايت سلسلة نفسك بكل سهولة:

إكمال سلسلة التعليمي

حاول استخدام 932 عن صفحة التعليمات البرمجية.لا أعتقد CP_UTF8 حقيقية الشفرة ، و قد تعمل فقط من أجل WideCharToMultibyte() والظهر.يمكنك أيضا محاولة isleadByte () ، ولكن هذا يتطلب أيضا تحديد اللغة بشكل صحيح ، أو الإعداد الافتراضي الشفرة بشكل صحيح.ولقد استخدمت بنجاح IsDBCSLeadByteEx () ، ولكن أبدا مع CP_UTF8.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top