0

I have this bit of Ruby code, which pulls all the vowels out of an array of strings while preserving punctuation:

def remove_vowels(arr)
  arr.map do |word|
    word.scan(/[\W||\w&&[^aeiou]]/).join
  end
end

arr = %w(Hello! How are you? My name is Bob; what is yours?)

p remove_vowels(arr)
# => ["Hll!", "Hw", "r", "y?", "My", "nm", "s", "Bb;", "wht", "s", "yrs?"]

I'm curious why putting ||\W on the tail end of the expression, so:

word.scan(/[\w&&[^aeiou]||\W]/).join

has no effect, requiring to lead with \W|| instead. Is there some rule about the order in Regexp that explains this, or is it a simple syntax error?

BobRodes
  • 5,990
  • 2
  • 24
  • 26

1 Answers1

2

|| is not OR in RegEx, and inside the [], there's no need OR.
You can simply write your regex like this: /[[\w&&[^aeiou]]\W]/. (update: or just /[^aeiou]/)
On the other hand, && is Class Intersection.

Examples:

arr
#=> ["Hello!", "How", "are", "you?", "[]||&\\", "My", "name", "is", "Bob;", "what", "is", "yours?"]
arr.map do |word| word.scan(/[[\w&&[^aeiou]]\W]/).join; end
#=> ["Hll!", "Hw", "r", "y?", "[]||&\\", "My", "nm", "s", "Bb;", "wht", "s", "yrs?"]
arr.map do |word| word.scan(/[[\w&&[^aeiou]]|]/).join; end # | inside [] will be read literally.
#=> ["Hll", "Hw", "r", "y", "||", "My", "nm", "s", "Bb", "wht", "s", "yrs"]
arr.map do |word| word.scan(/[[\w&&[^aeiou]]||]/).join; end
#=> ["Hll", "Hw", "r", "y", "||", "My", "nm", "s", "Bb", "wht", "s", "yrs"]
## Note this one, it is OR now:
arr.map do |word| word.scan(/[\w&&[^aeiou]]|\W/).join; end
#=> ["Hll!", "Hw", "r", "y?", "[]||&\\", "My", "nm", "s", "Bb;", "wht", "s", "yrs?"]

And as Mr. Swoveland correctly pointed out in comments, /[\W||\w&&[^aeiou]]/ is essentially the same as /[^aeiou]/, because the latter class actually includes \W.
Also you might want to add i flag to be case insensitive:

arr = %w(Hello! How are you? []||&\\ hELLO My name is Bob; what is yours?)
arr.map do |word| word.scan(/[\W||\w&&[^aeiou]]/).join; end
#=> ["Hll!", "Hw", "r", "y?", "[]||&\\", "hELLO", "My", "nm", "s", "Bb;", "wht", "s", "yrs?"]
arr.map do |word| word.scan(/[^aeiou]/).join; end
#=> ["Hll!", "Hw", "r", "y?", "[]||&\\", "hELLO", "My", "nm", "s", "Bb;", "wht", "s", "yrs?"]
arr.map do |word| word.scan(/[^aeiou]/i).join; end
#=> ["Hll!", "Hw", "r", "y?", "[]||&\\", "hLL", "My", "nm", "s", "Bb;", "wht", "s", "yrs?"]
Til
  • 5,150
  • 13
  • 26
  • 34
  • 1
    Isn't `/[\W||\w&&[^aeiou]]/` the same as `/[^aeiou]/`, considering that a character is either a word character or a non-word character? – Cary Swoveland Feb 16 '19 at 06:09
  • @CarySwoveland I can see that I was overthinking this when I first put it together! :) But still, I wanted to understand the mechanism for times when I might need to. – BobRodes Feb 16 '19 at 08:40