I am testing two strings to see if they are equal.
One string is just a simple string: "\17"
The other is parsed to: "\17"
num = 7
num2 = "\17"
parsed_num = "\1#{num}"
puts parsed_num.class
puts num2.class
if parsed_num == num2
puts 'Equal'
else
puts 'Not equal'
end
It returns:
String
String
Not equal
My goal is to have parsed_num exactly the same as the literal num2
I am going to take the opposite answer and assume that "\17" is correct, then consider this code:
num = 7
num2 = "\17"
puts "ni #{num2.inspect}"
# extra \ to fix error, for demo
parsed_num = "\\1#{num}"
puts "pi #{parsed_num.inspect}"
# for note, but ICK!!!
p2 = eval('"' + parsed_num + '"')
puts "p2i #{p2.inspect}"
puts "p2= #{p2 == num2}"
dec = (10 + num).to_s.oct
p3 = dec.chr
puts "p3i #{p3.inspect}"
puts "p3= #{p3 == num2}"
Result:
ni "\017"
pi "\\17"
p2i "\017"
p2= true
p3i "\017"
p3= true
The reason why "\1#{num}" didn't work is that string literals -- and the embedded escape sequences -- are handled during parsing while the string interpolation itself (#{}) happens later, at run-time. (This is required, because who knows what may happen to be in num?)
In the case of p2 I used eval, which parses and then executes the supplied code. The code there is equivalent to eval('"\17"'), because parsed_num contained the 3-letter string: \17. (Please note, this approach is generally considered bad!)
In the case of p3 I manually did what the parser does for string interpolation of \octal: took the value of octal, in, well, octal, and then converted it into the "character" with the corresponding value.
Happy coding.
If you're using "\17" backslash escape, it will be interpreted as as "\0017", where 17 would be an octal digit equals to 'F' hex:
"\17" # => "\u000F"
because your string uses double quotes.
You can achieve what you want with help of this snippet, for example:
num = 7
num2 = "\\17"
parsed_num = "\\1#{num}"
if parsed_num == num2
puts 'Equal'
else
puts 'Not equal'
end
# => Equal
As you can see you get this result with help of the backslash to escape another backslash :)
Use single quotes so that the strings involved are the literal things you are setting:
num = 7
num2 = '\17'
parsed_num = '\1' + String(num)
if parsed_num == num2
puts 'Equal'
else
puts 'Not equal'
end
This produces 'Equal' - the desired result. Here's a link with more info on the differences between single quoted strings and double quoted strings if desired.
Related
I got this assignment in Codecademy. I want to print the even numbers.
print "Print any number:"
inpt = gets.chomp
def odd_or_even(num)
if num % 2 == 0
print "even"
else
print "odd"
end
end
I do not get any output. Is the problem in the method, or how I've written the equation? I've tried changing both.
You defined the method odd_or_even but never actually call it.
You have two options:
Take the more script-like approach and work with the input without the use of methods:
print 'Print any number: '
input = gets.to_i
# ^ convert the input (which is always a string) to an integer
if input % 2 == 0
puts 'even'
# ^ is the same as `print` but adds a newline character at the end
# (unless the string ends with a newline character)
else
puts 'odd'
end
If you want to use a method you'll have to define it and call it as well:
def odd_or_even(num)
if num % 2 == 0
puts 'even'
else
puts 'odd'
end
end
print 'Print any number: '
input = gets.to_i
odd_or_even(input)
# ^ method is called here
Ruby also has a lot of build-in helpers. You can achieve the same result with the following two lines:
print 'Print any number: '
puts gets.to_i.odd? ? 'odd' : 'even'
references:
#gets get user input
String#to_i convert input to an integer
Integer#odd? check if the integer is odd
Ternary if: use inline of if expression ? true : false
I think you have to check your input data.
Otherwise it may be a situation:
'abc'.to_i.even? #=> true
It's because non-digital String#to_i returns 0.
As you see it's not good.
def odd_or_even(number)
number.odd? ? 'odd' : 'even'
end
puts 'Print any number:'
input = gets.chomp
if input =~ /\D/
puts 'It is not a number'
else
puts "It's #{odd_or_even(input.to_i)}"
end
Firstly we validate data using regex. If it's not a number we will not check is it odd or even.
Note:
Very often we use =~ operator to match String and Regexp.
/\D/ means any non-digit character.
i = 20
loop do
i -= 1
next if i % 2 == 1
print "#{i}"
break if i <= 0
end
I see two issues with what you've posted - first gets.chomp is going to return a string and you really want an integer, so you'd want to do gets.to_i (or Integer(gets) if you want to guard against non-numeric inputs). The second is that print doesn't include a line break, so that could be the source of your "no output" issue - maybe try switching to puts instead?
I am trying to loop until user inputs an integer. When user inputs a letter, the following code should print "Think of a number":
print "Think of a number "
while user_input = gets.to_i
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I succeeded with my code when user inputs an integer. However when user inputs a string, the to_i method returns 0, and does not execute the else statement because it is a number.
The main issue with your code is String#to_i method is omnivorous.
"0".to_i #⇒ 0
"0.1".to_i #⇒ 0
"foo".to_i #⇒ 0
That said, user_input in your code is always integer.
What you probably want is to accept digits only (and maybe a leading minus for negatives.) The only concise way to accept a subset of characters is a regular expression.
# chomp to strip out trailing carriage return
user_input = gets.chomp
if user_input =~ /\A-?\d+\z/
...
The regular expression above means nothing save for digits with optional leading minus.
Or, even better (credits to #Stefan)
if gets =~ /\A-?\d+\Z/
If you only want to accept postive digits, you can use a range:
user_input = gets.chomp
if ('0'..'9').cover? user_input
let check below one used Integer(gets.chomp) rescue ''
print "Think of a number "
while user_input = Integer(gets.chomp) rescue ''
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I came across a similar problem. I ended up doing this:
if user_input.strip == user_input.to_i.to_s
# More code here!
end
Testing for float would be:
if user_input.strip == user_input.to_f.to_s
# More code here!
end
Solved my issue. See if it helps.
I have a coding problem I solved and want to refactor. I know there has to be a cleaner way of doing what I did.
The goal is to write a method that takes a string of "!" and "?" and reduces the string by eliminating all odd groupings of each symbol.
Example - a string "????!!!" would have an odd grouping of "!!!" because there are three in a row. These would be deleted from the string.
If there is only one "!" or "?" its left because it is not in a group.
Ex -
remove("!????!!!?") answer == "!"
# => ("!????!!!?" --> "!?????" --> "!")
In the first string, the only odd grouping is "!!!", once removed, it leaves a new string with an odd grouping "?????". You remove the next odd grouping so you're left with "!". This fits the desired output.
Another example
remove("!???!!") == ""
# => ("!???!!" --> "!!!" --> "")
Current code:
def remove(s)
arr = [s]
i = 0
until i == arr[0].length
s = s.chars.chunk{|c|c}.map{ |n,a| a.join }.select{|x| x if x.length.even? || x.length <= 1}.join
arr << s
i += 1
end
return arr[-1]
end
My code solves this problem and all test cases. I have a suspicion that my until loop can be removed/refactored so that I could solve this problem in one line and have spent hours trying to figure it out with no luck.
Suppose
str = "???!!!???!"
If we first remove the two groups "???" we are left with "!!!!", which cannot be reduced further.
If we first remove the group "!!!" we are left with "??????!", which cannot be reduced further.
If we are permitted to remove all odd groups of either character without reference to the effect that either has on the other, we obtain !, which cannot be reduced further.
It's not clear what rule is to be used. Here are three possibilities and code to implement each.
I will use the following two regular expressions, and in the first two cases a helper method.
Rq = /
(?<!\?) # do not match a question mark, negative lookbehind
\? # match a question mark
(\?{2})+ # match two question marks one or more times
(?!\?) # do not match a question mark, negative lookahead
/x # free-spacing regex definition mode
which is commonly written /(?<!\?)\?(\?{2})+(?!\?)/.
Similarly,
Rx = /(?<!!)!(!{2})+(?!!)/
def sequential(str, first_regex, second_regex)
s = str.dup
loop do
size = s.size
s = s.gsub(first_regex,'').gsub(second_regex,'')
return s if s.size == size
end
end
I apply each of the three methods below to two example strings:
str1 = "???!!!???!"
str2 = 50.times.map { ['?', '!'].sample }.join
#=> "?!!!?!!!?!??????!!!?!!??!!???!?!????!?!!!?!?!???!?"
Replace all odd groups of "?" then odd groups of "!" then repeat until no further removals are possible
def question_before_exclamation(str)
sequential(str, Rq, Rx)
end
question_before_exclamation str1 #=> "!!!!"
question_before_exclamation str2 #=> "??!??!?!!?!?!!?"
Replace all odd groups of "!" then odd groups of "?" then repeat until no further removals are possible
def exclamation_before_question(str)
sequential(str, Rx, Rq)
end
exclamation_before_question str1 #=> "??????!"
exclamation_before_question str2 #=> "??!????!!?!?!!?!?!!?"
Replace all odd groups of both "?" and "!" then repeat until no further removals are possible
Rqx = /#{Rq}|#{Rx}/
#=> /(?-mix:(?<!\?)\?(\?{2})+(?!\?))|(?-mix:(?<!!)!(!{2})+(?!!))/
def question_and_explanation(str)
s = str.dup
loop do
size = s.size
s = s.gsub(Rqx,'')
return s if s.size == size
end
end
question_and_explanation str1 #=> "!"
question_and_explanation str2 #=> "??!?!!?!?!!?!?!!?"
I don't know the exact Ruby syntax for this, but you could simplify your solution by using regular expressions:
Gather all matches of consecutive characters
if all matches are of even length or 1 exit
Test if matches are an odd length
if an odd length, replace with the empty string
else do nothing
Goto step 1
A solution in Perl would be:
#!perl
use strict;
use warnings;
use feature qw(say);
my $string = '!????!!!?';
sub reduce {
my ($s) = #_;
while ( my #matches = $s =~ m/((.)\2+)/g ) {
last if ! grep { length($_) > 1 && length($_) % 2 == 1 } #matches;
foreach my $match ( #matches ) {
$s =~ s/\Q$match// if length($match) > 1 && length($match) % 2 == 1;
}
}
return $s;
}
say reduce($string);
I could be wrong (this is ruby, after all) but I don't think you'll find a one-liner for this because ruby's utility functions generally aren't recursive. But you can use regex to simplify your logic, at the very least:
def remove(s)
while s =~ /(?<!\!)\!([\!]{2})+(?!\!)/ || s =~ /(?<!\?)\?([\?]{2})+(?!\?)/
s.gsub! /(?<!\!)\!([\!]{2})+(?!\!)/, "" # remove odd !
s.gsub! /(?<!\?)\?([\?]{2})+(?!\?)/, "" # remove odd ?
end
return s
end
To make the regex less mind-boggling, it helps to look at them with 'a' instead of '?' and '!':
/(?<!a)a([a]{2})+(?!a)/ #regex for 'a'
(?<!a) #negative lookbehind: the match cannot start with an 'a'
a([a]{2})+ #the match should be an 'a' followed by 1 or more pairs
(?!a) #negative lookahead: the match cannot end with an 'a'
It should be simple enough with a regular expression replacement
def remove(string)
begin
original = string
string.gsub!(/(\!{3,})|(\?{3,})/) { |s| s.length.even? ? s : '' }
end until original == string
string
end
puts remove("!????!!!?").inspect # answer == "!"
puts remove("!???!!").inspect # answer == ""
puts remove("!????!!").inspect # answer == "!????!!"
I need to convert all the even indexed characters in a string to become uppercase, while the odd indexed characters stay lowercase. I've tried this, but it keeps failing and I'm not sure why. I'd appreciate some help!
for i in 0..string.length
if (i % 2) == 0
string[i].upcase
else
string[i].downcase
end
end
"foobar".gsub(/(.)(.?)/){$1.upcase + $2.downcase} # => "FoObAr"
"fooba".gsub(/(.)(.?)/){$1.upcase + $2.downcase} # => "FoObA"
There you go:
string = "asfewfgv"
(0...string.size).each do |i|
string[i] = i.even? ? string[i].upcase : string[i].downcase
end
string # => "AsFeWfGv"
We people don't use for loop usually, that's why I gave the above code. But here is correct version of yours :
string = "asfewfgv"
for i in 0...string.length # here ... instead of ..
string[i] = if (i % 2) == 0
string[i].upcase
else
string[i].downcase
end
end
string # => "AsFeWfGv"
You were doing it correctly, you just forgot to reassign it the string index after upcasing or downcasing.
You have two problems with your code:
for i in 0..string.length should be for i in 0...string.length to make the last character evaluated string[string.length-1], rather than going past the end of the string (string[string.length]); and
string[i] must be an L-value; that is, you must have, for example, string[i] = string[i].upcase.
You can correct your code and make it more idiomatic as follows:
string = "The cat in the hat"
string.length.times do |i|
string[i] = i.even? ? string[i].upcase : string[i].downcase
end
string
#=> "ThE CaT In tHe hAt"
I would like to capitalize each word of a UTF-8 string. However, I need the function to ignore some special characters in the beginning of words, like "(-.,". The function will be used to capitalize song titles which can look like this:
marko, gabriel boni, simple jack - recall (original mix)
...would output:
Marko, Gabriel Boni, Simple Jack - Recall (Original Mix)
It should also be able to capitalize UTF-8 chars like "å" > "Å". "é" > "É".
Is there something why Unicode::capitalize method from unicode library does not suit your needs ?
irb(main):013:0> require 'unicode'
=> true
irb(main):014:0> begin Unicode::capitalize 'åäöéèí' rescue $stderr.print "unicode error\n" end
=> "Åäöéèí"
irb(main):015:0> begin Unicode::capitalize '-åäöéèí' rescue $stderr.print "unicode error\n" end
=> "-åäöéèí"
"åbc".mb_chars.capitalize
#=> "Åbc"
"ébc".mb_chars.capitalize.to_s
#=> "Ébc"
UPD
And to ignore none word chars:
string = "-åbc"
str = string.match(/^(\W*)(.*)/)
str[1] + str[2].mb_chars.capitalize.to_s
#=> "-Åbc"
I did this and wanted to filter a lot of things.
I created a constants file initializers/constants.rb
letters = ("a".."z").collect
numbers = ("1".."9").collect
symbols = %w[! # # $ % ^ & * ( ) _ - + = | \] { } : ; ' " ? / > . < , ]
FILTER = letters + numbers + symbols
And then just did a check to see if it was in my filter:
if !FILTER.include?(c)
#no
else
#yes
end
You can also check the value of the unicode but you need to know the range or specific values. I did this with chinese characters, so that is where I got my values. I will post some code just to give you an idea:
def check(char)
char = char.unpack('U*').first
if char >= 0x4E00 && char <= 0x9FFF
return true
end
if char >= 0x3400 && char <= 0x4DBF
return true
end
if char >= 0x20000 && char <= 0x2A6DF
return true
end
if char >= 0x2A700 && char <= 0x2B73F
return true
end
return false
end
You need to know the specific values here of course.