如何在.Net中生成随机的英语“发声”单词?

时间:2010-07-30 13:23:36

标签: .net string passwords generator

我知道有几篇关于基于大词典或网页查找的随机单词生成的帖子。但是,我正在寻找一个单词生成器,我可以使用它来创建没有符号的强密码。我正在寻找的是一种可靠的机制来生成给定长度的随机,无法识别的英语单词。

单词类型的一个例子是“ratanta”等。

是否有任何算法可以理解兼容的音节,从而生成可发音的输出字符串?我知道某些验证码样式控件会生成这些类型的单词,但我不确定它们是使用算法还是来自大型集合。

如果有这种功能的任何.Net实现,我将非常有兴趣知道。

3 个答案:

答案 0 :(得分:3)

我会使用Markov chain算法。

总结:

  1. 建立字典。通过示例英文文本中的字母进行迭代。构建映射字母对的数据结构。针对每一对,记录第二个字母紧接第一个字母后出现的概率。
  2. 生成您的文字。使用您在(1)中构建的地图,选择一系列随机字母。在决定下一封要写的字母时,请查看您最近写的字母,并使用该字母确定下一封信的概率。

答案 1 :(得分:2)

你可以做几件事:

1)研究英语音节结构,并按照这些规则生成音节

2)采用马尔可夫链来获得英语音韵学的统计模型。

马尔可夫链上有很多资源,但主要思想是记录某个序列后出现任何特定字母的概率。例如,在“q”之后,“u”非常可能;在“k”之后,“q”非常不可能(这采用1长马尔可夫链);或者,在“th”之后,“e”很可能(这采用2长马尔可夫链)。

如果你去音节模型路线,你可以使用像this这样的资源来帮助你阐明你对你语言的直觉。

<强>更新

3)你可以通过不模拟完整的英语来简化它,但是,比如日语或意大利语,规则更容易,如果它是一个无意义的单词,它就像一个无意义的英语单词一样容易记住。例如,日语只有大约94个有效音节(47短,47长),你可以轻松列出所有这些音节并随机选择。

答案 2 :(得分:0)

一些答案​​建议使用马尔可夫链,但不要告诉您如何构建。这是一个实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace PseudoWord
{
    public sealed class PseudoWordGenerator : IDisposable
    {
        private readonly RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
        private readonly HashSet<string> enders = new HashSet<string>();
        private readonly IList<string> starters = new List<string>();

        private readonly Dictionary<char, IList<string>> gramDict =
            Enumerable
                .Range('a', 'z')
                .ToDictionary(a => (char) a, _ => (IList<string>) new List<string>());

        private readonly byte[] randomBytes = new byte[4];

        public PseudoWordGenerator(IEnumerable<string> words, int gramLen)
        {
            foreach (var word in words.Select(w => w.Trim().ToLower()).Where(w => w.Length > gramLen)
                .Where(w => Regex.IsMatch(w, "^[a-z]+$")))
            {
                this.starters.Add(word.Substring(0, gramLen));
                this.enders.Add(word.Substring(word.Length - gramLen, gramLen));
                for (var i = 0; i < word.Length - gramLen; i++)
                {
                    var currentLetter = word[i];
                    if (!this.gramDict.TryGetValue(currentLetter, out var grams))
                    {
                        i = word.Length;
                        continue;
                    }

                    grams.Add(word.Substring(i + 1, gramLen));
                }
            }
        }

        public string BuildPseudoWord(int length)
        {
            var result = new StringBuilder(this.GetRandomStarter());
            var lastGram = string.Empty;
            while (result.Length < length || !this.enders.Contains(lastGram))
            {
                lastGram = this.GetRandomGram(result[result.Length - 1]);
                result.Append(lastGram);
            }

            return result.ToString();
        }

        private string GetRandomStarter() => this.GetRandomElement(this.starters);

        private string GetRandomGram(char preceding) =>
            this.GetRandomElement(this.gramDict[preceding]);

        private T GetRandomElement<T>(IList<T> collection) =>
            collection[this.GetRandomUnsigned(collection.Count - 1)];

        public void Dispose()
        {
            for (var i = 0; i < this.randomBytes.Length; i++)
            {
                this.randomBytes[i] = 0;
            }

            this.rng?.Dispose();
        }

        private int GetRandomUnsigned(int max)
        {
            this.rng.GetBytes(this.randomBytes);
            return Math.Abs(BitConverter.ToInt32(this.randomBytes, 0)) % (max + 1);
        }
    }
}

以gramLen = 3并以"linuxwords" Linux dictionary作为输入,这是至少12个字符的示例输出

larisommento
damentivesto
honsgranspireas
incenctorsed
opemelersult
spenedriarblast
devokepocian
newmenaryrofile
perocererich
trerwhusinis

通过简单地将重复存储在数组中以处理概率,简化了此实现。此外,我们专门处理单词的开头和结尾以生成更合理的单词。