Here is my array:
a = ['a','b','c', 'C!', 'D!']
I would like to select any upcase letters followed by the ! character and display them. I was trying:
puts a.select! {|i| i.upcase + "!"}
which gave me null set. Any help would be greatly appreciated.
puts a.grep(/[A-Z]!/)
will do.
Try the following:
a.select {|i| i =~ /[A-Z]!/}
Here's another way using the Regexp match method in Ruby.
a.select { |letter| /[A-Z]!/.match(letter) }
Also, one note: consider a more meaningful and contextually relevant variable name than "i" in a.select! {|i| i.upcase + "!"}. For example, I chose the name "letter", although there may be a more meaningful name. It's just a good naming practice that a lot of Ruby programmers tend to follow. Same thing applies to the array named a.
Related
I want to replace the content (or delete it) that does not match with my filter.
I think the perfect description would be an opposite sub. I cannot find anything similar in the docs, and I'm not sure how to invert the regex, but I think a method would probably be the more convenient.
An example of how it would work (I've just changed the words to make it more clear)
"bird.cats.dogs".opposite_sub(/(dogs|cats)\.(dogs|cats)/, '')
#"cats.dogs"
I hope it's easy enough to understand.
Thanks in advance.
String#[] can take a regular expression as its parameter:
▶ "bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#⇒ "cats.dogs"
For multiple matches one can use String#scan:
▶ "bird.cats.dogs.bird.cats.dogs".scan /(?:dogs|cats)\.(?:dogs|cats)/
#⇒ ["cats.dogs", "cats.dogs"]
So you want to extract the part that matches your regex?
You can use String#slice, for example:
"bird.cats.dogs".slice(/(dogs|cats)\.(dogs|cats)/)
#=> "cats.dogs"
And String#[] does the same.
"bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#=> "cats.dogs"
You cannot have a single replacement string because the part of the string that matches the regex might not be at the beginning or end of the string, in which case it's not clear whether the replacement string should precede or follow the matching string. I've therefore written the following with two replacement strings, one for pre-match, the other for post_match. I've made this a method of the String class as that's what you've asked for (though I've given the method a less-perfect name :-) )
class String
def replace_non_matching(regex, replace_before, replace_after)
first, match, last = partition(regex)
replace_before + match + replace_after
end
end
r = /(dogs|cats)\.(dogs|cats)/
"birds.cats.dogs.pigs".replace_non_matching(r, "", "")
#=> "cats.dogs"
"birds.cats.dogs".replace_non_matching(r, "snakes.", ".hens")
#=> "snakes.cats.dogs.hens"
"birds.cats.dogs.mice.cats.dogs.bats".replace_non_matching(r, "snakes.", ".hens")
#=> "snakes.cats.dogs.hens"
Regarding the last example, the method could be modified to replace "birds.", ".mice." and ".bats", but in that case three replacement strings would be needed. In general, determining in advance the number of replacement strings needed could be problematic.
I need to puts a string like
puts "#{movie.title}, #{movie.imdb_rating.round(3)}, #{movie.imdb_ratings_count}"
So the output will be Gone Girl, 8.23, 302532
However, these are quite tedious since I always need to add #{} and "",
What is a good way to quick puts, without always adding #{} and ""?
I suggest constructing an array and using the join method.
def printStrings do *strings
strings.join(', ')
end
printStrings 'apple', 'banana', 'orange' #'apple, banana, orange'
Alternatively, you can utilize a special variable, called the output field separator, which you can access as $,. (Its default value is nil)
$, = ', '
print 'apple', 'banana', 'orange' #'apple, banana, orange'
$, = nil
This method is outlined in the docs for print
It would make sense to add a method to the Movie class:
class Movie
def to_desc
"##title, #{#imdb_rating.round(3)}, ##imdb_ratings_count"
end
end
LukeP's answer is good if you want the same punctuation between each value but if you want something with a varying format, eg Gone Girl - 8.23, 302532, you can use ruby's % operator for string formating:
"%s - %s, %s" % [movie.title, movie.imdb_rating.round(3), movie.imdb_ratings_count]
Ruby's printing is solid but not amazing. Have you looked at the Awesome Print gem?
https://github.com/michaeldv/awesome_print
It's what I use to do elegant printing. It's a little unclear exactly how you're asking to format it, but this gems seems like it'll give you enough options to solve your problem.
I often remove substrings from strings by doing this:
"don't use bad words like".gsub("bad", "").gsub("words", "").gsub("like", "")
What's a more concise/better way of excising long lists of substrings from a string in Ruby?
I would go with nronas' answer, however people tend to forget about Regexp.union:
str = "don't use bad words like"
str.gsub(Regexp.union('bad', 'words', 'like'), '')
# or
str.gsub(Regexp.union(['bad', 'words', 'like']), '')
You can always use regex when you gsubing :P. like:
str = "don't use bad words like"
str.gsub(/bad|words|like/, '')
I hope that helps
Edit2: Upon reflection, I think what I have below (or any solution that first breaks the string into an array of words) is really what you want. Suppose:
str = "Becky darned her socks before playing badmitten."
bad_words = ["bad", "darn", "socks"]
Which of the following would you want?
str.gsub(Regexp.union(*bad_words), '')
#=> "Becky ed her before playing mitten."
or
(str.split - bad_words).join(' ')
#=> "Becky darned her before playing badmitten."
Alternatively,
bad_words.reduce(str.split) { |arr,bw| arr.delete(bw); arr }.join(' ')
#=> "Becky darned her before playing badmitten."
:2tidE
Edit1: I've come to my senses and purged my solution. It was much too elaborate (and inefficient) for such a simple problem. I've just left an observation. :1tidE
If you want to end up with just a single space between words, you need to take a different tack:
(str.split - bad_words).join(' ')
#=> "don't use
I already suggested this to Cary, but it's here:
bad_words = %w[bad words like]
h = Hash.new{|h, k| k}.merge(bad_words.product(['']).to_h)
"don't use bad words like".gsub(/\w+/, h)
In my app, I have to monitor what users type. So I have to prevent any bad words from the web site. Just for example, suppose all my bad words were in this array.
bad_words = ['bad', 'evil', 'terrible', 'villain', 'enemy']
If a user typed those, I would like them to be deleted. Here was one thing I tried.
bad_words.each {|word| string.gsub(word, '')}
Help is appreciated.
You can use a Gem to do the clean job:
https://github.com/tjackiw/obscenity
including the gem will allow you methods like:
Obscenity.configure { |config| config.whitelist = bad_words }
and then:
Obscenity.sanitize(string)
Here's one way:
bad_words = ['bad', 'evil', 'terrible', 'villain', 'enemy']
orig_str =
"Evil is embodied by a terrible villain named 'Bad' who plays badmitten"
no_bad_str = orig_str.gsub(/(?<=^|\W)\w+(?=\W|$)/) { |w|
(bad_words.include?(w.downcase)) ? '' : w }
#=> " is embodied by a named '' who plays badmitten"
(?<=^|\W) is a positive lookbehind
(?=\W|$) is a positive lookahead
Can bad, evil and terrible words sneak by? Of course. Some examples for orig_str:
badbadbad
evilterribleenemy
eviloff
flyingevil
Good luck!
You can either do
bad_words.each {|word| string = string.gsub(word, '')}
or
bad_words.each {|word| string.gsub!(word, '')}
Either should work issue with your original was that it was returning a new string not modifying the old one like the to solutions I have proposed above.
You can use Regexp.union to create a regular expression containing all the words in yours list:
bad_words = ['bad', 'evil', 'terrible', 'villain', 'enemy']
Regexp.union(bad_words)
# => /bad|evil|terrible|villain|enemy/
string.gsub(Regexp.union(bad_words), '')
I have a list of names in an array in Ruby:
names = ["John Smith","Bob Miller"]
So I want to do a regex and get this array:
namesRegex = ["JS","BM"]
This is, I extract the uppercase characters from the string, merge them and put them in a new array.
Any help is appreciated.
This is really simple:
names.map { |name| name.gsub(/[^A-Z]/, '') }
You could very readily construct a less elegant but wholly valid solution to this problem that doesn't even require the use of regular expressions or mapping.
names.map { |name| name.scan(/\b\w/).*'' }