我想知道如何在PHP中生成随机逻辑单词列表.
我有一个充满英语单词(A - Z)的MySQL数据库,我想生成逻辑单词.
例如:在我有的单词列表中,数字26是'放弃',我想为这个单词生成一个单词,可能使用正则表达式或其他东西,所以我可以使用它来回翻译整页单词.
使用直接随机单词的问题是它们看起来不够真实,所以'放弃'可能变成(纯粹随机生成)'qdbskp'或类似的东西.这个词的问题根本看起来不真实,它看起来就像有人把他们的脸撞到了键盘上.
但是我想要一些逻辑,所以可能有一些元音和辅音使这个词看起来"真实".
希望我正确地解释自己.
谢谢.
TLDR:我正在尝试创建一个随机生成的单词字典,其中包含指向英语单词列表的链接,这些单词列表具有一些逻辑,因此单词看起来很真实.
use*_*918 14
什么可以使一个词看起来有点合乎逻辑的是,它是由你习惯看到它们的顺序中的字符组成的.一种方法是使用三元组的加权列表- 三个字符的序列.
基本上你接受任何两个字母,如"so",并添加另一个通常在它之后,如"l".然后取最后两个字母"ol",找到之后发生的事情.冲洗/重复,直到你得到任何你想要的长度 - "solverom".
从Peter Norvig的n-gram数据中获取(这本身就是从Google books ngram中编译而来),我在github上整理了一些json文件.我在这里直接包含数据,但是特别是trigrams.json在~128KB时有点大.
数据实际上可以从任何字典或其他笨重的单词列表中编译,并且结构如下......
[0,26,622,4615,6977,10541,13341,14392,13284,11079,8468,5769,3700,2272,1202,668,283,158,64,40,16,1,5,2]
Run Code Online (Sandbox Code Playgroud)
这一个是完整的.它是不同单词长度的(0索引)分布.每个索引都是单词长度,每个值都找到了该长度的单词数.因此,例如,有4615个不同的单词,长度为3个字符.
我们将使用它来决定我们的新词应该有多长.基本上我们将所有值相加,在1和总数之间选择一个随机数,然后找到它所放置的集合中的位置.该元素的关键是这个词的长度.
{
"TH": "82191954206",
"HE": "9112438473",
"IN": "27799770674",
"ER": "324230831",
...
Run Code Online (Sandbox Code Playgroud)
这个人将双字母组合,两个字符组合,以及在单词开头发现它们的频率.是的,一切都是大写字母.
我们将使用它来决定从什么开始.
{
"TH": {
"E": "69221160871",
"A": "9447439870",
"I": "6357454845",
"O": "3369505315",
"R": "1673179164",
...
},
"AN": {
"D": "26468697834",
"T": "3755591976",
"C": "3061152975",
...
Run Code Online (Sandbox Code Playgroud)
这个更有趣.此数据集中的每个键都是一个带有字符数组的二元组,以及该字符出现后的频率.
"D"出现在"AN"之后很多.
这就是我们用来构建其余部分的内容.
首先,我们需要一些实用功能.
function gmp_rand($min, $max) {
$max -= $min;
$bit_length = strlen(gmp_strval($max, 2));
do {
$rand = gmp_init(0);
for ($i = $bit_length - 1; $i >= 0; $i--) {
gmp_setbit($rand, $i, rand(0, 1));
if ($rand > $max) break;
}
} while ($rand > $max);
return $rand + $min;
}
Run Code Online (Sandbox Code Playgroud)
因为我们需要生成的一些数字可能比PHP_INT_MAX我们使用PHP GMP扩展来处理它们更大.简单的rand()工作就像.
function array_weighted_rand ($list) {
$total_weight = gmp_init(0);
foreach ($list as $weight) {
$total_weight += $weight;
}
$rand = gmp_rand(1, $total_weight);
foreach ($list as $key => $weight) {
$rand -= $weight;
if ($rand <= 0) return $key;
}
}
Run Code Online (Sandbox Code Playgroud)
这很像内置array_rand(),因为你传递一个数组,它将返回一个随机密钥.只有这一个因素在选择时会影响重量.
所以如果你传入一个看起来像这样的数组:
array (
'foo' => 2,
'bar' => 4,
'baz' => 12
)
Run Code Online (Sandbox Code Playgroud)
它会回来bar的两倍经常它会返回foo,并baz尽可能多三倍左右bar.
function fill_word ($word, $length, $trigrams) {
while (strlen($word) < $length) {
$word .= array_weighted_rand($trigrams[substr($word, -2)]);
}
return $word;
}
Run Code Online (Sandbox Code Playgroud)
这需要一个字符串$word并$length从给定的集合中填充它$trigrams.它根据字符串中的最后两个字符从数据集中选取的每次迭代.
$lengths = json_decode(file_get_contents('distinct_word_lengths.json'), true);
$bigrams = json_decode(file_get_contents('word_start_bigrams.json'), true);
$trigrams = json_decode(file_get_contents('trigrams.json'), true);
for ($i = 0; $i < 10; $i++) {
do {
$length = array_weighted_rand($lengths);
$start = array_weighted_rand($bigrams);
$word = fill_word($start, $length, $trigrams);
} while (!preg_match('/[AEIOUY]/', $word));
$word = strtolower($word);
echo "$word\n";
}
Run Code Online (Sandbox Code Playgroud)
我们正在做的是获得一个随机长度,随机的双字母组合来开始单词,然后填充它.该preg_match()只是为了验证该字包含一个元音,这是不以其他方式保证.如果没有,请再试一次.
您可以将此替换为您可能想要执行的任何类型的验证,例如确保它与数据库中的真实单词或其他任何内容不匹配.
是的,你可能会产生一个真实的词.如果你想说你做了它就发音不同.
经过几次运行让我感到满意:
ancover ingennized plesuri asymbablew
orkno oftedi nestrat arlysect
welvency thembe therespaid frokedgerition
judeth ist rectede privede
aprommautu offeleal townerislo callynerly
thentsi perma themenum agesputherflone
pecticangenti whoult ifileyea onster
flatco powne prative betion
inegansith meraddin theste mysistai
skerest uppre ongdonc hadmints
Run Code Online (Sandbox Code Playgroud)
所有这些都是我的拼写检查者讨厌的.
可以从github获取完整的数据和代码.
| 归档时间: |
|
| 查看次数: |
3088 次 |
| 最近记录: |