如何生成随机逻辑单词?

时间:2014-09-22 04:03:30

标签: php mysql

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

我有一个充满英语单词(A - Z)的MySQL数据库,我希望生成逻辑单词以供每个单词使用。

例如:在我所拥有的单词列表中,数字26是'放弃',我想为这个单词生成一个单词,可能使用正则表达式或其他东西,所以我可以使用它来回翻译整页单词。

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

但是我想要一些逻辑,所以可能有一些元音和辅音使这个词看起来“真实”。

希望我能正确解释自己。

感谢。

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

5 个答案:

答案 0 :(得分:14)

方法&数据

如果一个单词按照您习惯看到它们的顺序组成,那么什么可以让一个单词看起来有点合乎逻辑。一种方法是使用加权列表trigrams - 3个字符的序列。

基本上你接受任何两个字母,比如“so”,并添加另一个通常在它之后的字母,如“l”。然后取最后两个字母“ol”,找到之后发生的事情。冲洗/重复,直到你得到任何你想要的长度 - “solverom”

Peter Norvig's n-gram data采购(其本身是从Google books 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 extension来处理它们。足够简单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并将其从给定$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";
}

我们正在做的是获得一个随机长度,随机的双字母组合来开始单词,然后填充它。 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 :(得分:1)

我使用了很多建议的想法取得了很大的进步,并且提出了一个相当有趣的系统来生成他们的英语等同词。我已经创建了一个函数,它在最后用一个随机的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

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

除了我上面给出的评论,如果你特别想要废话,但仍然看似合理,可能最简单的方法就是这样:

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

例如,如果你结合了'#34; experimENTation&#34;和&#34; mENThol&#34;,你会得到&#34;实验&#34;。您应该在使用之前检查字典(如果它们必须是无意义的话),或者您可能会意外地创建一个真实的单词 - 例如结合&#34; mENThol&#34;和&#34;体验&#34;,你会得到&#34; mENTation&#34; - 这是一个真实的词。

答案 4 :(得分:0)

一个选项是拥有一个有效音节的列表,然后简单地将它们随机组合,或者键入你正在使用的真实单词作为假单词的基础(通过某种真实音节映射到假音节)。如果提出一个有效音节列表是太多的工作,或产生不好的结果,你可以进入一个新的水平:phonotactics。您必须开发一种能够以不违反英语规则的方式连接声音的系统。例如,用&#34; bl&#34;开始一个单词是可以的。接着是元音,但不是&#34; bn&#34;接着是一个元音(所以你可以拥有&#34;黑色&#34;但不是*&#34; bnack&#34;)。这些规则可能不能全部表示为&#34;字母x可以/不能跟字母y&#34;,但大多数可以,也许这足以产生随机假,但看似合理的声音词语的