生成随机字符串,包括特殊字符

时间:2019-09-12 08:53:24

标签: excel vba

我有一个代码生成随机包含8个字符的字符字符串(密码)。我的问题是只填充数字和字符。

1)我想在混音中包括特殊字符,并确保每个字符串中始终至少包含一个特殊字符。

2)我需要添加一个条件,即每个字符串始终包含至少一个大写字母,至少一个小写字母,至少一个数字。

这是我的代码,但是我无法弄清楚如何包括这些条件以使其按需工作。我已经尝试了很多谷歌搜索,使其专用于此代码,但无法弄清楚。你能请教吗?

Sub MakeRandom()
    Dim J As Integer
    Dim K As Integer
    Dim L As Double
    Dim iTemp As Integer
    Dim sNumber As String
    Dim bOK As Boolean

    Range("G5:G148").Activate
    Randomize
    L = InputBox("Amount of Passwords:")
      For J = 1 To L
        sNumber = ""
        For K = 1 To 8
            Do
                iTemp = Int((122 - 48 + 1) * Rnd + 48)
                Select Case iTemp
                    Case 48 To 57, 97 To 122
                        bOK = True
                    Case Else
                        bOK = False
                End Select
            Loop Until bOK
            bOK = False
            sNumber = sNumber & Chr(iTemp)
        Next K
        ActiveCell.Value = sNumber
        ActiveCell.Offset(1, 0).Select
    Next J
End Sub

我将不胜感激。

3 个答案:

答案 0 :(得分:0)

为什么不引入包含所有合法字符的长字符串,然后让您的算法从该字符串的随机位置中选择字符?这样,您可以轻松控制密码中的内容。

为确保条件成立,我将密码生成置于无限循环中,该循环仅在满足所有条件时结束。只要这实际上是可能的(也就是说,您的条件可以同时全部成立),则此循环最终将终止(由于大数定律)。

答案 1 :(得分:0)

我有一些可能对您有所帮助的东西。我使用不同的方法,但结果应该相似。我已根据您的限制进行了调整,但可能遗漏了一些东西。

我的工作原理是这样的:我有一个名为ChrSrc的工作表,其中包含我希望能够包含在字符串中的所有字符。字符已分为四列。从A到D列是小写字母,大写字母,数字,特殊字符。

创建一个数组来存储字符并创建随机字符串。该数组包含3个“列”。第一个给出1到4之间的数字,以确定应该从哪一列获取其字符。前四个始终为1,2,3,4,以确保每种字符至少使用一次。随机填充其他4个(如果随机字符串较长则更多)。

然后在第二个“列”中填充实际字符以添加到随机字符串中。最后,第三个“列”用零填充。这些将用于跟踪随机字符串中使用了哪些字符。

一旦数组被填满,do while loop用于随机选择字符的顺序。添加字符后,将数组中的零更改为1,以确保每个字符都使用一次。

最后,您的随机字符串位于变量RandomString中,您可以将其写入单元格或对其进行任何操作。

如果您想一次创建多个字符串,建议您编写一个小的调用者子程序,该子程序调用此子程序的次数为x。或在其中添加一个循环和输入框。

希望有帮助。

Sub CreateString()
    Dim StringArray() As Variant
    Dim PositionCount As Long
    Dim Lr As Long
    Dim RandomString As String
    Dim arrIndex As Long
    Dim Loopcount As Long
    Dim StringLength As Long

    StringLength = 8

    ReDim StringArray(1 To StringLength, 1 To 3)

    For PositionCount = 1 To StringLength

        If PositionCount > 4 Then

            StringArray(PositionCount, 1) = Random(4)

        Else

            StringArray(PositionCount, 1) = PositionCount

        End If
        'lastrow for each character category, adjust as needed
        Select Case StringArray(PositionCount, 1)
            Case Is <= 2
                Lr = 26
            Case Is = 3
                Lr = 10
            Case Is = 4
                Lr = 17
        End Select

        StringArray(PositionCount, 2) = ThisWorkbook.Sheets("ChrSrc").Cells(Random(Lr), StringArray(PositionCount, 1))
        StringArray(PositionCount, 3) = 0

    Next

    Do While Len(RandomString) < StringLength

        arrIndex = Random(StringLength)

        If StringArray(arrIndex, 3) = 0 Then

            RandomString = RandomString & StringArray(arrIndex, 2)
            StringArray(arrIndex, 3) = 1

        End If
        Loopcount = Loopcount + 1

    Loop


 End Sub

 Function Random(Max As Long)

    Random = Int(Max * Rnd) + 1

 End Function

答案 2 :(得分:0)

  • 在可能的情况下,建议避免使用ActivateSelect。在您的情况下,您可以创建一个随机字符串数组,然后将该数组写入工作表。数组的长度可以由InputBox返回的值控制。
  • 您的代码可能会受益于:L = InputBox("Amount of Passwords:", Type:=1),如果我正确阅读了文档,它将验证输入为数字。
  • 我的理解是,在正常情况下,您应该使用类型Long而不是Integer(因为Integer现在已经转换为Long了)。此外,在这种情况下,您将收到任意用户输入,Integer类型将在32768处溢出。例如,如果您在InputBox中输入32768(例如)或更大的数字,则会看到未处理的溢出错误。

参考此答案(https://stackoverflow.com/a/57903244/8811778)中描述的方法:

Option Explicit

Private Function CreateRandomString(Optional ByVal lengthOfOutput As Long = 8, Optional ByVal minimumCountOfNumbers As Long = 1, Optional ByVal minimumCountOfLetters As Long = 1, Optional ByVal minimumCountOfSymbols As Long = 1) As String

    Dim countRemaining As Long
    countRemaining = lengthOfOutput - (minimumCountOfLetters + minimumCountOfNumbers + minimumCountOfSymbols)

    Debug.Assert countRemaining >= 0

    Const LETTERS_ALLOWED As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    Const NUMBERS_ALLOWED As String = "0123456789"
    Const SYMBOLS_ALLOWED As String = "!""£$%^&*()-_+[]{};:'@#" ' Change as necessary, I do not know what symbols you want included.

    Dim toJoin() As String
    ReDim toJoin(1 To 4)

    toJoin(1) = GetRandomCharactersFromText(LETTERS_ALLOWED, minimumCountOfLetters, duplicatesAllowed:=False)
    toJoin(2) = GetRandomCharactersFromText(NUMBERS_ALLOWED, minimumCountOfNumbers, duplicatesAllowed:=False)
    toJoin(3) = GetRandomCharactersFromText(SYMBOLS_ALLOWED, minimumCountOfSymbols, duplicatesAllowed:=False)

    ' I arbitrarily pad the rest of the string with random letters, but you can change this logic.
    toJoin(4) = GetRandomCharactersFromText(LETTERS_ALLOWED, countRemaining, duplicatesAllowed:=False)

    Dim outputString As String
    outputString = Join(toJoin, vbNullString)

    ' This step is meant to scramble the characters in the string.
    ' Otherwise, the returned string's structure would reflect the code above:
    '   • w letters, followed by x numbers, followed by y symbols, followed by z characters
    ' which stops it being pseudo-random.
    outputString = GetRandomCharactersFromText(outputString, Len(outputString), False)
    CreateRandomString = outputString
End Function

Private Function RandomBetween(ByVal lowerLimit As Long, ByVal upperLimit As Long) As Long
    ' Could use Application.RandBetween instead (maybe). But maybe there is some performance difference.
    ' https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/rnd-function
    RandomBetween = Int((upperLimit - lowerLimit + 1) * Rnd + lowerLimit)
End Function

Private Function GetRandomCharactersFromText(ByVal someText As String, ByVal numberOfCharactersToGet As Long, Optional ByVal duplicatesAllowed As Boolean = True) As String
    ' Returns n characters from a given string. Characters are chosen pseudo-randomly.
    ' "duplicatesAllowed" controls whether a given index can be chosen more than once.

    Dim chosenIndexes() As Long
    ReDim chosenIndexes(1 To numberOfCharactersToGet)

    Dim characterIndex As Long
    For characterIndex = 1 To numberOfCharactersToGet
        Do While True
            Dim randomCharacterIndex As Long
            randomCharacterIndex = RandomBetween(1, Len(someText))

            If duplicatesAllowed Then Exit Do
            If IsError(Application.Match(randomCharacterIndex, chosenIndexes, 0)) Then Exit Do
        Loop
        chosenIndexes(characterIndex) = randomCharacterIndex
    Next characterIndex

    Dim chosenCharacters() As String
    ReDim chosenCharacters(1 To numberOfCharactersToGet)

    For characterIndex = 1 To numberOfCharactersToGet
        randomCharacterIndex = chosenIndexes(characterIndex)
        chosenCharacters(characterIndex) = Mid(someText, randomCharacterIndex, 1)
    Next characterIndex

    GetRandomCharactersFromText = Join(chosenCharacters, vbNullString)
End Function
  • 这只是我对用户发布的方法的解释。该用户可能以不同的方式实施了他们的方法。
  • 大部分工作由GetRandomCharactersFromText函数完成。
  • 您可能可以摆脱嵌套的For K = 1 to 8循环,并用ActiveCell.Value = CreateRandomString(lengthOfOutput:=8, minimumCountOfNumbers:=1, minimumCountOfSymbols:=1)之类的东西替换(尽管您应该避免使用ActiveCell,并且通常依赖于活动对象) 。
  • 最后,根据您代码的某些部分,该代码似乎旨在生成密码。我不是安全专家,所以我将避免提供与安全有关的建议/建议。阅读https://xkcd.com/936/和相关讨论https://security.stackexchange.com/a/6096/71460可能会或可能不会使您受益。