Laden...

Klasse für Zufallszahlen und Zeichenfolgen

Erstellt von Stipo vor 14 Jahren Letzter Beitrag vor 14 Jahren 7.507 Views
Stipo Themenstarter:in
699 Beiträge seit 2007
vor 14 Jahren
Klasse für Zufallszahlen und Zeichenfolgen

Beschreibung:

Hallo zusammen,
ich habe mir eine Klasse geschrieben, die Zufallszahlen und Zufallszeichenfolgen in beliebiger Länge erstellen kann.

Man kann die Klasse nutzen, um z.B. Passwörter oder Zeichenfolgen für Captcha erzeugen zu lassen. Dazu kann man über ein Enum den Typ des RandomString festlegen, der erzeugt werden soll.

Mögliche Typen:
-- RandomStringType.Numbers ( Es werden nur Zahlen erstellt )
-- RandomStringType.Letters ( Es werden nur Buchstaben erstellt )
-- RandomStringType.Both ( Es werden Zahlen und Buchstaben erstellt )

Öffentliche Methode um den RandomString zu erstellen, hat 3 Überladungen.

Per Default sind folgende Werte eingestellt:
RandomDigits = 5 ( Anzahl der Zeichen )
RandomStringType = RandomStringType.Numbers ( Zahlen erstellen )
RandomUseUpperCases = true ( Erstellt per Zufall Großbuchstaben )

Alle Werte lassen sich über Properties einstellen.

Die Cracks hier dürfen mich gerne steinigen, wenn ich grobe Fehler in meiner Klasse habe 😃 Durch Fehler lernt man Fehler zu vermeiden 😉

Ich hoffe die Klasse kann noch jemand gebrauchen.

Grüße Stephan

Aufgerufen kann die Funktion zB folgend:



// Eine Zufallszahl mit 5 Zahlen
string rndString;
RandomStringClass random = new RandomStringClass();
rndString = random.GetRandomString();

// Eine Zufallszeichenfolge ( Buchstaben ) mit 5 Zeichen
string rndString;
RandomStringClass random = new RandomStringClass();
rndString = random.GetRandomString(RandomStringType.Letters);

// Eine Zufallszeichenfolge ( Buchstaben ) mit 10 Zeichen
string rndString;
RandomStringClass random = new RandomStringClass();
rndString = random.GetRandomString(10, RandomStringType.Letters);

Hier noch der Code der Klasse und des Enum.


public class RandomStringClass
    {
        #region Private Byte Arrays
        // Großbuchstaben werden errechnet
        // Alle Buchstaben (a-z)
        private byte[] _arrLetters = new byte[26] { 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 
            107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 };

        // Alle Zahlen (0-9)
        private byte[] _arrNumbers = new byte[10] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 };

        // Großbuchstaben werden errechnet
        // Alle Zahlen und Buchstaben (0-9 / a-z)
        private byte[] _arrNumbersletters = new byte[36] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
            97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
            114, 115, 116, 117, 118, 119, 120, 121, 122 };
        #endregion

        #region Member Variablen
        private Random ucaseRandom = new Random();
        private Random random = new Random();
        #endregion

        #region Properties

        /// <summary>
        /// RandomDigits Property
        /// </summary>
        private int _randomDigits;
        public int RandomDigits
        {
            get { return _randomDigits; }
            set { this.SetPropertieDigits(value); }
        }

        /// <summary>
        /// RandomString Property
        /// </summary>
        private string _randomString;
        public string RandomString
        {
            get { return _randomString; }
        }

        /// <summary>
        /// RandomStringType Property
        /// </summary>
        private RandomStringType _randomStringType;
        public RandomStringType RandomStringType
        {
            get { return _randomStringType; }
            set { _randomStringType = value; }
        }

        /// <summary>
        /// RandomUseUpperCases Property
        /// </summary>
        private bool _randomUseUpperCases;
        public bool RandomUseUpperCases
        {
            get { return _randomUseUpperCases; }
            set { _randomUseUpperCases = value; }
        }    

        #endregion

        #region Private Propertie Check

        /// <summary>
        /// Prüft den übergebenen Digit Wert
        /// </summary>
        /// <param name="digits">Der Digit Wert</param>
        private void SetPropertieDigits(int digits)
        {
            if (!(digits < 1))
            {
                _randomDigits = digits;
            }
            else
            {
                throw new ArgumentOutOfRangeException("RandomDigits", digits,
                    "RandomDigits darf nicht kleiner 1 sein.");
            }
        }

        #endregion
        
        #region Konstruktoren

        /// <summary>
        /// Standard Konstruktor
        /// </summary>
        public RandomStringClass()
        {
            this._randomDigits = 5;
            this._randomString = String.Empty;
            this._randomStringType = RandomStringType.Numbers;
            this.RandomUseUpperCases = true;
        }
        
        #endregion

        #region Public Methoden

        /// <summary>
        /// Erzeugt einen String mit Zufallszahlen mit fester Länge(5)
        /// </summary>
        /// <returns>String mit Zufallszahlen</returns>
        public string GetRandomString()
        {
            this.MakeRandomString();
            return this._randomString;
        }

        /// <summary>
        /// Erzeugt einen String mit Zufallszahlen in einstellbarer Länge(digits)
        /// </summary>
        /// <param name="digits">Die Anzahl der Zeichen</param>
        /// <returns>String mit Zufallszahlen</returns>
        public string GetRandomString(int digits)
        {
            this.SetPropertieDigits(digits);
            this.MakeRandomString();
            return this._randomString;
        }

        /// <summary>
        /// Erstellt einen String mit Zufallszeichen mit fester Länge(5) eines bestimmten Typs
        /// </summary>
        /// <param name="type">Der zu erstellende Typ</param>
        /// <returns>String mit Zufallszeichen des gewählten Typs</returns>
        public string GetRandomString(RandomStringType type)
        {
            this._randomStringType = type;
            this.MakeRandomString();
            return this._randomString;
        }

        /// <summary>
        /// Erstellt einen String mit Zufallszeichen mit einstellbarer Länge(digits)
        /// eines einstellbaren Typs(RandomStringType)
        /// </summary>
        /// <param name="digits">Die Anzahl der Zeichen</param>
        /// <param name="type">Der zu erstellende Typ</param>
        /// <returns>String mit Zufallszeichen der gewählten Länge und Typs</returns>
        public string GetRandomString(int digits, RandomStringType type)
        {
            this.SetPropertieDigits(digits);
            this._randomStringType = type;
            this.MakeRandomString();
            return this._randomString;
        }

        #endregion        

        #region Private Methoden

        /// <summary>
        /// Prüft den Typ des zu erstellenden String 
        /// und führt die entsprechende Methode aus
        /// </summary>
        private void MakeRandomString()
        {
            if (this._randomStringType == RandomStringType.Letters)
            {
                this.MakeString(this._arrLetters, this._randomDigits);
            }
            else if (this._randomStringType == RandomStringType.Both)
            {
                this.MakeString(this._arrNumbersletters, this._randomDigits);
            }
            else
            {
                this.MakeString(this._arrNumbers, this._randomDigits);
            }
        }

        /// <summary>
        /// Erstellt eine Zufalls Zeichenfolge
        /// </summary>
        /// <param name="array">Das Rohe Zeichen Byte Array</param>
        /// <param name="digits">Die Anzahl der zu erstellenden Zeichen</param>
        private void MakeString(byte[] array, int digits)
        {
            byte[] randomNumbers = this.TmpByteNumbers(array, digits);
            for (int i = 0; i < digits; i++)
            {
                this._randomString = String.Concat(this._randomString,
                    Convert.ToString((char)this.UpperCaseString(randomNumbers[i])));
            }
        }
                
        /// <summary>
        /// Erstellt ein Byte Array mit Zeichen in übergebener Größe
        /// </summary>
        /// <param name="arr">Das Rohe Byte Array mit den Zeichen</param>
        /// <param name="digits">Die Anzahl der zu erstellenden Zeichen</param>
        /// <returns>Ein Byte Array mit Zeichen</returns>
        private byte[] TmpByteNumbers(byte[] arr, int digits)
        {
            byte[] randomNumbers = new byte[digits];
            for (int i = 0; i < digits; i++)
            {
                randomNumbers[i] = arr[random.Next(0, arr.Length - 1)];
            }
            return randomNumbers;
        }

        /// <summary>
        /// Wandelt nach dem Zufallsprinzip ein Zeichen in Großschreibung um
        /// </summary>
        /// <param name="str">Ein Byte</param>
        /// <returns>Ein Byte</returns>
        private byte UpperCaseString(byte str)
        {
            if (this._randomUseUpperCases)
            {
                if (ucaseRandom.Next(3) == 2)
                {
                    return (byte)(str - 32);
                }
                return str;
            }
            return str;
        }
        #endregion
    }


/// <summary>
    /// Legt den Typ des Random String fest
    /// </summary>
    public enum RandomStringType
    {
        /// <summary>
        /// Nur Zahlenreihen
        /// </summary>
        Numbers = 0,
        /// <summary>
        /// Nur Buchstabenreihen
        /// </summary>
        Letters = 1,
        /// <summary>
        /// Zahlen und Buchstaben
        /// </summary>
        Both = 2
    }

Schlagwörter: Zufallszahlen, Zufallszeichen, Random, Passwort

946 Beiträge seit 2008
vor 14 Jahren
// Großbuchstaben werden errechnet  
// Alle Buchstaben (a-z)  
private byte[] _arrLetters = new byte[26] { 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 };  
  
// Alle Zahlen (0-9)  
private byte[] _arrNumbers = new byte[10] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 };  
  
// Großbuchstaben werden errechnet  
// Alle Zahlen und Buchstaben (0-9 / a-z)  
private byte[] _arrNumbersletters = new byte[36] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,  
114, 115, 116, 117, 118, 119, 120, 121, 122 };  

Das finde ich etwas unötig. Denn es lassen sich ja eigentlich alle Zeichen errechnen.

(char)r.Next('a', 'z' + 1); // Kleinbuchstabe
(char)r.Next('A', 'A' + 1); // Grossbuchstabe
(char)r.Next('0', '9' + 1); // Zahl

// Bei allen Zahlen und Buchstaben muss man etwas tricksen (ungetestet)
char random = (char)r.Next('0', ('Z' + 1) - 'a' + ('9' + 1)); // Zahl, Gross- oder
if (random > '9') random = (char)(random + ('a' - '9' + 1));  // Kleinbuchstabe

Eventuell könnte man die Random-Klasse auch durch den RNGCryptoServiceProvider ersetzen (bessere Zufallszahlen).

mfg
SeeQuark

B
21 Beiträge seit 2008
vor 14 Jahren

Hallo,

bei der Initialisierung der Random-Instanz würde ich den Tick der CPU mitgeben. Damit wird das Objekt stets anders initialisiert. --> bessere Zufallszahlen

Das folgende würde ich persönlich in einen Switch-Case-Block packen.


private void MakeRandomString()
        {
            if (this._randomStringType == RandomStringType.Letters)
            {
                this.MakeString(this._arrLetters, this._randomDigits);
            }
            else if (this._randomStringType == RandomStringType.Both)
            {
                this.MakeString(this._arrNumbersletters, this._randomDigits);
            }
            else
            {
                this.MakeString(this._arrNumbers, this._randomDigits);
            }
        }

Das innere "return str" ist überflüssig. Noch schöner wäre es natürlich, wenn
im innersten der String neu gesetzt wird und erst mit dem letzten Return zurück gegeben wird.


private byte UpperCaseString(byte str)
        {
            if (this._randomUseUpperCases)
            {
                if (ucaseRandom.Next(3) == 2)
                {
                    return (byte)(str - 32);
                }
               return str;
            }
            return str;
        }

also eher so


private byte UpperCaseString(byte str)
        {
            if (this._randomUseUpperCases)
            {
                if (ucaseRandom.Next(3) == 2)
                {
                    str = (byte)(str - 32);
                }
            }
            return str;
        }

Man sollte die Methode nicht aus irgendwelche if-blöcken heraus verlassen.

Schau es mir spätere noch etwas genauer an.

MfG
billy

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo Stipo,

bei der Initialisierung der Random-Instanz würde ich den Tick der CPU mitgeben.

wenn man ein Random-Objekt ohne Parameter erzeugt, passiert intern genau das. Insofern ist es ok, wie Stipo es gemacht hat, und muss und sollte nicht geändert werden.

Das innere "return str" ist überflüssig. Noch schöner wäre es natürlich, wenn
im innersten der String neu gesetzt wird und erst mit dem letzten Return zurück gegeben wird.

Das ist reine Geschmackssache (ich fände das im Gegenteil hässlicher) und daher dem Programmier überlassen. Über Geschmack sollten wir in "Projekte" ohnehin nicht streiten.

Man sollte die Methode nicht aus irgendwelche if-blöcken heraus verlassen.

Manche sehen das so, andere sehen es anders und sagen, man sollte return an allen Zweigen verwenden, wo die Verarbeitung abgeschlossen ist, damit man beim Lesen des Code den Zweig gedanklich abhaken kann und gleichzeitig oft Einrückungstiefe spart. Es ist eben Geschmackssache. Das wollte ich aufzeigen. Über Geschmack sollten wir in "Projekte" nicht streiten.

Hallo Stipo,

wenn man auf die vorgegebenen Zeichen-Klassen beschränkt ist, halte ich das für eine unnötige Einschränkung in der Flexibilität. Du solltest noch eine Methode machen, der man ein eigenes char-Array mit den Zeichen, aus denen gewählt werden soll, übergeben kann.

herbivore

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 14 Jahren

Hallo zusammen,

danke für die Tips die Ihr mir gegeben habt. Werde davon sicher ein paar in der Klasse umsetzen, wenn ich die Klasse noch erweitere ( Hab noch 2-3 Ideen ).

Schön, das euch aber allgemein keine groben Schnitzer aufgefallen sind.
Das bestätigt dann mein Programmierstil und meine Kenntnisse, die ich schon erlangen konnte. Lesen und noch mal lesen, das hilft eben doch 😉

Grüße Stephan