在Ruby中用字符串将元音改为其索引号的程序

时间:2015-10-24 16:38:42

标签: ruby

这是一个将元音改为索引的程序:

my $category_set=NotificationIRPConstDefs::NotificationCategorySetOpt->new();
$category_set->value(["1f1"]);

有谁能告诉我为什么它没能通过'Codewars是世界上最好的网站'?

当我尝试传递类似的测试用例时:

 def vowel_2_index(string)  
   return '' if string.nil?  
   arr = string.enum_for(:scan,/[aeiou]/i).map {Regexp.last_match.begin(0) }  
   s_arr = arr.map{|x| x+1 }  
   arr.each_with_index{|x,y| string[x] = s_arr[y].to_s}   
   string  
 end  

输出如下内容:

Test.assert_equals(vowel_2_index('Codewars is the best site in the world'),'C2d4w6rs 10s th15 b18st s23t25 27n th32 w35rld') 

3 个答案:

答案 0 :(得分:3)

正如您所看到的,当您开始用位置替换元音时,它的位置是单个数字(即15),但是当位置变为2位数时({{ 1}}和更大)所有找到的索引开始转移,10信息不再正确。

我建议使用gsub,因为你想进行全局搜索和替换,你几乎做得对:

arr

答案 1 :(得分:3)

以下所有内容均指:

str = 'Codewars is the best site in the world'

至于你遇到的问题,让我们分解一下:

enum = str.enum_for(:scan,/[aeiou]/i)
  #=> #<Enumerator: "Codewars is the best site in the world":scan(/[aeiou]/i)>

要查看由map传递给其块的此枚举器的元素,我们可以将其转换为数组:

enum.to_a
  #=> ["o", "e", "a", "i", "e", "e", "i", "e", "i", "e", "o"] 

继续:

arr = enum.map {Regexp.last_match.begin(0) }
  #=> [1, 3, 5, 9, 14, 17, 22, 24, 26, 31, 34] 
s_arr = arr.map{|x| x+1 }  
  #=> [2, 4, 6, 10, 15, 18, 23, 25, 27, 32, 35] 
arr.each_with_index{|x,y| string[x] = s_arr[y].to_s}   
  #=> [1, 3, 5, 9, 14, 17, 22, 24, 26, 31, 34] 
str
  #=> "C2d4w6rs 10s t15e18bes232527ite32i35 the world"

该方法应返回:

  #=> "C2d4w6rs 10s th15 b18st s23t25 27n th32 w35rld" 

所以你看到分歧开始于'h'中的'the',它位于索引13。将10的元素arr传递给块时会发生此问题。此时,

str
  #=>  "C2d4w6rs is the best site in the world"

块变量设置为:

x,y = [10, 3]
x #=> 10
y #=> 3

所以块计算是:

str[10] = s_arr[3].to_s
  #=>      = "10"

现在:

str
  #=> "C2d4w6rs 10s the best site in the world"

如您所见,10之后的所有字母的索引都增加了一个。这不是一个问题,因为前三个字符每个都用一位数字代替。 arrs_arr的其余元素现在由一个元素关闭,在下一个替换之后,剩余的元素的索引将关闭两个,依此类推。

                           *********

我会使用以下方法之一。

VOWELS = 'aeiouAEIOU'

<强>#1

pos = '0'
str.gsub(/./) { |c| pos.next!; VOWELS.include?(c) ? pos : c }
  #=> "C2d4w6rs 10s th15 b18st s23t25 27n th32 w35rld" 

<强>#2

str.each_char.with_index(1).map { |c,i| VOWELS.include?(c) ? i.to_s : c }.join
  #=> "C2d4w6rs 10s th15 b18st s23t25 27n th32 w35rld" 

#3

str.size.times.map { |i| VOWELS.include?(str[i]) ? (i+1).to_s : str[i] }.join
  #=> "C2d4w6rs 10s th15 b18st s23t25 27n th32 w35rld" 

我稍微偏爱#1,因为它直接对字符串进行操作,而不是创建数组然后将其元素连接回字符串。而且,我认为它读得最好。

答案 2 :(得分:1)

str = 'Codewars is the best site in the world'

您可以将字符串拆分为字符数组,并使用with_index(1)将每个值与regex.Am进行比较,因为数组基于零。

str.split(//).map.with_index(1){|k,v| /[aeiou]/=~k ? v : k}.join

结果是:

#=> 'C2d4w6rs 10s th15 b18st s23t25 27n th32 w35rld'