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 第一次 给定字母的出现。所以,两个问题:
- 'metal' 中的 'm' 不是字符串中 'm' 的第一次出现。它出现在单词 'complementary' 中。因此,只要它在字符串中看到 'm',previous 将始终是 'o',因此不会触发
push()
.
- 只要您的字符串中的第一个字母重复出现(无论位置如何),它都会触发您的第一个条件。如果将测试字符串中的初始 'C' 更改为 'c' ,您可以看到效果。结果将是
CSCC
因为 'semiconductor'. 中有两个 'c'
作为替代方案,这里有一个使用正则表达式的选项:
def self.abbreviate(phrase)
phrase.gsub('-', ' ')
.scan(/(\A\w|(?<=\s)\w)/)
.flatten
.join.upcase
end
一步一步:
- 从@DollarChills 借用
.gsub
将 '-' 变成 space。
scan()
returns 所有匹配的数组。正则表达式匹配字符串中的第一个单词以及前面带有 space. 的任何单词
scan
的结果实际上是一个数组数组,因此 flatten 会取消嵌套它们。
- 组合成字符串和大写
我正在创建一个接受字符串并创建首字母缩略词的函数,但 运行 出错了。
当我输入 "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 第一次 给定字母的出现。所以,两个问题:
- 'metal' 中的 'm' 不是字符串中 'm' 的第一次出现。它出现在单词 'complementary' 中。因此,只要它在字符串中看到 'm',previous 将始终是 'o',因此不会触发
push()
. - 只要您的字符串中的第一个字母重复出现(无论位置如何),它都会触发您的第一个条件。如果将测试字符串中的初始 'C' 更改为 'c' ,您可以看到效果。结果将是
CSCC
因为 'semiconductor'. 中有两个 'c'
作为替代方案,这里有一个使用正则表达式的选项:
def self.abbreviate(phrase)
phrase.gsub('-', ' ')
.scan(/(\A\w|(?<=\s)\w)/)
.flatten
.join.upcase
end
一步一步:
- 从@DollarChills 借用
.gsub
将 '-' 变成 space。 scan()
returns 所有匹配的数组。正则表达式匹配字符串中的第一个单词以及前面带有 space. 的任何单词
scan
的结果实际上是一个数组数组,因此 flatten 会取消嵌套它们。- 组合成字符串和大写