如何生成一个随机的逻辑单词


How can I generate a random logical word?

我想知道如何在PHP中生成随机逻辑单词列表。

我有一个MySQL数据库,里面装满了英语单词(a-Z),我想生成每个单词的逻辑单词。

例如:在我的单词列表中,数字26是"放弃",我想用regex或其他东西为这个单词生成一个单词,这样我就可以用它来回翻译一整页的单词。

使用直接随机单词的问题是它们看起来不够真实,所以"放弃"可能会变成(纯粹随机生成的)"qdbskp"或类似的东西。问题是这个词看起来一点都不真实,看起来就像有人把脸撞到了键盘上。

然而,我希望它有一些逻辑性,所以也许可以用一些元音和辅音来使这个词看起来"真实"。

希望我能正确地解释自己。

谢谢。

TLDR:我正在尝试创建一个随机生成的单词词典,其中包含指向英语单词列表的链接,这些单词列表具有一定的逻辑性,因此单词看起来是真实的。

方法;数据

让一个词看起来有点合乎逻辑的是,如果它是按照你习惯的顺序由字符组成的。一种方法是使用一个三元图的加权列表,即3个字符的序列。

基本上,你可以取任意两个字母,比如"so",然后再加上一个通常在它后面的字母,就像"l"。然后取最后两个字母"ol",然后找出后面的内容。冲洗/重复,直到你得到一个你想要的长度的单词——"solverrom"

来源于Peter Norvig的n-gram数据(它本身是从谷歌图书ngrams编译的),我在github上整理了一些json文件。我会直接在这里包含数据,但trigrams.json尤其有点大,大约为128KB。

数据实际上可以从任何字典或其他庞大的单词列表中编译,并且结构类似…


distinct_word_lengths.json

[0,26,622,4615,6977,10541,13341,14392,13284,11079,8468,5769,3700,2272,1202,668,283,158,64,40,16,1,5,2]

这个是完整的。它是不同单词长度的(0索引)分布。每个索引都是单词的长度,每个值都是找到该长度的单词数。例如,有4615个不同的单词,长度为3个字符。

我们会用这个来决定我们的新词应该有多长。基本上,我们把所有的值加起来,选择一个介于1和总数之间的随机数,然后找到它在集合中的位置。这个元素的关键是单词的长度


word_start_bigrams.json

{
    "TH": "82191954206",
    "HE": "9112438473",
    "IN": "27799770674",
    "ER": "324230831",
    ...

这一个结合了双字,两个字符的组合,以及它们出现在单词开头的频率。是的,所有的东西都是大写的。

我们将用这个来决定单词的开头。


trigrams.json

{
    "TH": {
        "E": "69221160871",
        "A": "9447439870",
        "I": "6357454845",
        "O": "3369505315",
        "R": "1673179164",
        ...
    },
    "AN": {
        "D": "26468697834",
        "T": "3755591976",
        "C": "3061152975",
        ...

这个更有趣一点。这个数据集中的每个键都是一个二元图,其中包含一个字符数组以及该字符出现在其后的频率

"D"经常出现在"AN"之后。

这就是我们将用来构建单词其余部分的内容。


功能

首先,我们需要一些实用函数。

gmp_rand()

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;
}

因为我们需要生成的一些数字可能大于PHP_INT_MAX,所以我们将使用PHP GMP扩展来处理它们。足够简单的rand()工作方式。


array_weighted_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;
    }
}

这很像内置的array_rand(),因为您向它传递一个数组,它将返回一个随机密钥。只有这一项在挑选时会考虑重量。

因此,如果你传入一个数组,它看起来像:

array (
  'foo' => 2,
  'bar' => 4,
  'baz' => 12
)

它返回bar的频率是返回foo的两倍,返回baz的频率是bar的三倍。


fill_word()

function fill_word ($word, $length, $trigrams) {
    while (strlen($word) < $length) {
        $word .= array_weighted_rand($trigrams[substr($word, -2)]);
    }
    return $word;
}

这取一个字符串$word,并将其从给定的$trigrams的集合填充到$length。它根据字符串中的最后两个字符从数据集中挑选每个迭代。


用法

$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";
}

我们正在做的是得到一个随机的长度,随机的双字开头,然后填充它。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

所有这些我的拼写检查器都讨厌。


可以从github获取完整的数据和代码。

我使用了许多建议的想法,取得了很大的进步,并提出了一个相当有趣的系统来生成与英语等价的单词。我做了一个函数,它生成的单词有随机的1-3个辅音,结尾有一个元音。

function generateRandomWord($length = false) {
  $vowels = "aeiou";
  $consonants = "bcdfghjklmnpqrstvwxyz";
  $string = "";
  if ($length == false) {
    $length = rand(1, 3);
  }
  for ($i = 0; $i < $length; $i++) {
    $ratio = rand(0, 3);

    for ($a = 0; $a < $ratio; $a++) {
      $string .= $consonants[rand(0, strlen($consonants) - 1)];
    }
    $string .= $vowels[rand(0, strlen($vowels) - 1)];
  }
  if (strlen($string) > $length) {
    $string = substr($string, 0, $length);
  }
  return $string;
}

它还修剪了字符串的末尾,这样单词就不会太长。

按下刷新几次,我得到了这个:

aa ri
aah oeb
aal gyi
aalii cpwaa
aardvark qdiaieug
aardvarks jupuhuafs
aardwolf yaniruqk
aardwolves qtxikicoes
aargh yauka
aarrghh byifqsa

我发现这很有趣,我可以用这些生成的单词的英文翻译来填充数据库。

这可能会成为一种非常酷的秘密语言,可以来回翻译。

function random_word( $length = 6 ) {
    $cons = array( 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v', 'w', 'x', 'z', 'pt', 'gl', 'gr', 'ch', 'ph', 'ps', 'sh', 'st', 'th', 'wh' );
    $cons_cant_start = array( 'ck', 'cm', 'dr', 'ds','ft', 'gh', 'gn', 'kr', 'ks', 'ls', 'lt', 'lr', 'mp', 'mt', 'ms', 'ng', 'ns','rd', 'rg', 'rs', 'rt', 'ss', 'ts', 'tch');
    $vows = array( 'a', 'e', 'i', 'o', 'u', 'y','ee', 'oa', 'oo');
    $current = ( mt_rand( 0, 1 ) == '0' ? 'cons' : 'vows' );
    $word = '';
    while( strlen( $word ) < $length ) {
        if( strlen( $word ) == 2 ) $cons = array_merge( $cons, $cons_cant_start );
        $rnd = ${$current}[ mt_rand( 0, count( ${$current} ) -1 ) ];
        if( strlen( $word . $rnd ) <= $length ) {
            $word .= $rnd;
            $current = ( $current == 'cons' ? 'vows' : 'cons' );
        }
    }
    return $word;
}

简单而且效果很好,归功于http://ozh.in/vh

除了我上面给出的评论之外,如果你特别想要无意义的单词,但仍然是可信的,那么最简单的方法可能是:

找到两个单词,它们有一个共同的字母数(这个数字可能需要实验)(不是在开头或结尾),并将它们组合在一起——一个的开头和另一个的结尾。

例如,如果你把"experimENTation"answers"mENThol"组合起来,你就会得到"experimENThol"。在使用它们之前,你应该先查一下字典(如果它们一定是胡说八道的话),否则你可能会意外地生成一个真实的单词——例如,将"mENThol"answers"experimENTation"组合在一起,你会得到"mENTation"——这是一个真实单词。

一种选择是有一个有效音节的列表,然后简单地随机组合这些音节,或者去掉你用来作为假单词基础的真单词(通过将真音节映射到假单词)。如果列出一个有效音节的列表工作量太大,或者结果不好,你可以进入下一个层次:表音策略。你必须开发一个系统,以一种不违反英语规则的方式连接声音。例如,一个单词的开头可以是"bl",然后是元音,但不能是"bn",后面是元音(所以你可以用"black",但不能用*"bnack")。这些规则可能不能全部表示为"字母x可以/不能后跟字母y",但大多数规则都可以,也许这足以生成随机的假单词,但听起来似乎很合理。