我正在创建一个函数,该函数接受一个字符串并创建一个缩写词,但遇到了错误。当我输入"Complementary metal-oxide semiconductor"
时,当我期望"CMOS"
时,我得到"CS"
作为回报。为什么会发生这种情况,有什么建议吗?我传递了很多其他字符串,它有效,只是在这种情况下不起作用。
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
代码的问题是index()
返回给定字母的第一个出现。因此,有两个问题:
- 'metal'中的'm'不是字符串中'm'的第一个出现。它出现在"互补"一词中。因此,每当它在字符串中看到"m"时,前一个总是"o",因此不会触发
push()
- 只要字符串中的第一个字母重复出现(无论位置如何(,就会触发第一个条件。如果将测试字符串中的首字母"C"更改为"C",则可以看到效果。结果将是
CSCC
,因为"半导体"中有两个"c">
作为一种替代方案,这里有一个使用regex:的选项
def self.abbreviate(phrase)
phrase.gsub('-', ' ')
.scan(/(Aw|(?<=s)w)/)
.flatten
.join.upcase
end
循序渐进:
- 借用@DollarChills的
.gsub
将"-"变成一个空间 scan()
返回所有匹配项的数组。正则表达式匹配字符串中的第一个单词和前面有空格的任何单词scan
的结果实际上是一个数组的数组,所以扁平化将不测试它们- 组合成字符串并大写
您可以尝试使用gsub来忽略连字符。
<%= ('Complementary metal-oxide semiconductor').gsub('-', ' ') %>
退货:互补金属氧化物半导体
您在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]]
如果您进行了修复,那么您的代码将按您的意图执行。
不过有一个建议:您通常可以避免处理数组索引的细节。看看@Mori的答案是如何在更高层次上运作的。