【问题标题】:Ruby: Scanning strings for matching adjacent vowel groupsRuby:扫描字符串以匹配相邻的元音组
【发布时间】:2015-10-23 00:40:25
【问题描述】:

我正在构建一个脚本来随机生成听起来像英语的单词。我把大量的英文单词分解成VCV groups

...其中 V 代表单词中所有相邻的元音,C 代表所有相邻的辅音。例如,英文单词“miniature”会变成 “-mi”、“inia”、“iatu”和“ure”。 “school”将变成“-scho”和“ool”。 这些组将与来自其他单词的其他组组合在一起 规则是完整的相邻结尾元音集必须匹配 附组的完整起始元音集。

我已经在以下结构中构造了一个哈希:

pieces = { 
   :starters => { "-sma" => 243, "-roa" => 77, "-si" => 984, ...},
   :middles =>  { "iatu" => 109, "inia" => 863, "aci" => 229, ...},
   :enders =>   { "ar-" => 19, "ouid-" => 6, "ude" => 443,   ...}
}

为了构造生成的单词,“starter”字符串需要以与“middle”字符串相同的元音分组结尾。将“middle”字符串与“ender”字符串连接时也是如此。使用上述示例的一种可能结果是 "-sma" + "aba" + "ar-" 得到 "smabar"。另一个是 "-si" + "inia" + "iatu" + "ude" 给出 "siniatude"

我的问题是,当我对任意两件进行采样时,我不知道如何确保第一件的结束 V 组与第二件的开始 V 组完全匹配。例如,“utua”+“uailo”不能一起使用,因为 “ua”“uai” 不同。但是,成功的对将是 "utua" + "uado",因为 "ua" = "ua"

【问题讨论】:

  • 你的数据结构中的数字(243、77、984等)代表什么?
  • 相对频率。在分析的所有单词中,该组出现了该次数。

标签: ruby regex string


【解决方案1】:
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]+/]

【讨论】:

    【解决方案2】:

    由于您已经对字典进行了预处理,因此我建议您进行更多的预处理以简化生成过程。我有两个建议。首先,对于初学者和中间人,将它们分成一个元组(在 Ruby 中,我们只使用一个二元素数组),形式为 (VC, V),例如"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 组来查找中间,因此我们将这些元组放在一个 Hash 中,并将它们的初始 V 组作为键:

    middles = {
      "ia" => [
        [ "iat", "u" ],
        [ "iabl", "e" ],
      ],
      "i" => [
        [ "in", "ia" ],
        # ...
      ],
      "a" => [
        [ "ac", "i" ],
        # ...
      ],
      # ...
    }
    

    由于我们在上面的middle1_key 中存储了 starter 的最终 V 组,我们现在可以使用它作为键来获取初始 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 存储在元组中,因为我们不会像使用中间件那样使用它们的任何部分来查找任何内容。我们可以将它们放在一个哈希中,其键是初始 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-
    

    编辑

    上面的数据结构省略了相对频率(我在有机会阅读您对我关于数字的问题的回答之前写了上面的内容)。显然,将相对频率也存储在零件旁边是微不足道的,但我不知道有一种快速的方法来以加权方式选择零件。希望我的回答对你有所帮助。

    【讨论】:

      【解决方案3】:

      您可以使用Enumerable#flat_mapString#partitionEnumerable#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" 
      

      【讨论】:

        猜你喜欢
        • 2020-08-29
        • 2011-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-15
        相关资源
        最近更新 更多