Ruby 来自字符串的首字母缩略词创建者

Ruby Acronym Creator from string

我正在创建一个接受字符串并创建首字母缩略词的函数,但 运行 出错了。 当我输入 "Complementary metal-oxide semiconductor" 时,我在 return 中得到 "CS" 而期望 "CMOS"。为什么会发生这种情况有什么建议吗?我给它传递了很多其他字符串并且它起作用了,只是在这种情况下不起作用。

class Acronym

    def self.abbreviate(phrase)
        letters = phrase.split("")
        acronym = []
        letters.each do |letter|
            previous = letters.index(letter) - 1
            if previous == -1
                acronym.push(letter)
            elsif letters[previous] == " " || letters[previous] == "-"
                acronym.push(letter)
            end
        end
        acronym.join("").upcase
    end

end

简化为

def acronym(str)
  str.split(/ |-/).map(&:first).join.upcase
end

以上依赖于Rails activesupport 库。这是仅 Ruby 的变体:

str.split(/ |-/).map { |s| s[0] }.join.upcase 

您可以尝试使用 gsub 来忽略连字符。

<%= ('Complementary metal-oxide semiconductor').gsub('-', ' ') %>

Returns:互补金属氧化物半导体

您在 previous = letters.index(letter) - 1

中有一个错误

看看你能不能发现它:

arr = [:a, :b, :c, :a]
previous_indexes = arr.map { |n| arr.index(n) - 1 }
you_are_expecting = [-1, 0, 1, 2]

previous_indexes == you_are_expecting
# => false

arr.index(:a) # => 0
arr.index(:b) # => 1
arr.index(:c) # => 2
arr.index(:a) # => 0

要通过迭代获取索引,请使用 with_index:

arr = %i[a b c a]
arr.map.with_index { |x, i| [x, i] }
# => [[:a, 0], [:b, 1], [:c, 2], [:a, 3]]

如果您进行了该修复,您的代码将按预期运行。

一个建议:你通常可以避免处理数组索引的细节。通过更高层次的操作,看看是如何工作的。

您的代码的问题是 index() returns 第一次 给定字母的出现。所以,两个问题:

  1. 'metal' 中的 'm' 不是字符串中 'm' 的第一次出现。它出现在单词 'complementary' 中。因此,只要它在字符串中看到 'm',previous 将始终是 'o',因此不会触发 push().
  2. 只要您的字符串中的第一个字母重复出现(无论位置如何),它都会触发您的第一个条件。如果将测试字符串中的初始 'C' 更改为 'c' ,您可以看到效果。结果将是 CSCC 因为 'semiconductor'.
  3. 中有两个 'c'

作为替代方案,这里有一个使用正则表达式的选项:

def self.abbreviate(phrase)
  phrase.gsub('-', ' ')
        .scan(/(\A\w|(?<=\s)\w)/)
        .flatten
        .join.upcase
end

一步一步:

  1. 从@DollarChills 借用 .gsub 将 '-' 变成 space。
  2. scan() returns 所有匹配的数组。正则表达式匹配字符串中的第一个单词以及前面带有 space.
  3. 的任何单词
  4. scan 的结果实际上是一个数组数组,因此 flatten 会取消嵌套它们。
  5. 组合成字符串和大写