编写正则表达式作为 gsub 的参数!方法——难倒?

Writing a regexp as argument to gsub! method -- stumped?

在我的 Rails 4.2.6 / Ruby 2.2.4 应用程序中,我有一个生成字符串的数据库查询方法;例如:

"Chest - pectoralis, Quads - quadriceps, Hamstrings - biceps femoris"

然而,我想要的结果是:

"Chest, Quads, Hamstrings"

域跟踪 21 个肌肉群,这意味着生成的字符串可以有很多不同的组合。但是,字符串将始终具有相同的模式,即:"common muscle name - technical muscle name".

使用条件逻辑,我可以通过将 "string" 个参数传递给 gsub 方法来获得我想要的结果,如下所示:

 if @muscle_group_ids == [1, 13, 14]
    @muscle_group_names = MuscleGroup.where(id: @muscle_group_ids).map { |n|   n[:name]
   }.join(', ').gsub!("Chest - pectoralis", "Chest").gsub!("Quads -    quadriceps", "Quads").gsub!("Hamstrings - biceps femoris", "Hamstrings")
end
=> "Chest, Quads, Hamstrings"

这种方法不可行;它既乏味又脆弱。必须有更好的方法来从生成的字符串中删除破折号和技术名称。我对如何最好地完成这项工作感到困惑。是否可以编写一个正则表达式来达到预期的结果,如何实现?是否有更简单、更好、更清洁的方法来实现我想要做的事情?谢谢!

像这样?

irb(main):001:0> s="Chest - pectoralis, Quads - quadriceps, Hamstrings - biceps femoris"
irb(main):002:0> s.gsub(/(\w+)\s+-\s+[^,]*/, '')
=> "Chest, Quads, Hamstrings"

搜索任意数量 (+) 的 "word" 个字符 (\w),它会记住这些字符,因为它们在括号中,后跟 space (\s+)、一个连字符、更多 space,以及任何不是逗号的内容 ([^,]*)。它只用它记住的单词字符 (</code>) 替换所有这些.</p> <p>该模式非常具体,如果常见名称可能不止一个词,则需要进行修改。</p> <p>此外,我只是对 return 执行了上面的 <code>gsub(并在 irb 中显示)结果;要就地修改字符串,您可以使用 gsub!.

肌肉群#common_name

最简单的方法是在 MuscleGroup 模型中定义一个新方法:

def common_name
  name.split(' - ').first
end

您的代码变为:

@muscle_group_names = MuscleGroup.where(id: @muscle_group_ids).map { |muscle_group|
  muscle_group.common_name }.join(', ')

双分裂

如果出于某种原因,您已经有了一个完整的字符串,则双重拆分可能比大正则表达式更健壮且更易于阅读。

您可以围绕 ', ' 拆分以获得 "common muscle name - technical muscle name" 的数组。然后,您可以围绕 ' - ' 拆分每个字符串并保留第一部分:

"Chest - pectoralis, Quads - quadriceps, Hamstrings - biceps femoris".
  split(', ').map{|s| s.split(' - ').first}
# ["Chest", "Quads", "Hamstrings"]

一旦你有了数组,你就可以连接回一个字符串:

"Chest - pectoralis, Quads - quadriceps, Hamstrings - biceps femoris".
  split(', ').map{|s| s.split(' - ').first}.join(', ')
#  "Chest, Quads, Hamstrings"

您可以在地图函数中 " -" 上拆分名称,并且只有 return 第一部分像这样:

if @muscle_group_ids == [1, 13, 14]
    @muscle_group_names = MuscleGroup.where(id: @muscle_group_ids).map { |n|   
        n = n[:name].split(" -")[0] 
    }.join(', ')
end
=> "Chest, Quads, Hamstrings"
 r = /[[:alpha:]]+     # match one or more letters
      [\s+[:alpha:]+]* # match one or more spaces followed by one or more letters,
                       # zero or more times, to match any words after the first
      (?=\s+-\s+)      # match a hyphen surrounded by whitespace in a positive lookahead
     /x                # free-spacing regex definition mode

"Chest - pectoralis, Quads - quadriceps, Achilles heel - Achilles tendon".scan(r)
  #=> ["Chest", "Quads", "Achilles heel"]