«السلاسل النصية» و«البايتات»: لماذا هي الصداع الأبدي للمبرمج؟
\nتخيل موقفًا: تكتب تطبيق شبكي بلغة C#، وترسل بيانات إلى الخادم، وفي النهاية تحصل على خليط من الرموز. أو تقوم بتشفير كلمة مرور، ولا يستطيع الطرف الآخر فك تشفيرها. مألوف؟ غالبًا ما يكمن جذر المشكلة في التحويل غير الصحيح للسلسلة النصية إلى مصفوفة بايتات (والعكس).
\nسؤال «Converting string to byte array in C#» على Stack Overflow جمع آلاف المشاهدات ليس من قبيل الصدفة. إنه الأساس الذي تقوم عليه معالجة الملفات، والتشفير، والتسلسل، والتفاعل الشبكي. بدون فهم هذا الموضوع، ستكرر نفس الأخطاء. دعنا نفهم مرة واحدة وإلى الأبد كيفية القيام بذلك بشكل صحيح.
\n\nلماذا لا يمكن ببساطة تحويل السلسلة النصية إلى بايتات؟
\nالنهج الساذج هو استخدام BitConverter.GetBytes() للحرف؟ لا. المشكلة هي أن السلسلة النصية هي تجريد يتكون من أحرف (char، 2 بايت في C#). بينما مصفوفة البايتات هي بيانات خام تعتمد على الترميز.
نفس الحرف «A» في ترميز UTF-8 سيأخذ 1 بايت، وفي UTF-16 سيأخذ 2 بايت، وفي UTF-32 سيأخذ 4 بايتات. إذا اخترت الترميز الخاطئ، فستفقد البيانات. تذكر القاعدة الأساسية: حدد الترميز دائمًا بشكل صريح.
\n\nالطريقة الأكثر شيوعًا: Encoding.UTF8.GetBytes()
\nهذا ما ستستخدمه في 90% من الحالات. UTF-8 هو المعيار الفعلي للويب و JSON ومعظم واجهات API.
\n\nusing System;\nusing System.Text;\n\nclass Program\n{\n static void Main()\n {\n string original = "Привет, мир! 🌍";\n \n // تحويل السلسلة النصية إلى مصفوفة بايتات (UTF-8)\n byte[] utf8Bytes = Encoding.UTF8.GetBytes(original);\n \n // التحويل العكسي (للتحقق)\n string restored = Encoding.UTF8.GetString(utf8Bytes);\n \n Console.WriteLine($"السلسلة الأصلية: {original}");\n Console.WriteLine($"مصفوفة البايتات (الطول {utf8Bytes.Length}): {BitConverter.ToString(utf8Bytes)}");\n Console.WriteLine($"السلسلة المستعادة: {restored}");\n }\n}\n\nنتيجة التشغيل:
\nالسلسلة الأصلية: Привет, мир! 🌍\nمصفوفة البايتات (الطول 18): D0-9F-D1-80-D0-B8-D0-B2-D0-B5-D1-82-2C-20-D0-BC-D0-B8-D1-80-21-20-F0-9F-8C-8D\nالسلسلة المستعادة: Привет, мир! 🌍\n\nلاحظ: الرمز التعبيري «🌍» يأخذ 4 بايتات (F0-9F-8C-8D). UTF-8 قادر على التعامل مع أي رموز يونيكود، على عكس الترميزات القديمة.
\n\nترميزات شائعة أخرى
\n- \n
- Encoding.ASCII — فقط الرموز ذات 7 بتات (0-127). غير مناسب للسيريلية أو الرموز الخاصة — كل ما هو أعلى من 127 سيتحول إلى '?' \n
- Encoding.Unicode (المعروف أيضًا باسم UTF-16LE) — يُستخدم داخليًا في C# لتخزين السلاسل النصية. كل حرف يأخذ 2 بايت (أو 4 للأزواج البديلة). \n
- Encoding.UTF32 — كل حرف بدقة 4 بايتات. مكلف من حيث الموارد ولكنه قابل للتنبؤ. \n
- Encoding.Default — ترميز النظام (ANSI). تجنبه! يختلف من جهاز لآخر. \n
التحويل باستخدام BitConverter و MemoryStream
\nأحيانًا تحتاج إلى الحصول على تمثيل «خام» للسلسلة النصية كمصفوفة من الأحرف (char). هذا ليس نفس البايتات في الترميز، لكنه قد يكون مفيدًا للعمل على مستوى منخفض.
\n\nstring text = "C#";\n// الحصول على مصفوفة char\nchar[] chars = text.ToCharArray();\n// تحويل كل char إلى 2 بايت (Little-Endian)\nbyte[] rawBytes = new byte[chars.Length * sizeof(char)];\nBuffer.BlockCopy(chars, 0, rawBytes, 0, rawBytes.Length);\n\nConsole.WriteLine(BitConverter.ToString(rawBytes)); // 43-00-23-00\n\nتعطي هذه الطريقة مصفوفة بترميز UTF-16LE (كما هو مخزن في الذاكرة). استخدمها فقط إذا كنت تعرف بالضبط ما تفعله.
\n\nحالة خاصة: Base64
\nإذ