【问题标题】:c# generate random string based on patternc#根据模式生成随机字符串
【发布时间】:2013-01-02 00:27:46
【问题描述】:

我正在尝试基于模式进行简单的字符串生成。
我的想法是使用正则表达式进行简单的替换。 我从简单的方法开始:

private static string parseTemplate(string template)
{
    return Regex.Replace(template, @"(\[d)((:)?([\d]+)?)\]", RandomDigit());
}

private static string RandomDigit()
{
    Random r = new Random();
    return r.Next(0, 9).ToString();
}

现在这样做是将[d][d:3] 等组替换为应该是随机数字的组。
不幸的是,每个组都被替换为相同的数字,例如,如果我输入 test [d][d][d:3],我的方法将返回 test 222
我想在每个地方得到不同的数字,比如test 361

我遇到的第二个问题是处理长度的方法:

现在我必须为我想要的每个数字指定[d],但指定[d:3] 并获得相同的输出会更容易。

我知道有一个名为Fare 的项目,但我想在没有这个库的情况下这样做

目前我只搜索[d],但是这种方法是否可以正常工作,添加其他组不会有问题,例如:[s] 用于特殊字符或任何其他类型的模式。

编辑1

正如建议的那样,我将 Random 更改为静态变量,如下所示:

private static string parseTemplate(string template)
    {
        return Regex.Replace(template, @"(\[d)((:)?([\d]+)?)\]", RandomDigit());
    }

    private static Random r = new Random();

    private static string RandomDigit()
    {
        return r.Next(0, 9).ToString();
    }

问题是当我这样调用我的代码时:

Console.WriteLine(parseTemplate("test [d:2][d:][d]"));
Console.WriteLine(parseTemplate("test [d:2][d:][d]")); 

我得到这样的输出

test 222
test 555

我想要这样的输出(例如):

test 265
test 962

我认为问题出在Regex.Replace 上,它只调用了我的RandomDigit 一次。

【问题讨论】:

  • 这是您使用 Random 类的问题,您需要使用不同的种子对其进行初始化,或者在调用之间等待一段时间以确保它返回不同的值。
  • 查看answer
  • 让你的随机静态:stackoverflow.com/questions/4855756/…
  • 静态随机在这里不是问题:) 我在我的问题中添加了一些代码。 Regex.Replace 似乎只调用了一次我的随机方法。

标签: c# regex


【解决方案1】:

对于您的第一个问题:当您调用 new Random() 时,每次调用该函数时都会使用相同的值进行播种 - 初始化一个静态 Random 成员变量,然后返回 r.Next(0,9).ToString();

编辑:

在回答您的评论时,请尝试将 MatchEvaluator 与委托一起使用,如下所示(未经测试):

static string RandomReplacer(Match m)
{
    var result = new StringBuilder();
    foreach (char c in m.ToString())
        result.Append(c == 'd' ? RandomDigit() : c);
    return result.ToString()
}

private static string parseTemplate(string template)
{
    return Regex.Replace(template, @"(\[d)((:)?([\d]+)?)\]", new MatchEvaluator(RandomReplacer));
}

然后您可以扩展此方法以匹配 [d:3] 并在您的 MatchEvaluator 中相应地解析它,从而解决您的第二个问题。

【讨论】:

  • 静态随机不是我的问题。看起来Regex.Replace 只调用了我的随机函数一次。
  • 更新答案(Regex.Replace(String, String, MatchEvaluator) 重载上的msdn article 是使用 Random() 的一个很好的例子)
  • 谢谢 :) 使用 lambda 更简单:return Regex.Replace(template, @"(\[d)((:)?([\d]+)?)\]", m => RandomDigit());
【解决方案2】:

假设[d:3]表示“三个随机数字”,以下MatchEvaluator使用长度(从第4组读取)生成随机数字字符串:

static string ReplaceSingleMatch(Match m)
{
    int length;
    if (!int.TryParse(m.Groups[1].Value, out length))
        length = 1;
    char[] chars = new char[length];
    for (int i = 0; i < chars.Length; i++)
        chars[i] = RandomDigit()[0];
    return new string(chars);
}

你可以这样称呼它:

private static string parseTemplate(string template)
{
    return Regex.Replace(template, @"\[d(?::(\d+))?\]", ReplaceSingleMatch);
}

您可能想要更改 RandomDigit 以返回单个 char 而不是字符串,或者采用 int 并返回多个字符。

【讨论】:

  • 您可能需要将委托调用包装在 new MatchEvaluator()
  • @AlexG 我不需要,但也许你在早期版本的 .NET 中需要。
  • @Rawling - 谢谢你 :) 很棒的工作。还有一个问题-我应该如何更改该正则表达式,使其仅对[d][d:3](冒号后的任何数字)有效,但不适用于[d:]-冒号后没有数字。
  • @Misiu 我不知道如何修改你的模式来做到这一点,但如果你使用@"\[d(?::(\d+))?\]"并从1组而不是@组读取长度987654334@,应该可以。
  • @Rawling 再次感谢您的帮助,也许对你来说这不是什么特别的东西,但对我来说这是一段很棒的代码:)
【解决方案3】:
private static string GenerateMask(string mask)
{
    StringBuilder output = new StringBuilder();
    for (int i = 0; i < mask.Length; i++)
    {
        if (mask[i] == 'd' && mask[i - 1] != '\\')
        {
            int quantifier = 1;

            if (mask[i + 1] == ':')
                Int32.TryParse(mask[i + 2].ToString(), out quantifier);

            output.Append(GetRandomDigit(quantifier));
            i += 2;
        }
        else
        {
            if(mask[i] != '\\')
            output.Append(mask[i]);
        }
    }

    return output.ToString();
}

private static string GetRandomDigit(int length)
{
    Random random = new Random();
    StringBuilder output = new StringBuilder();
    while (output.Length != length)
        output.Append(random.Next(0, 9));
    return output.ToString();
}

有一个自定义算法我只是为了好玩而放在一起,这是实现:

Console.WriteLine(GenerateMask(@"Hey Da\d, meet my new girlfrien\d she's d:2"));
//Output: Hey Dad, meet my new girlfriend she's 44

【讨论】:

  • 我会检查一下 :) 似乎有一个选项可以在没有正则表达式的情况下执行此操作。你能举一些例子吗?你把什么当作面具?你认为什么会更好?
  • 我更新了原帖。虽然很有趣,但如果其他人的方法对你有用,那么我会自己使用他们的。
  • 他们似乎工作得更好,但你更容易扩展 - 添加其他模式,如 c 用于随机字符或 s 用于特殊等等 :)
  • 当您的字符串以小写“d”开头时,请注意 ArgumentOutOfRangeError
猜你喜欢
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-01
  • 2011-06-30
  • 2010-09-26
相关资源
最近更新 更多