أسرع طريقة لتحويل ربما خالية إنهاء ascii byte[] إلى سلسلة ؟

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

  •  02-07-2019
  •  | 
  •  

سؤال

أنا في حاجة لتحويل (ربما) null إنهاء مجموعة من ascii بايت إلى سلسلة في C# و أسرع طريقة وجدتها للقيام بذلك هي باستخدام بلدي UnsafeAsciiBytesToString الطريقة الموضحة أدناه.يستخدم هذا الأسلوب السلسلة.سلسلة(sbyte*) منشئ الذي يحتوي على تحذير في ملاحظات:

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

ملاحظة: * لأن صفحة رموز ANSI الافتراضي هو نظام يعتمد على السلسلة التي تم إنشاؤها بواسطة هذا المنشئ من مطابقة التوقيع بايت المصفوفات قد تختلف على أنظمة مختلفة.* ...

* إذا كان المحدد مجموعة غير خالية منتهية ، سلوك هذا المنشئ هو نظام يعتمد.على سبيل المثال, مثل هذه الحالة قد يؤدي إلى انتهاك حقوق الوصول.* "

الآن أنا متأكد أن الطريق السلسلة المشفرة لن يتغير أبدا...ولكن الافتراضي الشفرة على نظام بلدي التطبيق يعمل على قد تغير.هل هناك أي سبب من الأسباب التي لا يجب الهروب من استخدام سلسلة.سلسلة(sbyte*) لهذا الغرض ؟

using System;
using System.Text;

namespace FastAsciiBytesToString
{
    static class StringEx
    {
        public static string AsciiBytesToString(this byte[] buffer, int offset, int maxLength)
        {
            int maxIndex = offset + maxLength;

            for( int i = offset; i < maxIndex; i++ )
            {
                /// Skip non-nulls.
                if( buffer[i] != 0 ) continue;
                /// First null we find, return the string.
                return Encoding.ASCII.GetString(buffer, offset, i - offset);
            }
            /// Terminating null not found. Convert the entire section from offset to maxLength.
            return Encoding.ASCII.GetString(buffer, offset, maxLength);
        }

        public static string UnsafeAsciiBytesToString(this byte[] buffer, int offset)
        {
            string result = null;

            unsafe
            {
                fixed( byte* pAscii = &buffer[offset] )
                { 
                    result = new String((sbyte*)pAscii);
                }
            }

            return result;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            byte[] asciiBytes = new byte[]{ 0, 0, 0, (byte)'a', (byte)'b', (byte)'c', 0, 0, 0 };

            string result = asciiBytes.AsciiBytesToString(3, 6);

            Console.WriteLine("AsciiBytesToString Result: \"{0}\"", result);

            result = asciiBytes.UnsafeAsciiBytesToString(3);

            Console.WriteLine("UnsafeAsciiBytesToString Result: \"{0}\"", result);

            /// Non-null terminated test.
            asciiBytes = new byte[]{ 0, 0, 0, (byte)'a', (byte)'b', (byte)'c' };

            result = asciiBytes.UnsafeAsciiBytesToString(3);

            Console.WriteLine("UnsafeAsciiBytesToString Result: \"{0}\"", result);

            Console.ReadLine();
        }
    }
}
هل كانت مفيدة؟

المحلول

أي سبب لعدم استخدام String(sbyte*, int, int) منشئ ؟ إذا كنت قد عملت من أي جزء من المنطقة العازلة تحتاج بقية يجب أن تكون بسيطة:

public static string UnsafeAsciiBytesToString(byte[] buffer, int offset, int length)
{
    unsafe
    {
       fixed (byte* pAscii = buffer)
       { 
           return new String((sbyte*)pAscii, offset, length);
       }
    }
}

إذا كنت بحاجة إلى أن ننظر أولا:

public static string UnsafeAsciiBytesToString(byte[] buffer, int offset)
{
    int end = offset;
    while (end < buffer.Length && buffer[end] != 0)
    {
        end++;
    }
    unsafe
    {
       fixed (byte* pAscii = buffer)
       { 
           return new String((sbyte*)pAscii, offset, end - offset);
       }
    }
}

إذا كان هذا حقا هو سلسلة ASCII (أيكل بايت أقل من 128) ثم الشفرة المشكلة لا ينبغي أن يكون مشكلة إذا لم يكن لديك خاصة غريب الافتراضي الشفرة التي لا تستند إلى ASCII.

من الفائدة, هل فعلا لمحة التطبيق الخاص بك للتأكد من أن هذا هو حقا عنق الزجاجة ؟ هل تحتاج بالتأكيد المطلق أسرع التحويل بدلا من واحد الذي هو أكثر قابلية للقراءة (على سبيل المثالباستخدام ترميز.GetString المناسبة ترميز)?

نصائح أخرى

Oneliner (على افتراض العازلة في الواقع يحتوي على واحد مهيأ بشكل جيد null إنهاء سلسلة):

String MyString = Encoding.ASCII.GetString(MyByteBuffer).TrimEnd((Char)0);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestProject1
{
    class Class1
    {
    static public string cstr_to_string( byte[] data, int code_page)
    {
        Encoding Enc = Encoding.GetEncoding(code_page);  
        int inx = Array.FindIndex(data, 0, (x) => x == 0);//search for 0
        if (inx >= 0)
          return (Enc.GetString(data, 0, inx));
        else 
          return (Enc.GetString(data)); 
    }

    }
}

أنا لست متأكدا من السرعة, ولكن وجدت أنه من الأسهل استخدام LINQ لإزالة بالقيم الخالية قبل الترميز:

string s = myEncoding.GetString(bytes.TakeWhile(b => !b.Equals(0)).ToArray());
s = s.Substring(0, s.IndexOf((char) 0));

احتمال واحد في الاعتبار:تأكد من أن التعليمات البرمجية الافتراضية-الصفحة هو مقبول واستخدام هذه المعلومات لتحديد آلية التحويل في وقت التشغيل.

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

سهلة / آمنة / طريقة سريعة لتحويل byte[] الكائنات السلاسل التي تحتوي على ASCII ما يعادل والعكس باستخدام .صافي النظام الطبقي.النص.ترميز.الطبقة لديه وظيفة ثابتة أن يعود ASCII التشفير:

من سلسلة byte[]:

string s = "Hello World!"
byte[] b = System.Text.Encoding.ASCII.GetBytes(s);

من byte[] سلسلة:

byte[] byteArray = new byte[] {0x41, 0x42, 0x09, 0x00, 0x255};
string s = System.Text.Encoding.ASCII.GetString(byteArray);

هذا هو قبيح قليلا ولكن لم يكن لديك إلى استخدام تعليمات برمجية غير آمنة:

string result = "";
for (int i = 0; i < data.Length && data[i] != 0; i++)
   result += (char)data[i];
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top