吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 326|回复: 9
收起左侧

[经验求助] c# 如何更高效率的随机一个位数较长的字符串

[复制链接]
夜雨闻笛 发表于 2024-7-7 07:46
25吾爱币
大佬们好,小白又来问小白问题了,新手写代码天天都是问题,只能厚着脸皮来求大佬指教,希望大佬们能帮帮忙祝大佬们生活顺心,薪水年年暴涨。

问题:取较长长度的随机字符串,一种是数字字符串,一种是字母字符串。我自己现在用的代码如下:






求助原因:感觉运行有点慢。
以10万次为例:字母字符串(生成长度为10)超过1200毫秒,如果是大小混合时间更是会翻倍。数字字符串会快一些,但也有270毫秒左右。
要求:用C#语言,尽可能高效率的优化。
[Asm] 纯文本查看 复制代码
string 取随机数字字符串(){
    string 返回字符串 = "";
    for (int i = 0; i < 2; i++)
    {
        int a = 取随机整数(0, int.MaxValue);
        if (a >= 1000000000)
        {
            返回字符串 += a.ToString();
        }
        else
        {
            返回字符串 += a.ToString().PadLeft(10, '0');
        }
    }
    return 返回字符串;
}

string 取随机x个字母(int 要几个字母, byte 大写填1小写填2混合填3)
{
    string 返回字符串 = "";
    int 随机数;
    char 字符;
    if (大写填1小写填2混合填3 == 1)
    {
        for (int j = 0; j < 要几个字母; j++)
        {
            随机数 = 取随机整数(65, 91);
            字符 = (char)随机数;
            返回字符串 += 字符;
        }
    }
    else if (大写填1小写填2混合填3 == 2)
    {
        for (int j = 0; j < 要几个字母; j++)
        {
            随机数 = 取随机整数(97, 123);//小写范围97~122
            while (随机数 == 108) //永远不会取到不好辨认的L小写字母,l编码108 
            {
                随机数 = 取随机整数(97, 123);
            }
            字符 = (char)随机数;
            返回字符串 += 字符;
        }
    }
    else
    {
        for (int j = 0; j < 要几个字母; j++)
        {
            if (取随机整数(1, 3) == 1)
            {
                随机数 = 取随机整数(65, 91);
            }
            else
            {
                随机数 = 取随机整数(97, 123);
            }
            while (随机数 == 73 || 随机数 == 108)//如果是混合大小写,那么I和L都不能随机到   因为大写I和小写L很容易弄混
            {
                if (取随机整数(1, 3) == 1)
                {
                    随机数 = 取随机整数(65, 91);
                }
                else
                {
                    随机数 = 取随机整数(97, 123);
                }
            }
            字符 = (char)随机数;
            返回字符串 += 字符;
        }
    }

    return 返回字符串;
}

int 取随机整数(int 最小值, int 最大值)
{
    byte[] b = Guid.NewGuid().ToByteArray();
    int b1 = BitConverter.ToInt32(b, 0);
    Random ran = new(b1);
    return ran.Next(最小值, 最大值);
}



不知道有没有精研效率秘法的精锐大佬出手帮忙优化一下?

最佳答案

查看完整内容

32位字符……没有运行测试,供您参考: [mw_shl_code=csharp,true]using System; using System.Security.Cryptography; using System.Runtime.CompilerServices; public static class PasswordGenerator { private static readonly RNGCryptoServiceProvider SharedRng = new RNGCryptoServiceProvider(); private const string CharSet = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()-_=+ ...

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

shuisanyue 发表于 2024-7-7 07:46
32位字符……没有运行测试,供您参考:


[C#] 纯文本查看 复制代码
using System;
using System.Security.Cryptography;
using System.Runtime.CompilerServices;
public static class PasswordGenerator
{
    private static readonly RNGCryptoServiceProvider SharedRng = new RNGCryptoServiceProvider();
    private const string CharSet = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()-_=+[]{}|;:,.<>?";
    private const int CharSetSize = CharSet.Length;
    public static string GenStr(int length)
    {
        var result = new char[length];
        Span<byte> bytes = stackalloc byte[length * 4];
        SharedRng.GetBytes(bytes);
        for (int i = 0, j = 0; i < length; i++, j += 4)
        {
            uint randomIndex = (uint)(bytes[j] << 24 | bytes[j + 1] << 16 | bytes[j + 2] << 8 | bytes[j + 3]);
            result[i] = CharSet[randomIndex % CharSetSize];
        }
        return new string(result);
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static uint GetRandomUInt32(Span<byte> bytes, ref int index)
    {
        return (uint)(bytes[index] << 24 | bytes[index + 1] << 16 | bytes[index + 2] << 8 | bytes[index + 3]);
    }
}
class Program
{
    static void Main()
    {
        string password = PasswordGenerator.GenStr(32);
        Console.WriteLine(password);
    }
}
zazakgfh 发表于 2024-7-7 12:06
这个中文变量名给我整笑了
现在这个都不手动撸代码了
直接调用别人的一个库,一个叫随机密码的库
shuisanyue 发表于 2024-7-7 13:13
没有测试,看看时间开销多少?

[C#] 纯文本查看 复制代码
using System;
using System.Text;

public class RandUtil
{
    private static readonly Random rnd = new Random();

    public static string GrtRndNumStr(int count)
    {
        StringBuilder sb = new StringBuilder((count * 11) / 2);
        byte[] buffer = new byte[4 * count];
        rnd.NextBytes(buffer);

        for (int i = 0; i < buffer.Length; i += 4)
        {
            uint num = BitConverter.ToUInt32(buffer, i);
            num %= 10000000000;
            sb.Append(num.ToString());
            if ((i / 4 + 1) % 2 == 0 && i < buffer.Length - 4) sb.Append(',');
        }

        return sb.ToString();
    }

    public static string GrtRndCharStr(int count, int typ)
    {
        StringBuilder sb = new StringBuilder(count);
        byte[] buffer = new byte[count];
        rnd.NextBytes(buffer);

        foreach (byte b in buffer)
        {
            char ch = (char)(typ == 1 ? b + 'A' : b + 'a');
            if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') sb.Append(ch);
        }

        return sb.ToString();
    }
}
 楼主| 夜雨闻笛 发表于 2024-7-7 16:16
zazakgfh 发表于 2024-7-7 12:06
这个中文变量名给我整笑了
现在这个都不手动撸代码了
直接调用别人的一个库,一个叫随机密码的库

哈哈,大佬别嫌辣眼睛,不会英语,要是用英文单词变量名方法名,那就连自己写的代码自己都看不懂了。
 楼主| 夜雨闻笛 发表于 2024-7-7 17:11
shuisanyue 发表于 2024-7-7 13:13
没有测试,看看时间开销多少?

[mw_shl_code=csharp,true]using System;

大佬,你的代码我测试了一下,效率比我的高多了。无论哪一种的十万次都能跑30毫秒左右。
但是有一个问题是字符串随机生成位数不正确。
在GrtRndCharStr的foreach里面,有一句if是只有char满足范围时才会被StringBuilder 添加,而不满足则跳过了。这会使得返回结果和指定长度不符合。
我想用while解决(不知道合不合适),而且关键代码也不会写:
public static string 取指定长度大写字母字符串(int count)
{
    StringBuilder sb = new(count);
    byte[] buffer = new byte[count];
    rnd.NextBytes(buffer);

    for (int i = 0; i < buffer.Length; i++)
    {
        char ch = (char)(buffer + 'A');
        while (ch < 'A' || ch > 'Z')
        {
            //如果ch不在大写字母范围,就重新生成ch
            //如何重新随机这个值不会写,未完成
        }
        sb.Append(ch);
    }

    return sb.ToString();
}
flyer_2001 发表于 2024-7-7 19:10
夜雨闻笛 发表于 2024-7-7 17:11
大佬,你的代码我测试了一下,效率比我的高多了。无论哪一种的十万次都能跑30毫秒左右。
但是有一个问题 ...

把大写字母加入到一个列表或数组中,随机生成序号,不需要的字母不要加
 楼主| 夜雨闻笛 发表于 2024-7-7 20:13
zazakgfh 发表于 2024-7-7 12:06
这个中文变量名给我整笑了
现在这个都不手动撸代码了
直接调用别人的一个库,一个叫随机密码的库

之前都没注意到最后一句话,原来有现成的库吗?
大佬,我在项目程序包和百度都搜了一下随机密码库 ,不知道具体是哪个库,能告诉我一下这个库的全名吗?
shuisanyue 发表于 2024-7-7 22:26
RNGCryptoServiceProvider看看这个,没有测试,参考一下:

[C#] 纯文本查看 复制代码
using System;
using System.Security.Cryptography;
public class PassGen
{
    private const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private const string Lower = Upper.ToLower();
    private const string Nums = "0123456789";
    private const string Specs = "!@#$%^&*()-_=+[]{}|;:,.<>?";
    public static string GenPass(int len)
    {
        var charSet = Upper + Lower + Nums + Specs;
        var passChars = new char[len];
        var rng = new RNGCryptoServiceProvider();
        byte[] buf = new byte[4];
        for (int i = 0; i < passChars.Length; i++)
        {
            rng.GetBytes(buf);
            uint rand = BitConverter.ToUInt32(buf, 0);
            passChars[i] = charSet[rand % charSet.Length];
        }
        return new string(passChars);
    }
}

class Prog
{
    static void Main()
    {
        string pass = PassGen.GenPass(30);
        Console.WriteLine(pass);
    }
}
shuisanyue 发表于 2024-7-7 22:30
本帖最后由 shuisanyue 于 2024-7-7 22:31 编辑

上面不能改了……
RNGCryptoServiceProvider看看这个,没有测试,供您参考一下(2):


[C#] 纯文本查看 复制代码
using System;
using System.Security.Cryptography;
using System.Text;
public class PassGen
{
    private static readonly RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    private const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private const string Lower = Upper.ToLower();
    private const string Nums = "0123456789";
    private const string Specs = "!@#$%^&*()-_=+[]{}|;:,.<>?";
    private static readonly string CharSet = new StringBuilder(Upper)
        .Append(Lower)
        .Append(Nums)
        .Append(Specs)
        .ToString();
    public static string GenPass(int len)
    {
        char[] passChars = new char[len];
        byte[] buf = new byte[4];
        for (int i = 0; i < len; i += 4)
        {
            rng.GetBytes(buf);
            uint rand = BitConverter.ToUInt32(buf, 0);
            for (int j = i; j < Math.Min(i + 4, len); j++)
            {
                passChars[j] = CharSet[rand % CharSet.Length];
                rand /= CharSet.Length; 
            }
        }
        return new string(passChars);
    }
}

class Prog
{
    static void Main()
    {
        string pass = PassGen.GenPass(30);
        Console.WriteLine(pass);
    }
}
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-12 19:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表