Ruby: String Comparison Issues
gets
returns the entire string entered, including the newline, so when they type "M" and press enter the string you get back is "M\n"
. To get rid of the trailing newline, use String#chomp
, i.e replace your first line with answer = gets.chomp
.
String || comparison operator in Ruby
'X' || 'O'
just says X or O. And since any string is truthy it always returns X. So any spot where you’ve said [('X' || 'O')]
, you’ve really just said ['X']
.
Because of this, you’re only ever checking if a whole line of 3 is all X.
I don’t really understand how you’re trying to test this, but I feel like you’d be better off running the function twice first handing in X and then handing in O if it didn’t find X as a winner, as opposed to trying to check both as once.
Alternatively you could instead have the function return 'X', 'O', or nil and then you could have it only run the function once. The string returned would be who won and if it’s nil then no one won. I would also recommend making a loop for this. I find it easier to read.
Here's how I would solve the problem.
ROWS = [
[1,2,3],
[4,5,6],
[7,8,9],
[1,4,7],
[2,5,8],
[3,6,9],
[1,5,9],
[7,5,3],
]
def find_winner(board)
ROWS.each do |row|
# subtract 1 because the ROWS is 1-indexed (like a phone dial) but arrays are 0-indexed
row_values = row.map { |v| board[v - 1] }
return('X') if row_values.all?('X')
return('O') if row_values.all?('O')
end
return(nil)
end
test1 = [
'X', 'X', 'X',
'O', 'X', 'O',
'O', 'O', '',
]
puts "Winner of test1: #{find_winner(test1).inspect}"
"X"
test2 = [
'X', '', 'X',
'X', 'O', 'O',
'X', 'O', 'X',
]
puts "Winner of test2: #{find_winner(test2).inspect}"
"X"
test3 = [
'O', 'X', 'X',
'O', 'X', 'O',
'O', 'O', '',
]
puts "Winner of test3: #{find_winner(test3).inspect}"
"O"
test4 = [
'O', 'X', 'O',
'X', 'O', 'X',
'O', 'O', 'X',
]
puts "Winner of test4: #{find_winner(test4).inspect}"
"O"
test5 = [
'O', 'X', 'O',
'O', 'X', 'O',
'X', 'O', 'X',
]
puts "Winner of test5: #{find_winner(test5).inspect}"
nil
Ruby, problems comparing strings with UTF-8 characters
This is an issue with Unicode equivalence.
The a
version of your string consists of the character ư
(U+01B0: LATIN SMALL LETTER U WITH HORN), followed by U+0303 COMBINING TILDE. This second character, as the name suggests is a combining character, which when rendered is combined with the previous character to produce the final glyph.
The b
version of the string uses the character ữ
(U+1EEF, LATIN SMALL LETTER U WITH HORN AND TILDE) which is a single character, and is equivalent to the previous combination, but uses a different byte sequence to represent it.
In order to compare these strings you need to normalize them, so that they both use the same byte sequences for these types of characters. Current versions of Ruby have this built in (in earlier versions you needed to use a third party library).
So currently you have
a == b
which is false
, but if you do
a.unicode_normalize == b.unicode_normalize
you should get true
.
If you are on an older version of Ruby, there are a couple of options. Rails has a normalize
method as part of its multibyte support, so if you are using Rails you can do:
a.mb_chars.normalize == b.mb_chars.normalize
or perhaps something like:
ActiveSupport::Multibyte::Unicode.normalize(a) == ActiveSupport::Multibyte::Unicode.normalize(b)
If you’re not using Rails, then you could look at the unicode_utils gem, and do something like this:
UnicodeUtils.nfkc(a) == UnicodeUtils.nfkc(b)
(nfkc
refers to the normalisation form, it is the same as the default in the other techniques.)
There are various different ways to normalise unicode strings (i.e. whether you use the decomposed or combined versions), and this example just uses the default. I’ll leave researching the differences to you.
Ruby/Rails string case comparison issue's within postgres
Try
Food.where("lower(name) = ?", row['name'].downcase)
ruby string comparisons .match vs .eql?
As always, don't just use methods without reading their documentation. There can be important notes.
Here's eql?
:
Two strings are equal if they have the same length and content.
Here's match
:
Converts pattern to a Regexp (if it isn’t already one), then invokes its match method on str. If the second parameter is present, it specifies the position in the string to begin the search.
Note the part about converting. In a regular expression (
and )
, among other characters, have significant meaning. You can't use match
arbitrarily here. It has a very specific function.
You rarely see .eql?
used in actual Ruby code, the convention is simply this:
text_from_page == error_text
The eql?
method is primarily intended for internal use. It comes into play when doing comparisons, and when finding things in a container like an Array or Hash.
How do I do String comparison in Ruby?
The string returned by gets will have a linebreak at the end. Use String#chomp
to remove it (i.e. state_abbreviation = gets.chomp
).
PS: Your code would look much cleaner (IMHO) if you used case-when instead of if-elsif-elsif.
Is == in Ruby always value equality?
In Ruby, ==
can be overloaded, so it could do anything the designer of the class you're comparing wants it to do. In that respect, it's very similar to Java's equals()
method.
The convention is for ==
to do value comparison, and most classes follow that convention, String
included. So you're right, using ==
for comparing strings will do the expected thing.
The convention is for equal?
to do reference comparison, so your test a.object_id == b.object_id
could also be written a.equal?(b)
. (The equal?
method could be defined to do something nonstandard, but then again, so can object_id
!)
(Side note: when you find yourself comparing strings in Ruby, you often should have been using symbols instead.)
String comparison in Ruby
As I understand, you have two strings, s1
and s2
, from which you obtain two strings:
ss1 = s1[0,n]
ss2 = s2[0,n]
where
n = [s1.size, s2.size].min
and you want to know if the characters of ss2
can be rearranged to equal ss1
. If my understanding is correct, that would be true if and only if the following is true:
ss1.chars.sort == ss2.chars.sort
Example:
s1 = "ebcda"
s2 = "adcbefr"
n = [s1.size, s2.size].min #=> 5
ss1 = s1[0,n] #=> "ebcda"
ss2 = s2[0,n] #=> "adcbe"
ss1.chars.sort == ss2.chars.sort #=> true
Why does comparing strings in Ruby always return false?
gets
will return the entered string plus a newline charcter, so you'll need to remove it. As it is a string you don't need to run to_str on the result either.
torf = gets.downcase.chomp.eql? qs[n].answer.downcase.to_s
Related Topics
Difference Between Rake Db:Migrate Db:Reset and Db:Schema:Load
What Is the Colon Operator in Ruby
Disable Activerecord For Rails 4
Rails: Access to Current_User from Within a Model in Ruby on Rails
What's the Best Way to Model Recurring Events in a Calendar Application
Ruby/Ruby on Rails Memory Leak Detection
Rails 3, Has_One/Has_Many With Lambda Condition
Rails Activerecord: Find All Users Except Current User
Why Is Division in Ruby Returning an Integer Instead of Decimal Value
How to Update Ruby Gems from Behind a Proxy (Isa-Ntlm)
Get the Name of the Currently Executing Method
Limitations in Running Ruby/Rails on Windows
Test If String Is a Number in Ruby on Rails