我正在构建一个脚本来随机生成听起来像英语的单词。我已将大量英文单词分解为VCV groups。
...其中V代表一个单词中所有相邻的元音,C代表所有相邻的辅音。例如,英文单词“缩样”将成为 “-mi”,“inia”,“iatu”和“ure”。 “学校”将成为“-schoo”和“ool”。 这些小组将与其他小组一起组成 规则是完整的相邻结尾元音必须匹配 附件组的一整套起始元音。
我在以下结构中构造了一个哈希:
pieces = {
:starters => { "-sma" => 243, "-roa" => 77, "-si" => 984, ...},
:middles => { "iatu" => 109, "inia" => 863, "aci" => 229, ...},
:enders => { "ar-" => 19, "ouid-" => 6, "ude" => 443, ...}
}
为了构造生成的单词,“起始”字符串需要以与“中间”字符串相同的元音分组结束。将“中间”字符串与“ender”字符串连接时也是如此。使用上述示例的一个可能结果是“ - sma”+“aba”+“ar - ”以提供“smabar”。另一个是“ - si”+“inia”+“iatu”+“ude”来提供“siniatude”。
我的问题是,当我采样任何两件时,我不知道如何确保第一件的结束V组与第二件的开始V组完全匹配。例如,“utua”+“uailo”不会一起使用,因为“ua”与“uai”不同。但是,成功的一对将是“utua”+“uado”,因为“ua”=“ua”。
答案 0 :(得分:2)
def match(first, second)
end_of_first = first[/[aeiou]+$|[^aeiou]+$/]
start_of_second = second[/^[aeiou]+|^[^aeiou]+/]
end_of_first == start_of_second
end
match("utua", "uailo")
# => false
match("inia", "iatu")
# => true
编辑:我显然无法阅读,我以为你只想匹配这个组(无论是元音还是辅音)。如果限制为元音组,则更简单:
end_of_first = first[/[aeiou]+$/]
start_of_second = second[/^[aeiou]+/]
答案 1 :(得分:0)
由于您已经预处理了字典,我建议您进行一些预处理以使生成更简单。我有两个建议。首先,对于starters和middles,将每个分成一个形式(VC,V)的元组(在Ruby中,我们只使用一个双元素数组),例如, "inia"
变为["in", "ia"]
:
starters = [
[ "-sm", "a" ],
[ "-r", "oa" ],
[ "-s", "i" ],
# ...
]
我们将启动器存储在数组中,因为我们只需要随机选择一个,我们可以使用Array#sample
:
starter, middle1_key = starters.sample
puts starter # => "-sm"
puts middle1_key # => "a"
我们希望能够通过他们的初始V组查找middles,所以我们将这些元组放在Hash中,而将其初始V组作为键:
middles = {
"ia" => [
[ "iat", "u" ],
[ "iabl", "e" ],
],
"i" => [
[ "in", "ia" ],
# ...
],
"a" => [
[ "ac", "i" ],
# ...
],
# ...
}
由于我们将起始器的最终V组存储在上面的middle1_key
中,我们现在可以使用它作为键来获取初始V组匹配的中间元组数组,并像上面一样随机选择一个:
possible_middles1 = middles[middle1_key]
middle1, middle2_key = possible_middles1.sample
puts middle1 # => "ac"
puts middle2_key => "i"
只是为了踢,让我们选择第二个中间位置:
middle2, ender_key = middles[middle2_key].sample
puts middle2 # => "in"
puts ender_key # => "ia"
我们的enders我们不需要存储在元组中,因为我们不会像使用middles一样使用它们中的任何部分。我们可以把它们放在哈希中,哈希的键是初始V组,其值是所有具有该初始V组的enders的数组:
enders = {
"a" => [ "ar-", ... ],
"oui" => [ "ouid-", ... ],
"u" => [ "ude-", ... ],
"ia" => [ "ial-", "iar-", ... ]
# ...
}
我们将第二个中间人的最终V组存储在上面的ender_key
中,我们可以使用它来获取匹配的enders数组:
possible_enders = enders[ender_key]
ender = possible_enders.sample
puts ender # => "iar-"
现在我们有四个部分,我们只是把它们放在一起形成我们的话:
puts starter + middle1 + middle2 + ender
# => -smaciniar-
上面的数据结构省略了相对频率(在我有机会阅读你关于数字的问题的答案之前,我写了上述内容)。显然,将相对频率存储在零件旁边也是微不足道的,但我不知道如何快速地以加权的方式选择零件。希望无论如何,我的答案对你有用。
答案 2 :(得分:0)
您可以使用方法Enumerable#flat_map,String#partition,Enumerable#chunk以及一些更熟悉的方法来实现这一目标:
def combine(arr)
arr.flat_map { |s| s.partition /[^aeiou-]+/ }.
chunk { |s| s }.
map { |_, a| a.first }.
join.delete('-')
end
combine ["-sma", "aba", "ar-"]) #=> "smabar"
combine ["-si", "inia", "iatu", "ude"] #=> "siniatude"
combine ["utua", "uailo", "orsua", "uav-"] #=> "utuauailorsuav"
要了解其工作原理,让我们看一下最后一个例子:
arr = ["utua", "uailo", "orsua", "uav-"]
a = arr.flat_map { |s| s.partition /[^aeiou-]+/ }
#=> ["u", "t", "ua", "uai", "l", "o", "o", "rs", "ua", "ua", "v", "-"]
enum = a.chunk { |s| s }
#=> #<Enumerator: #<Enumerator::Generator:0x007fdd14963888>:each>
我们可以通过将它转换为数组来查看此枚举器的元素:
enum.to_a
#=> [["u", ["u"]], ["t", ["t"]], ["ua", ["ua"]], ["uai", ["uai"]],
# ["l", ["l"]], ["o", ["o", "o"]], ["rs", ["rs"]], ["ua", ["ua", "ua"]],
# ["v", ["v"]], ["-", ["-"]]]
b = enum.map { |_, a| a.first }
#=> ["u", "t", "ua", "uai", "l", "o", "rs", "ua", "v", "-"]
s = b.join
#=> "utuauailorsuav-"
s.delete('-')
#=> "utuauailorsuav"