简体   繁体   中英

Program to change vowel to its index number in string in Ruby

This is a program to change a vowel into its index:

 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  

Can anyone tell me why it's failing to pass 'Codewars is the best site in the world'?

When I try to pass a testcase like:

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

it outputs something like:

"C2d4w6rs 10s t15e18bes232527ite32i35 the world"

As you can see, when you start replacing vowels with their positions it works while the position is a single digit (ie 1 or 5 ), but when position becomes 2-digit ( 10 and bigger) all found indexes start to shift and arr information is not correct anymore.

I'd propose to use gsub , since you want to do a global search and replace, you almost did it right:

str = 'Codewars is the best site in the world'    
str.gsub(/[aeiou]/) { |item| Regexp.last_match.begin(0) + 1 }
# => "C2d4w6rs 10s th15 b18st s23t25 27n th32 w35rld"

All of the following refers to:

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

As to the problem you are having, let's break it down:

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

To see the elements of this enumerator that are passed by map to its block, we can convert it to an array:

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

Continuing:

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"

The method should return:

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

So you see the divergence begins with 'h' in 'the' , which is at index 13 . The problem occurs when element 10 of arr is passed to the block. At this point,

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

The block variables are set to:

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

so the block calculation is:

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

and now:

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

As you see, the indices of all the letters following 10 have increased by one. This wasn't a problem earlier because the first three characters were each replaced with a single-digit number. The remaining elements of arr and s_arr are now off by one, and after the next replacement the indices of those that remain will be off by two, and so on.

                           *********

I would use one of the following approaches.

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" 

I have a slight preference for #1 because it operates on the string directly, as opposed to creating an array and then joining its elements back into a string. Moreover, I think it reads best.

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

You can split string to array of chars and compare each value with the regex.Am using with_index(1) because array is zero based.

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

Which results to:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM