สร้างข้อมูลสุ่มจำนวนที่แม่นยำใน C#

ฉันต้องการวิธีสร้างข้อมูลสุ่มหลอก (สตริง) จำนวนที่แม่นยำ ตัวอย่างเช่น ฉันต้องการเขียนโค้ดวิธีการที่ใช้อาร์กิวเมนต์สำหรับจำนวนไบต์เพื่อสร้างและส่งกลับสตริงที่มีขนาดที่แน่นอนนั้น

เดิมทีฉันตั้งใจจะสร้าง 1 ตัวอักษรต่อไบต์ที่ต้องการ แต่ดูเหมือนว่าอักขระจะไม่ใช่ไบต์ทั้งหมดอีกต่อไป

ความช่วยเหลือใด ๆ ที่ชื่นชม!


person Razick    schedule 26.09.2012    source แหล่งที่มา
comment
สตริงที่ถูกจำกัดไว้เฉพาะชุดอักขระ?   -  person Alex K.    schedule 26.09.2012
comment
วัดสตริงที่มีอยู่เพื่อกำหนดจำนวนไบต์ที่แน่นอน - อีกครั้ง ไม่ใช่ไบต์ทั้งหมดอีกต่อไป   -  person Henk Holterman    schedule 26.09.2012
comment
@อเล็กซ์เค ไม่จริงหรอก แค่ข้อมูลสตริงแบบสุ่ม   -  person Razick    schedule 26.09.2012
comment
@Henk Holterman ฉันต้องสามารถสร้างข้อมูลแบบสุ่มได้ กล่าวคือ มันจะต้องแตกต่างกันในแต่ละครั้ง ดังนั้นนอกเหนือจากการใช้สตริงขนาดเล็กหลาย ๆ ตัวที่บอกว่ายาว 10 ไบต์และประกอบเข้าด้วยกันแบบสุ่ม นั่นก็ไม่ได้ผลและนั่นก็ไม่ใช่วิธีแก้ปัญหาที่ดีสำหรับฉัน   -  person Razick    schedule 26.09.2012
comment
สตริงไม่มีไบต์เลย มีแต่อักขระ อักขระใช้หน่วยความจำสองไบต์ แต่ฉันไม่คิดว่านั่นคือสิ่งที่คุณต้องการ คุณยังสามารถเข้ารหัสสตริงเป็นไบต์ได้ แต่ความยาวจะแตกต่างกันไปขึ้นอยู่กับการเข้ารหัสที่ใช้ จุดประสงค์ในการรับสตริงที่สอดคล้อง (ในทางใดทางหนึ่ง) กับจำนวนไบต์คืออะไร? คุณจะใช้มันอย่างไร?   -  person Guffa    schedule 26.09.2012
comment
ความสัมพันธ์ระหว่างข้อมูลและข้อความดูเหมือนจะเบลอเล็กน้อยที่นี่ สตริงเป็นผลลัพธ์สุดท้ายหรือเป็นวิธีการรับไบต์หรือไม่?   -  person Henk Holterman    schedule 26.09.2012
comment
@HenkHolterman สตริงเป็นผลลัพธ์สุดท้าย   -  person Razick    schedule 26.09.2012
comment
ตกลง และคุณกำหนดขนาดเกี่ยวกับการนับถ่านหรือจำนวนไบต์หรือไม่   -  person Henk Holterman    schedule 26.09.2012
comment
@Guffa ฉันคิดว่าการเข้ารหัสสมัยใหม่เช่น Unicode และ utf-8 มีขนาดที่ใช้งานได้จริง (อักขระบางตัวอาจไม่ใช้พื้นที่เท่ากัน อธิบายได้ยากเล็กน้อยว่าฉันใช้อย่างไร แต่ข้อมูลแบบสุ่มจะถูกใส่ลงในไฟล์เพื่อใช้เป็นตัวยึดตำแหน่งสำหรับข้อมูลจริง   -  person Razick    schedule 26.09.2012
comment
@HenkHolterman ฉันไม่แน่ใจว่าคุณหมายถึงอะไร แต่ผลลัพธ์สุดท้าย (สตริง) จะต้องมีขนาดที่แม่นยำในหน่วยไบต์   -  person Razick    schedule 26.09.2012
comment
ต้องมีขนาดที่แน่นอนเป็นไบต์ - ตอนนี้คุณขัดแย้งกับตัวเองแล้ว สตริงมีตัวอักษรไม่ใช่ไบต์ sizeof(char) == 2 * sizeof(byte)   -  person Henk Holterman    schedule 26.09.2012
comment
สิ่งที่ฉันหมายถึงคือฉันต้องการความสามารถในการสร้างข้อมูลข้อความแบบสุ่มขนาด 1kb ขนาดของอักขระแต่ละตัวไม่เกี่ยวข้อง   -  person Razick    schedule 26.09.2012
comment
ค่อนข้างง่ายที่จะสร้างสตริงที่จะใช้จำนวนไบต์ที่ระบุเมื่อเข้ารหัส แต่ดูเหมือนว่าคุณต้องการสร้างตัวยึดตำแหน่งที่จะใช้จำนวนไบต์เท่ากันกับที่สตริงที่กำหนดเองจะใช้ และนั่นเป็นไปไม่ได้เพราะ จำนวนไบต์นั้นจะขึ้นอยู่กับว่าสตริงนั้นมีอะไรบ้าง และยังไม่ทราบแน่ชัด   -  person Guffa    schedule 26.09.2012
comment
@Guffa นั่นไม่เป็นเช่นนั้น สตริงสุ่มจะยังคงเติมไฟล์ต่อไปหลังจากจุดที่สตริงที่แทนที่ไฟล์สิ้นสุด   -  person Razick    schedule 27.09.2012
comment
@Razick: โอเค มันง่ายมาก :)   -  person Guffa    schedule 27.09.2012


คำตอบ (3)


ฉันแนะนำให้ใช้ RNGCryptoServiceProvider ซึ่งอาจสร้างได้มาก สุ่มไบต์ตามที่คุณต้องการ จากนั้นคุณสามารถแปลงเป็นสตริงได้ (เช่น ใช้การเข้ารหัส byte64 หรือวิธีอื่น)

อย่าลืมเพิ่ม using System.Security.Cryptography; ลงในไฟล์

public class RandomService : IDisposable
{
    private readonly RNGCryptoServiceProvider rngCsp;

    public CryptoService()
    {
        rngCsp = new RNGCryptoServiceProvider();            
    }

    public byte[] GetRandomBytes(int length)
    {
        var bytes = new byte[length];
        rngCsp.GetBytes(bytes);
        return bytes;
    }

    public string GetRandomString(int length)
    {
        var numberOfBytesForBase64 = (int) Math.Ceiling((length*3)/4.0);
        string base64String = Convert.ToBase64String(GetRandomBytes(numberOfBytesForBase64)).Substring(0, length); //might be longer because of padding            
        return base64String.Replace('+', '_').Replace('/', '-'); //we don't like these base64 characters
    }

    public void Dispose()
    {
        rngCsp.Dispose();
    }
}
person empi    schedule 26.09.2012
comment
ขนาดยังคงเท่าเดิมเมื่อแปลงเป็นสตริงหรือไม่ - person Razick; 26.09.2012
comment
คุณได้รับประมาณ 8/6 ถ่านต่อไบต์ - person Henk Holterman; 26.09.2012
comment
@Razick: ฐาน 64 นั้นยาวกว่าอาร์เรย์ไบต์เริ่มต้น ตรวจสอบการอัปเดตของฉัน - ฉันได้ให้โค้ดตัวอย่างแล้ว - person empi; 26.09.2012
comment
ขอบคุณ ฉันจะลองดู - person Razick; 26.09.2012
comment
RNG เป็นการสุ่มมาก แต่ก็อาจต้องใช้ความพยายามมากเกินไปในการสร้างข้อมูลทดสอบบางอย่าง แม้จะเป็นปัญหาหากคุณต้องการข้อมูลจำนวนมาก `Random.NextBytes()' ก็อาจจะใช้ได้เช่นกัน - person Henk Holterman; 26.09.2012
comment
@HenkHolterman: ใช่ นั่นเป็นเรื่องจริง ฉันใช้คลาสนี้ในสถานการณ์ที่ฉันต้องการข้อมูลสุ่มแบบเข้ารหัส (โดยเฉพาะรหัสเซสชัน) อย่างไรก็ตาม คุณอาจเปลี่ยนการใช้งาน GetRandomBytes และปล่อยให้ GetRandomString ไว้สำหรับการแปล - person empi; 26.09.2012
comment
@HenkHolterman ใช้งานได้ดีมาก ฉันจะลองทำตามคำแนะนำของคุณและดูว่าฉันจะได้ความเร็วที่ดีขึ้นหรือไม่ - person Razick; 26.09.2012
comment
@HenkHolterman การปรับปรุงความเร็วไม่มาก แต่มันสะอาดขึ้นเล็กน้อยดังนั้นฉันจะใช้มัน ขอบคุณ. - person Razick; 26.09.2012

คุณอาจใช้คลาส Random แปลงเป็น byte[] จากนั้น ToString()

person Amelia    schedule 26.09.2012
comment
แม้ว่าทุก string จะสามารถแปลงเป็น byte[] ได้ แต่ไม่ใช่ทุก byte[] ที่สามารถแปลงเป็นสตริงได้ - person dtb; 26.09.2012
comment
@dtb: ทุกไบต์[] สามารถแปลงเป็นสตริงได้ (เช่น base64 หรือการแปลตามอำเภอใจ) - person empi; 26.09.2012
comment
แต่อย่างที่ชื่อบอก มันใช้ตัวอักษรที่แตกต่างกันเพียง 64 ตัวเท่านั้น มีมากกว่านั้นในโลก Unicode - person Henk Holterman; 26.09.2012
comment
อักขระที่เป็นไปได้ 64 ตัวน่าจะใช้ได้จริง - person Razick; 26.09.2012

หากคุณใช้ชุดอักขระที่จำกัด คุณสามารถเลือกอักขระที่จะลงเอยเป็นโค้ดไบต์เดียวได้ไม่ว่าจะใช้การเข้ารหัสใดก็ตาม

public byte[] CreateFiller(int length, Random rnd) {
  string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  return Encoding.UTF8.GetBytes(Enumerable.Range(0, length).Select(i => chars[rnd.Next(chars.Length)]).ToArray());
}

// only use the overload that creates a Random object itself if you use it once, not in a loop
public byte[] CreateFiller(int length) {
  return CreateFiller(length, new Random());
}
person Guffa    schedule 26.09.2012