تحويل السلاسل النصية إلى بايتات في C# بدون ترميز: حل المشكلة بالطريقة الصحيحة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا هذا السؤال شائع جدًا على Stack Overflow؟



إذا كنت قد كتبت يومًا بلغة C# وواجهت الحاجة لتحويل سلسلة نصية إلى مصفوفة بايتات، فبالتأكيد تساءلت: "لماذا يجب أن أحدد الترميز؟ فالسلسلة النصية هي مجرد سلسلة نصية!". هذا السؤال حصد آلاف المشاهدات على Stack Overflow ليس من قبيل الصدفة. إنه يتطرق إلى سوء فهم أساسي بين كيف نرى النص وكيف يراه الكمبيوتر.



في هذه المقالة، لن نقدم فقط كودًا جاهزًا، بل سنفهم أيضًا لماذا Encoding.UTF8.GetBytes("hello") ليس حلاً مؤقتًا، بل هو الطريقة الصحيحة الوحيدة. ستتعلم كيفية الحصول على تمثيل البايتات للسلاسل النصية في C# دون خطر فقدان البيانات، وما يختبئ وراء سحر "الاختيار التلقائي للترميز".



خرافة "السلسلة النصية بدون ترميز"



يعتقد العديد من المبتدئين أن السلسلة النصية في C# هي مجرد تسلسل من البايتات. هذا غير صحيح. داخليًا، يتم تخزين string في .NET كـ UTF-16 (أحرف ثنائية البايت). عندما تكتب "Привет"، فهي في الذاكرة 12 بايتًا (6 أحرف × 2 بايت). ولكن إذا حاولت إرسال هذه السلسلة النصية إلى ملف، أو شبكة، أو قاعدة بيانات، فستحتاج دائمًا تقريبًا إلى تنسيق آخر - غالبًا UTF-8.



محاولة الحصول على بايتات "بدون ترميز" تشبه السؤال: "كيف أترجم كتابًا من الروسية إلى الإنجليزية دون تحديد اللغة؟". مستحيل. الترميز هو قواعد تحويل الأحرف إلى بايتات. بدونها، ستحصل على فوضى.



كيف لا يجب أن تفعل (خطأ نموذجي)



string text = "Hello, мир!";byte[] wrongBytes = System.Text.Encoding.Default.GetBytes(text); // سيء!


يستخدم هذا الكود الترميز الافتراضي للنظام (عادةً Windows-1251 على نظام Windows الروسي). إذا قمت بتشغيل هذا الكود على جهاز آخر أو تحت Linux - ستحصل على بايتات مختلفة. سيصبح تطبيقك غير قابل للتنبؤ.



النهج الصحيح: تحديد الترميز بشكل صريح



الطريقة الوحيدة الموثوقة للحصول على تمثيل بايتات متسق للسلاسل النصية هي تحديد الترميز بشكل صريح. الخيار الأكثر شيوعًا والموصى به هو UTF-8:



string text = "Hello, мир!";byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(text);// النتيجة: [72, 101, 108, 108, 111, 44, 32, 208, 188, 208, 184, 209, 128, 33]


سيعطي هذا الكود دائمًا نفس النتيجة على أي منصة. لماذا؟ لأن UTF-8 هو معيار دولي يعمل بنفس الطريقة في كل مكان.



خيارات الترميز الأخرى (عند الحاجة إليها)



  • ASCII - فقط الحروف اللاتينية، يتجاهل جميع الأحرف >127.
  • Unicode (UTF-16LE) - التنسيق الداخلي لـ C#، لكنه غير فعال للتخزين.
  • Windows-1251 - قديم، فقط للتوافق مع الأنظمة القديمة.


لـ 99% من المهام الحديثة، استخدم Encoding.UTF8.



ماذا لو أردت "بدون تحديد"؟ هل هناك اختراق؟



تقنيًا، يمكنك استخدام BitConverter.ToString() أو كود غير آمن مع المؤشرات، لكن هذا سيعطيك بايتات UTF-16 الخام المخزنة في الذاكرة. هذه فكرة سيئة لعدة أسباب:



  • النتيجة تعتمد على المنصة (Little-Endian مقابل Big-Endian).
  • ستحصل على بايتات صفرية زائدة للأحرف اللاتينية (كل حرف سيأخذ 2 بايت).
  • عند تغيير إصدار .NET، قد يتغير التمثيل الداخلي (غير محتمل، لكنه ممكن).


مثال على كود خطير لا يجب تكراره:



unsafe{    string text = "Hello";    fixed (char* ptr = text)    {        byte* bytePtr = (byte*)ptr;        // العمل مع بايتات UTF-16 الخام    }}


هذا يعمل، لكنه ينتهك مبدأ "لا تتدخل في التفاصيل الداخلية إذا كنت لا تفهم العواقب".



أفضل الممارسات للمبتدئين

المدونات

توصيات الكتب