.net string.format - كيف يمكنني الحصول على تمثيل البايت المتناسق للسلاسل في C#بدون تحديد الترميز يدوياً؟




date (25)

كيف يمكنني تحويل string إلى byte[] في .NET (C #) دون تحديد ترميز معين يدويًا؟

سأقوم بتشفير السلسلة. يمكنني تشفيرها دون تحويل ، ولكنني لا زلت أرغب في معرفة سبب تشغيل التشفير هنا.

أيضا ، لماذا ينبغي أن تؤخذ الترميز في الاعتبار؟ لا يمكنني ببساطة الحصول على ما بايت تم تخزين السلسلة في؟ لماذا هناك اعتماد على ترميزات الشخصيات؟


Answers

C # لتحويل string إلى صفيف byte :

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}

كما يرجى توضيح سبب مراعاة الترميز. لا يمكنني ببساطة الحصول على ما بايت تم تخزين السلسلة في؟ لماذا هذا الاعتماد على الترميز؟

لأنه لا يوجد شيء اسمه "بايت السلسلة".

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

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

لذا ، باختصار ، فإن محاولة الحصول على "بايت من سلسلة بدون استخدام الترميزات" مستحيل مثل "كتابة نص دون استخدام أي لغة".

بالمناسبة ، أوصيك بشدة (وأي شخص ، لهذه المسألة) بقراءة هذه الحكمة الصغيرة: joelonsoftware.com/articles/Unicode.html


الإجابة المقبولة معقدة للغاية. استخدم فئات .NET المضمن لهذا:

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

لا تعيد اختراع العجلة إذا لم تكن مضطرًا ...


حسنا ، لقد قرأت جميع الإجابات وكانوا حول استخدام الترميز أو واحد عن التسلسل الذي يسقط بديلين غير مزايدات.

انها سيئة عندما تأتي السلسلة ، على سبيل المثال ، من SQL Server حيث تم بناءه من صفيف تخزين البايت ، على سبيل المثال ، تجزئة كلمة المرور. إذا قمنا بإسقاط أي شيء منه ، فسوف يقوم بتخزين تجزئة غير صالحة ، وإذا أردنا تخزينها في XML ، فنحن نريد أن نتركها سليمة (لأن كاتب XML يسقط استثناءً عن أي بديل غير مزاوج يجده).

لذلك أستخدم ترميز Base64 لصفائف البايتات في مثل هذه الحالات ، ولكن يا للهول ، يوجد على الإنترنت حل واحد لهذا في C # ، ولديه خلل فيه وهو طريقة واحدة فقط ، لذلك أصلحت الخطأ وأعدت كتابتي إجراء. أنت هنا ، موظفو Google المستقبليون:

public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}

تحتاج إلى أخذ الترميز بعين الاعتبار ، لأنه يمكن تمثيل حرف واحد بمقدار 1 بايت أو أكثر (حتى حوالي 6) ، وسوف تتعامل الترميزات المختلفة مع هذه البايتات بشكل مختلف.

جويل لديه نشر على هذا:

joelonsoftware.com/articles/Unicode.html


الجزء الأول من سؤالك (كيفية الحصول على وحدات البايت) تمت الإجابة عليه بالفعل من قبل الآخرين: ابحث في مساحة الاسم System.Text.Encoding .

سوف أتناول سؤال المتابعة الخاص بك: لماذا تحتاج إلى اختيار الترميز؟ لماذا لا يمكنك الحصول على ذلك من فئة السلسلة نفسها؟

الجواب في جزأين.

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

إذا كان برنامجك بالكامل داخل .Net world فلا داعي للقلق بشأن الحصول على صفائف بايت للسلاسل على الإطلاق ، حتى إذا كنت ترسل البيانات عبر شبكة. بدلاً من ذلك ، استخدم .Net Serialization للقلق بشأن نقل البيانات. لا تقلق بشأن البايتات الفعلية أكثر من ذلك: تنسيق المنسق يفعل ذلك نيابة عنك.

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

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

الذي يقودني إلى الجزء الثاني ... اختيار ترميز Unicode يخبر. صافي لاستخدام وحدات البايت الأساسية. أنت بحاجة إلى اختيار هذا الترميز ، لأنه عندما يخرج Unicode-Plus متضررًا جديدًا ، يجب أن يكون وقت تشغيل Net. مجانيًا لاستخدام هذا النموذج الجديد الأفضل للترميز دون كسر البرنامج. ولكن ، في الوقت الحالي (والمستقبل القريب) ، فإن اختيار ترميز Unicode يمنحك ما تريده.

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


BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());

With the advent of Span<T> released with C# 7.2, the canonical technique to capture the underlying memory representation of a string into a managed byte array is:

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

Converting it back should be a non-starter because that means you are in fact interpreting the data somehow, but for the sake of completeness:

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

The names NonPortableCast and DangerousGetPinnableReference should further the argument that you probably shouldn't be doing this.

Note that working with Span<T> requires installing the System.Memory NuGet package .

Regardless, the actual original question and follow-up comments imply that the underlying memory is not being "interpreted" (which I assume means is not modified or read beyond the need to write it as-is), indicating that some implementation of the Stream class should be used instead of reasoning about the data as strings at all.


simple code with LINQ

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

EDIT : as commented below, it is not a good way.

but you can still use it to understand LINQ with a more appropriate coding :

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();

يعتمد ذلك على ترميز السلسلة ( ASCII ، UTF-8 ، ...).

فمثلا:

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

عينة صغيرة لماذا ترميز الأمور:

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCII ببساطة ليست مجهزة للتعامل مع الشخصيات الخاصة.

داخليًا ، يستخدم .NET framework UTF-16 لتمثيل السلاسل ، لذلك إذا أردت الحصول على البايتات التي تستخدمها .NET ، استخدم System.Text.Encoding.Unicode.GetBytes (...) .

راجع تشفير الأحرف في .NET Framework (MSDN) لمزيد من المعلومات.


From byte[] to string :

        return BitConverter.ToString(bytes);

bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes

bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes

byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}

It depends on what you want the bytes FOR

This is because, as Tyler so aptly said , "Strings aren't pure data. They also have information ." In this case, the information is an encoding that was assumed when the string was created.

Assuming that you have binary data (rather than text) stored in a string

This is based off of OP's comment on his own question, and is the correct question if I understand OP's hints at the use-case.

Storing binary data in strings is probably the wrong approach because of the assumed encoding mentioned above! Whatever program or library stored that binary data in a string (instead of a byte[] array which would have been more appropriate) has already lost the battle before it has begun. If they are sending the bytes to you in a REST request/response or anything that must transmit strings, Base64 would be the right approach.

If you have a text string with an unknown encoding

Everybody else answered this incorrect question incorrectly.

If the string looks good as-is, just pick an encoding (preferably one starting with UTF), use the corresponding System.Text.Encoding.???.GetBytes() function, and tell whoever you give the bytes to which encoding you picked.


هذا سؤال شائع. من المهم أن نفهم ما الذي يطرحه مؤلف السؤال ، وأن الأمر يختلف عما هو على الأرجح هو الحاجة الأكثر شيوعًا. لتثبيط سوء استخدام الكود حيث لا توجد حاجة إليه ، أجبت على السؤال الأحدث أولاً.

حاجة مشتركة

كل سلسلة تحتوي على مجموعة أحرف وترميز. عند تحويل كائن System.String إلى صفيف من System.Byte لا يزال لديك مجموعة أحرف وترميز. بالنسبة إلى معظم الاستخدامات ، ستعرف مجموعة الأحرف والترميز التي تحتاجها ويجعل .NET من السهل "النسخ باستخدام التحويل". ما عليك سوى اختيار فئة Encoding المناسبة.

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

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

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

من الواضح أن التحويلات ليست بالضرورة ضائعة!

ملاحظة: بالنسبة لـ System.String فإن مجموعة حروف المصدر هي Unicode.

الشيء المربك الوحيد هو أن .NET تستخدم اسم مجموعة أحرف لاسم ترميز معين لمجموعة الأحرف تلك. يجب استدعاء Encoding.UTF16 .

هذا هو لمعظم الاستخدامات. إذا كان هذا ما تحتاجه ، فتوقف عن القراءة هنا. شاهد joelonsoftware.com/articles/Unicode.html المرح إذا كنت لا تفهم ما هو الترميز.

حاجة محددة

الآن ، يسأل كاتب السؤال ، "كل سلسلة يتم تخزينها كمصفوفة من البايتات ، أليس كذلك؟ لماذا لا يمكنني ببساطة الحصول على تلك البايتات؟"

لا يريد أي تحويل.

من مواصفات C # :

تستخدم معالجة الأحرف والصفوف في C # ترميز Unicode. يمثل نوع char وحدة ترميز UTF-16 ، ويمثل نوع السلسلة تسلسل وحدات كود UTF-16.

لذلك ، نعلم أنه إذا طلبنا التحويل الصفري (أي من UTF-16 إلى UTF-16) ، فسنحصل على النتيجة المرجوة:

Encoding.Unicode.GetBytes(".NET String to byte array")

ولكن لتجنب ذكر الترميزات ، يجب علينا القيام بذلك بطريقة أخرى. إذا كان نوع البيانات الوسيطة مقبولًا ، فهناك اختصار مفاهيمي لهذا:

".NET String to byte array".ToCharArray()

هذا لا يعطينا نوع البيانات المطلوب ، لكن إجابة مهرداد توضح كيفية تحويل صفيف Char إلى صفيف Byte باستخدام BlockCopy . ومع ذلك ، هذا ينسخ السلسلة مرتين! ويستخدم بشكل صريح للغاية رمز الترميز محددة: نوع البيانات System.Char .

الطريقة الوحيدة للوصول إلى وحدات البايت الفعلية التي يتم تخزين السلسلة فيها هي استخدام مؤشر. يسمح البيان fixed بأخذ عنوان القيم. من مواصفات C #:

[For] تعبيرًا عن سلسلة الكتابة ، ... يقوم المُهيء بحساب عنوان الحرف الأول في السلسلة.

للقيام بذلك ، تخطي المحول البرمجي التعليمات البرمجية تخطي عبر الأجزاء الأخرى من كائن سلسلة مع RuntimeHelpers.OffsetToStringData . لذلك ، للحصول على وحدات البايت الخام ، فقط إنشاء مؤشر إلى السلسلة ونسخ عدد البايتات المطلوبة.

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

كما أشارCodesInChaos ، فإن النتيجة تعتمد على endianness الجهاز. لكن صاحب السؤال لا يهتم بذلك.


Fastest way

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

EDIT as Makotosan commented this is now the best way:

Encoding.UTF8.GetBytes(text)

استعمال:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

The result is:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103

Simply use this:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);

جرب هذا ، رمز أقل بكثير:

System.Text.Encoding.UTF8.GetBytes("TEST String");

You can use following code to convert a string to a byte array in .NET

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);

The key issue is that a glyph in a string takes 32 bits (16 bits for a character code) but a byte only has 8 bits to spare. A one-to-one mapping doesn't exist unless you restrict yourself to strings that only contain ASCII characters. System.Text.Encoding has lots of ways to map a string to byte[], you need to pick one that avoids loss of information and that is easy to use by your client when she needs to map the byte[] back to a string.

Utf8 is a popular encoding, it is compact and not lossy.


فقط لإثبات أن إجابة Mehrdrad السليمة تعمل ، يمكن لمقاربته أن تستمر حتى في [BinaryFormatter (التي كان العديد منها قد وجهت ضد إجابتي ، ولكن الجميع متساوون في ذلك ، على سبيل المثال System.Text.Encoding.UTF8.GetBytes ، System.Text.Encoding.Unicode.GetBytes ؛ لا يمكن لأساليب الترميز هذه أن تستمر على الأحرف البديلة الكبيرة d800 على سبيل المثال ، وتلك فقط مجرد استبدال أحرف بديلة عالية مع القيمة fffd ):

using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }

    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }        
}

انتاج:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

حاول ذلك مع System.Text.Encoding.UTF8.GetBytes أو System.Text.Encoding.Unicode.GetBytes ، فإنها سوف تستبدل فقط أحرف بديلة عالية مع القيمة fffd

في كل مرة يكون هناك حركة في هذا السؤال ، ما زلت أفكر في مسلسل (سواء كان ذلك من Microsoft أو من مكون 3rd الطرف) التي يمكن أن تستمر السلاسل حتى يحتوي على أحرف بديلة غير مزاوجة ؛ أنا غوغل هذا كل الآن وبعد ذلك: التسلسل إزاحة شخصية بديلة . NET . هذا لا يجعلني أخسر أي نوم ، لكنه مزعج نوعًا ما بين الحين والآخر ، هناك شخص ما يعلق على جوابي بأنه معيوب ، ومع ذلك فإن إجاباتهم تشوبها عيوب متساوية عندما يتعلق الأمر بشخصيات بديلة غير مترابطة.

الرنة ، مايكروسوفت يجب أن تستخدم فقط System.Buffer.BlockCopy في BinaryFormatter لها

谢谢!


Here is my unsafe implementation of String to Byte[] conversion:

public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

It's way faster than the accepted anwser's one, even if not as elegant as it is. Here are my Stopwatch benchmarks over 10000000 iterations:

[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

In order to use it, you have to tick "Allow Unsafe Code" in your project build properties. As per .NET Framework 3.5, this method can also be used as String extension:

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}

Two ways:

public static byte[] StrToByteArray(this string s)
{
    List<byte> value = new List<byte>();
    foreach (char c in s.ToCharArray())
        value.Add(c.ToByte());
    return value.ToArray();
}

And,

public static byte[] StrToByteArray(this string s)
{
    s = s.Replace(" ", string.Empty);
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    return buffer;
}

I tend to use the bottom one more often than the top, haven't benchmarked them for speed.


الأهداف الرئيسية لشفرة بلدي هي:

  1. يكون توزيع السلاسل متماثلًا تقريبًا (لا تهتم بالانحرافات الطفيفة ، طالما أنها صغيرة)
  2. ينتج أكثر من بضعة مليارات من السلاسل لكل مجموعة حجة. إن توليد سلسلة تتكون من 8 أحرف (~ 47 بتة من الإنتروبيا) لا معنى لها إذا كان PRNG الخاص بك يولد قيمًا مختلفة 2 مليار (31 بت من الإنتروبيا).
  3. إنه آمن ، حيث أتوقع أن يستخدم الأشخاص ذلك لكلمات المرور أو الرموز الأمنية الأخرى.

ويتحقق الخاصية الأولى من خلال اتخاذ حجم 64 بت حجم حرف الأبجدية. بالنسبة للحروف الهجائية الصغيرة (مثل 62 حرفًا من السؤال) ، يؤدي هذا إلى تحيز لا يذكر. يتم تحقيق الخاصية الثاني والثالث باستخدام RNGCryptoServiceProvider بدلاً من System.Random .

using System;
using System.Security.Cryptography;

public static string GetRandomAlphanumericString(int length)
{
    const string alphanumericCharacters =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
        "abcdefghijklmnopqrstuvwxyz" +
        "0123456789";
    return GetRandomString(length, alphanumericCharacters);
}

public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
    if (length < 0)
        throw new ArgumentException("length must not be negative", "length");
    if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
        throw new ArgumentException("length is too big", "length");
    if (characterSet == null)
        throw new ArgumentNullException("characterSet");
    var characterArray = characterSet.Distinct().ToArray();
    if (characterArray.Length == 0)
        throw new ArgumentException("characterSet must not be empty", "characterSet");

    var bytes = new byte[length * 8];
    new RNGCryptoServiceProvider().GetBytes(bytes);
    var result = new char[length];
    for (int i = 0; i < length; i++)
    {
        ulong value = BitConverter.ToUInt64(bytes, i * 8);
        result[i] = characterArray[value % (uint)characterArray.Length];
    }
    return new string(result);
}




c# .net string