Heim > Backend-Entwicklung > Golang > Wie erstelle ich in Go eine schnelle, zufällige Zeichenfolge mit einer festgelegten Länge?

Wie erstelle ich in Go eine schnelle, zufällige Zeichenfolge mit einer festgelegten Länge?

Linda Hamilton
Freigeben: 2024-10-24 01:40:02
Original
523 Leute haben es durchsucht

How Do I Generate a Quick, Random String of a Set Length in Go?

Wie erzeuge ich in Go eine zufällige Zeichenfolge fester Länge?

Problem

Ich möchte nur eine zufällige Zeichenfolge aus Zeichen (Groß- oder Kleinbuchstaben). ), keine Zahlen, in Go. Wie geht das am schnellsten und einfachsten?

Antwort

Die Frage sucht nach dem „schnellsten und einfachsten“ Ansatz. Pauls Antwort bietet eine einfache Technik. Betrachten wir jedoch auch den „schnellsten“ Aspekt. Wir werden unseren Code iterativ verfeinern und zu einer optimierten Lösung gelangen.

I. Verbesserungen

1. Genesis (Runen)

Die erste Lösung, die wir optimieren werden, ist:

<code class="go">import (
    "math/rand"
    "time"
)

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandStringRunes(n int) string {
    b := make([]rune, n)
    for i := range b {
        b[i] = letterRunes[rand.Intn(len(letterRunes))]
    }
    return string(b)
}</code>
Nach dem Login kopieren

2. Bytes

Wenn die für die Zufallszeichenfolge verwendeten Zeichen auf englische Groß- und Kleinbuchstaben beschränkt sind, können wir mit Bytes arbeiten, da die Buchstaben des englischen Alphabets 1:1 den Bytes in der UTF-8-Kodierung zugeordnet werden ( welches Go zum Speichern von Zeichenfolgen verwendet).

So können wir ersetzen:

<code class="go">var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")</code>
Nach dem Login kopieren
Nach dem Login kopieren

durch:

<code class="go">var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")</code>
Nach dem Login kopieren
Nach dem Login kopieren

Oder noch besser:

<code class="go">const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"</code>
Nach dem Login kopieren

Dies ist eine erhebliche Verbesserung, da wir jetzt eine Konstante verwenden können (Go unterstützt String-Konstanten, aber keine Slice-Konstanten). Zusätzlich wird auch der Ausdruck len(letters) konstant sein.

3. Rest

Vorherige Lösungen ermittelten eine Zufallszahl für einen Buchstaben durch den Aufruf von rand.Intn() (der an Rand.Intn() und weiter an Rand.Int31n() delegiert).

Dies ist langsamer als die Verwendung von rand.Int63(), die eine Zufallszahl mit 63 Zufallsbits erzeugt.

Wir können also einfach rand.Int63() aufrufen und den Rest nach der Division durch len(Buchstaben) verwenden:

<code class="go">func RandStringBytesRmndr(n int) string {
    b := make([]byte, n)
    for i := range b {
        b[i] = letters[rand.Int63() % int64(len(letters))]
    }
    return string(b)
}</code>
Nach dem Login kopieren

Dies geht schneller und behält gleichzeitig eine gleiche Wahrscheinlichkeitsverteilung aller Buchstaben bei (obwohl die Verzerrung vernachlässigbar ist, ist die Anzahl der Buchstaben 52 viel kleiner als 1<<63 - 1).

4. Maskierung

Wir können eine gleichmäßige Verteilung der Buchstaben aufrechterhalten, indem wir nur die niedrigsten Bits der Zufallszahl verwenden, die ausreichen, um die Anzahl der Buchstaben darzustellen. Für 52 Buchstaben werden 6 Bit benötigt: 52 = 110100b. Daher verwenden wir nur die niedrigsten 6 Bits der von rand.Int63() zurückgegebenen Zahl.

Wir „akzeptieren“ die Zahl auch nur, wenn sie im Bereich 0..len(letterBytes)-1 liegt . Wenn die niedrigsten Bits größer sind, verwerfen wir und fordern eine neue Nummer an.

<code class="go">const (
    letterIdxBits = 6                    // 6 bits to represent a letter index
    letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
)

func RandStringBytesMask(n int) string {
    b := make([]byte, n)
    for i := 0; i < n; {
        if idx := int(rand.Int63() & letterIdxMask); idx < len(letterBytes) {
            b[i] = letterBytes[idx]
            i++
        }
    }
    return string(b)
}
Nach dem Login kopieren

5. Maskierung verbessert

Die vorherige Lösung verwendet nur die niedrigsten 6 Bits der 63 Zufallsbits von rand.Int63(). Dies ist ineffizient, da das Erhalten der Zufallsbits der langsamste Teil unseres Algorithmus ist.

Da wir 52 Buchstaben haben, kodieren 6 Bits einen Buchstabenindex. Die 63 Zufallsbits können 63/6 = 10 verschiedene Buchstabenindizes bezeichnen. Nutzen wir alle 10:

const (
    letterIdxBits = 6                    // 6 bits to represent a letter index
    letterIdxMask = 1<= 0; {
        if remain == 0 {
            cache, remain = rand.Int63(), letterIdxMax
        }
        if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
            b[i] = letterBytes[idx]
            i--
        }
        cache >>= letterIdxBits
        remain--
    }
    return string(b)
}

6. Quelle

Masking Improved ist ziemlich effizient. Betrachten wir einen anderen Aspekt: ​​die Quelle von Zufallszahlen.

Das crypto/rand-Paket stellt die Funktion Read(b []byte) bereit. Dies würde jedoch der Leistung nicht helfen, da crypto/rand einen kryptografisch sicheren Pseudozufallszahlengenerator implementiert, der langsamer ist.

Wir bleiben also beim math/rand-Paket. rand.Rand verwendet eine rand.Source als Quelle für Zufallsbits. Wir können also direkt eine rand.Source verwenden:

<code class="go">import (
    "math/rand"
    "time"
)

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandStringRunes(n int) string {
    b := make([]rune, n)
    for i := range b {
        b[i] = letterRunes[rand.Intn(len(letterRunes))]
    }
    return string(b)
}</code>
Nach dem Login kopieren

7. Unter Verwendung von strings.Builder

Frühere Lösungen gaben Strings zurück, die zuerst in einem Slice erstellt wurden ([]rune in Genesis und anschließend []byte) und dann in String konvertiert wurden. Diese endgültige Konvertierung erfordert das Kopieren des Slice-Inhalts, da String-Werte unveränderlich sind.

Go 1.10 führte strings.Builder ein. Mit diesem neuen Typ können String-Inhalte ähnlich wie bytes.Buffer erstellt werden. Es verwendet intern ein []Byte und muss den Inhalt nicht kopieren, um die Zeichenfolge zu erstellen.

<code class="go">var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")</code>
Nach dem Login kopieren
Nach dem Login kopieren

8. „Imitiert“ strings.Builder mit dem Paket unsafe

strings.Builder erstellt einen String in einem internen []Byte, genau wie wir es selbst gemacht haben. Die Verwendung von strings.Builder führt also zu einem gewissen Overhead, den wir nur geändert haben, um das endgültige Kopieren zu vermeiden.

Wir können dieses Kopieren jedoch auch vermeiden, indem wir das Paket unsafe:

<code class="go">var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")</code>
Nach dem Login kopieren
Nach dem Login kopieren
verwenden

Das obige ist der detaillierte Inhalt vonWie erstelle ich in Go eine schnelle, zufällige Zeichenfolge mit einer festgelegten Länge?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage