程序虽然能够工作,但99%的输出都是垃圾,因为它没有遵守英语语言的结构规则,我得到了和e一样多的x和z单词。
我有什么选项来偏置RNG,使其更经常使用常用字母。
我正在使用从STL中种植的rand()和时间。
你可以对某段文本进行n-gram分析,并将其用作偏差的基础。你可以按字母或音节来进行分析。按音节进行分析可能更加复杂。
按字母进行分析很容易。你可以遍历源文本中的每个字符,并跟踪你遇到的最后n-1个字符。然后,对于每个下一个字符,你将上次遇到的n-1个字符和这个新字符(一个n-gram)添加到频率表中。
这个频率表是什么样子的?你可以使用映射将n-grams映射到它们的频率。但是,这种方法对我下面建议的算法来说并不是很好。为此,最好将每个(n-1)-gram映射到一个映射,该映射将n-gram的最后一个字母映射到其频率。类似于:std::map<std::string, std::map<char,int>>
。
进行分析并收集统计数据后,算法将如下所示:
选取一个随机的起始n-gram。您之前的分析可能包含有权数据,其中字母通常用于开始单词; 从以前的n-1个字母开头的所有n-gram中选择一个随机的最后一个字母(考虑分析中的权重); 重复以上步骤,直到达到单词的结尾(可以使用预定义的长度或来自单词结束频率的数据)。如果你想要更真实的输出,可以使用英语字母频率:http://en.wikipedia.org/wiki/Letter_frequency。
但是如果你想要可发音的单词,最好从音节中生成它们。你可以在网上找到更多信息,例如这里:http://spell.psychology.wustl.edu/SyllStructDistPhon/CVC.html
如果你想创建可发音的单词,不要试图将字母拼在一起。
拼接音素。制作一个音素列表以供选择:"abe"、"ape"、"gre"等。
qu
对),请获取英语语言字母频率列表。e
(7分之1的机会)而不是x
(大约1000分之1的机会)。letter | weight | start | end
a | 8.17% | 0 | 8167
b | 1.49% | 8168 | 9659
c | 2.78% | 9660 | 12441
d | 4.25% | 12442 | 16694
e | 12.70% | 16695 | 29396
f | 2.23% | 29397 | 31624
g | 2.02% | 31625 | 33639
.....
z | 0.07% | 99926 | 99999
3. 生成一个0到99999之间的随机数,并使用它来找到相应的字母。这样,您将拥有正确的字母频率。
struct WeightedLetter
{
char letter;
int weight;
};
static WeightedLetter const letters[] =
{
{ 'a', 82 },
{ 'b', 15 },
{ 'c', 28 },
// ...
};
char getLetter()
{
int totalWeight = 0;
for ( WeightedLetter const* iter = begin( letters );
iter != end( letters );
++ iter ) {
totalWeight += iter->weight;
}
int choice = rand() % totalWeight;
// but you probably want a better generator
WeightedLetter const* result = begin( letters );
while ( choice > result->weight ) {
choice -= result->weight;
++ result;
}
return result->letter;
}
这只是我脑海中的想法,所以很可能会包含错误;至少第二个循环需要一些验证。但它应该能给你基本的想法。
当然,这仍然不会产生类似英语的单词。序列“uq”和“qu”一样可能出现,没有任何阻止没有元音的单词或只有元音的十个字母的单词。维基百科关于英语音系学有一些关于哪些组合可以在哪里发生的好信息,但它没有任何统计数据。另一方面,如果你正在尝试编造可能的单词,比如贾伯沃克,那么这可能不是一个问题:选择一个随机数量的音节,从1到某个最大值,然后是开端、核心和闭韵。(别忘了开端和闭韵可以为空。)