RegEx in Ruby: Just one match? - ruby

I'm trying to figure out how to check if a string matches a regular expression, but I want to know if the entire string matches just once. Here's my code but it seems absurdly long
def single_match(test_me, regex)
ret_val = false
test = regex.match(test_me)
if (test.length==1 && test[0].length == test_me.length)
ret_val = true
end
return ret_val
end
is there an easier way to do this?
P.S. Here's the method I'm really trying to write, since people always seem to ask why I want the gun these days:
def is_int(test_me)
return single_match(test_me, /[0-9]*/)
end
Edit Thanks everybody. Here's where I'm really using it, but this regex stuff is always interesting to go through. Thanks for the great and educational answers.

You don't need to do this, your method can be replaced by using the regular expression of /^[0-9]*$/. The ^ tells it match start of a line and $ tells it match end of the line. So it will match: start of line, 0 to any in range of 0 to 9, and finally end of line.
def is_int(test_me)
test_me =~ /^[0-9]*$/
end
And you don't need the return statements, Ruby implicitly returns the last statement.
Edit:
It probably would be easier and look better to use the to_i instance method of String class.
def is_int(test_me)
test_me.to_i.to_s == test_me
end
Edit: (did some tests)
Comparing the performance between the two methods shows that .to_i.to_s == way is 5% faster. So it is up to personal preference to which ever looks better and if you want to handle leading zeroes.

To do what you really want should be even simpler
def is_int(test_me)
test_me.to_i.to_s == test_me
end

This?
def single_match(str, regex)
str.match(regex).to_s == str
end

To answer your original question, for the sake of people finding this page in a search, "scan" will return an array of matches, so if you want to find out how many times some regexp matches, e.g. how many runs of digits there are, you can do:
mystring.scan(/\d+/).size

Related

Ruby Anagram Comparison Module

I am new to Ruby and trying to figure out a problem for an online test. The problem is as follows:
An anagram is a word formed from another by rearranging its letters,
using all the original letters exactly once; for example, orchestra
can be rearranged into carthorse.
Write a function that checks if two words are each other's anagrams.
For example, AreAnagrams.are_anagrams?('momdad', 'dadmom') should
return true as arguments are anagrams.
The code I have come up with is this:
module AreAnagrams
def self.are_anagrams?(string_a, string_b)
## Create #word1 variable to store string_a
#word1 = string_a
## Create #word1_compare variable to store string_a in lower case
#word1_compare = #word1.downcase
## Create #word2_compare variable to store string_b
#word2 = string_b
## Create #word2_compare variable to store string_b in lower case
#word2_compare = #word2.downcase
## Check length of #word1 and #word2 to make sure they are the same length
if #word1.length == #word2.length
=begin
Sort the letters of the #word1 and #word2 variables and compare
them to see if they are anagrams
=end
if #word1_compare.chars.sort.join == #word2_compare.chars.sort.join
puts "#{#word1} and #{#word2} are anagrams!"
else
puts "#{#word1} and #{#word2} are not anagrams!"
end
else
puts "#{#word1} and #{#word2} are not anagrams!"
end
end
end
When I submit the code, I get the following back from the test:
Compilation OK, but 4 out of 4 test cases fail
Sample case: Wrong answer
Words with unique letters: Wrong answer
Words with duplicate letters: Wrong answer
One word is the prefix of another word: Wrong answer
I have tested my code with multiple strings and it seems to work just fine. It looks like it wants me to check for more specific instances (special characters, words with duplicate letters, etc.) but is that really required? Sorry if it's a dumb question, I'm new to Ruby and lost.
Any help would be greatly appreciated!
I think the problem here is you're displaying a message but not returning a true or false value which is what is expected.
After each puts, include the appropriate answer. That way your method will return something useful. Right now I'm presuming it's nil for all cases, since that's what puts returns.

Convert a letter to its corresponding control code

Given a single letter (string), say "a", I want to convert this into its corresponding control code, i.e. "\ca" - or equivalently (in alternate syntax) - "\C-a", ?\ca, "\x01", "\u0001"
I was hoping there'd be some "nice", clean way of doing this conversion, but I can't figure it out.
An obvious first attempt might be to try something like:
def convert_to_control_code(letter)
"\c#{letter}"
end
...But this does not work, since this will always return "\u0003{letter}" (where "\u0003" is the control code "\c#"
My current solution is simply to "brute force" it by doing the following:
def convert_to_control_code(letter)
(0..255).detect { |x| x.chr =~ Regexp.new("\\c#{char}") }.chr
end
However, I can't help but feel there's a "right" way of doing this!
Edit:
Here's another, non brute-force solution I've come up with, that seems to work:
def convert_to_control_code(letter)
(letter.ord % 32).chr
end
This looks much nicer, but also very hacky!
You can write it as :
def convert_to_control_code(letter)
eval "?\\C-#{letter.chr}"
end
convert_to_control_code(97) # => "\u0001"
convert_to_control_code(98) # => "\u0002"
One possibility is to do the same as Ruby itself does. It might look something like this:
def convert_to_control(letter)
letter = letter.chr # ensure we are only dealing with a single char
return 0177.chr if letter == '?'
raise 'an error' unless letter.ascii_only? # or do something else
(letter.ord & 0x9f).chr
end
You might want to change the encoding of the result depending on what you are doing.

Push an array into another array with Ruby, and return square brackets

I've spent a few hours searching for a way to push an array into another array or into a hash. Apologies in advance if the formatting of this question is bit messy. This is the first time I've asked a question on StackOverflow so I'm trying to get the hang of styling my questions properly.
I have to write some code to make the following test unit past:
class TestNAME < Test::Unit::TestCase
def test_directions()
assert_equal(Lexicon.scan("north"), [['direction', 'north']])
result = Lexicon.scan("north south east")
assert_equal(result, [['direction', 'north'],
['direction', 'south'],
['direction', 'east']])
end
end
The most simple thing I've come up with is below. The first part passes, but then the second part is not returning the expected result when I run rake test.
Instead or returning:
[["direction", "north"], ["direction", "south"], ["direction",
"east"]]
it's returning:
["north", "south", "east"]
Although, if I print the result of y as a string to the console, I get 3 separate arrays that are not contained within another array (as below). Why hasn't it printed the outermost square brackets of the array, y?
["direction", "north"]
["direction", "south"]
["direction", "east"]
Below is the code I've written in an attempt to pass the test unit above:
class Lexicon
def initialize(stuff)
#words = stuff.split
end
def self.scan(word)
if word.include?(' ')
broken_words = word.split
broken_words.each do |word|
x = ['direction']
x.push(word)
y = []
y.push(x)
end
else
return [['direction', word]]
end
end
end
Any feedback about this will be much appreciated. Thank you all so much in advance.
What you're seeing is the result of each, which returns the thing being iterated over, or in this case, broken_words. What you want is collect which returns the transformed values. Notice in your original, y is never used, it's just thrown out after being composed.
Here's a fixed up version:
class Lexicon
def initialize(stuff)
#words = stuff.split
end
def self.scan(word)
broken_words = word.split(/\s+/)
broken_words.collect do |word|
[ 'direction', word ]
end
end
end
It's worth noting a few things were changed here:
Splitting on an arbitrary number of spaces rather than one.
Simplifying to a single case instead of two.
Eliminating the redundant return statement.
One thing you might consider is using a data structure like { direction: word } instead. That makes referencing values a lot easier since you'd do entry[:direction] avoiding the ambiguous entry[1].
If you're not instantiating Lexicon objects, you can use a Module which may make it more clear that you're not instantiating objects.
Also, there is no need to use an extra variable (i.e. broken_words), and I prefer the { } block syntax over the do..end syntax for functional blocks vs. iterative blocks.
module Lexicon
def self.scan str
str.split.map {|word| [ 'direction', word ] }
end
end
UPDATE: based on Cary's comment (I assume he meant split when he said scan), I've removed the superfluous argument to split.

Test whether a variable equals either one of two values

I want to test whether a equals 1 or 2
I could do
a == 1 || a == 2
but this requires repeating a (which would be annoying for longer variables)
I'd like to do something like a == (1 || 2), but obviously this won't work
I could do [1, 2].include?(a), which is not bad, but strikes me as a bit harder to read
Just wondering how do to this with idiomatic ruby
Your first method is idiomatic Ruby. Unfortunately Ruby doesn't have an equivalent of Python's a in [1,2], which I think would be nicer. Your [1,2].include? a is the nearest alternative, and I think it's a little backwards from the most natural way.
Of course, if you use this a lot, you could do this:
class Object
def member_of? container
container.include? self
end
end
and then you can do a.member_of? [1, 2].
I don't know in what context you're using this in, but if it fits into a switch statement you can do:
a = 1
case a
when 1, 2
puts a
end
Some other benefits is that when uses the case equality === operator, so if you want, you can override that method for different behavior. Another, is that you can also use ranges with it too if that meets your use case:
when 1..5, 7, 10
One way would be to petition "Matz" to add this functionality to the Ruby specification.
if input == ("quit","exit","close","cancel") then
#quit the program
end
But the case-when statement already lets you do exactly that:
case input when "quit","exit","close","cancel" then
#quit the program
end
When written on one line like that, it acts and almost looks like an if statement. Is the bottom example a good temporary substitution for the top example? You be the judge.
First put this somewhere:
class Either < Array
def ==(other)
self.include? other
end
end
def either(*these)
Either[*these]
end
Then, then:
if (either 1, 2) == a
puts "(i'm just having fun)"
end
You can just use intersection like
([a] & [1,2]).present?
a alternative way.
Include is definitely the way to go here. 🤝
%w[cat dog].include?(type)
a.to_s()=~/^(1|2)$/
Maybe I'm being thick here, but it seems to me that:
(1..2) === a
...works.

Converting an empty string into nil in Ruby

I have a string called word and a function called infinitive such that
word.infinitive would return another string on some occasions and an empty string otherwise
I am trying to find an elegant ruby one line expression for the code-snippet below
if word.infinitive == ""
return word
else return word.infinitive
Had infinitive returned nil instead of "", I could have done something like
(word.infinitive or word)
But since it does not, I can't take advantage of the short-circuit OR
Ideally I would want
1) a single expression that I could easily embed in other code
2) the function infinitive being called only once
3) to not add any custom gems or plugins into my code
The ActiveSupport presence method converts an empty (or blank?) string to nil. It's designed for your exact use case:
word.infinitive.presence || word
Note that you can easily use ActiveSupport outside of rails:
require 'active_support/core_ext/object/blank'
You can use a regex like this article suggests
(word.infinitive[/.+/m] or word) #Fancy way to convert "" to nil
If you're not ashamed of monkeypatching and abusing syntax, this would work:
class String
def | x
if empty? then x else self end
end
end
Then you can say word.infinitive | word, which actually scans fairly naturally, if you ask me.
However, I think a better idea would be to modify the infinitive method, or add a version of it that returns the word unchanged.
Edit: Here's a possibly more elegant solution:
[word.infinitive, word].find {|x| not x.empty?}
Do the right thing - fix infinitive so that it returns nils instead of blank strings, or wrap it with your own interface if you really can't touch it.
Or you can monkeypatch a new function to String without having to abuse syntax.
class String
def squash
self.empty? ? nil : self
end
end
Now you can do
puts var.squash or "default text"
I'm not a native english speaker so I don't know if squash is the best word. Is there a word that would better convey the idea of "turn into nil only if empty"?
You could use the ternary operator (boolean ? true-val : false-val) with String#empty?
return word.infinitive.empty? ? word : word.infinitive
if you only want to call infinitive once:
return (inf = word.infinitive).empty? ? word : inf
You may also want to consider adding some memoization to your code.

Resources