# #!/usr/local/bin/ruby
puts "why doesn't this work??"
pi = ''
special = "[;\`'<>-]"
regex = /[#{special.gsub(/./){|char| "\\#{char}"}}]/
pi = ARGV[0].to_s #takes in console argument to test
if pi == '3.1415926535897932385'
puts "got it"
end
if pi =~ regex
puts "stop word"
else
puts "incorrect"
end
All I'm trying to do is test whether or not the pi variable contains any of the stop characters, if true, print "stop word" otherwise got it or incorrect respectively. I've tried doing this about ten ways. with scans, include? lines and I feel like this is the best route.
I think you may be over-thinking this. Here are a couple of ways (among many), where true means that the string contains at least one of the special characters):
#1
baddies = "[;`'<>-]"
pi = '3.14'
pi.delete(baddies).size < pi.size #=> false
pi = '3.1;4'
pi.delete(baddies).size < pi.size #=> true
#2
special = %w| [ ; ` ' < > - ] |
# => ["[", ";", "`", "'", "<", ">", "-", "]"]
pi = '3.14'
(pi.chars & special).any? #=> false
pi = '3.1cat4'
(pi.chars & special).any? #=> false
pi = '3.1;4'
(pi.chars & special).any? #=> true
You don't need to escape any of the characters in your character class:
special = "[;\`'<>-]"
regex = /#{special}/
p regex
#pi = ARGV[0] #takes in console argument to test
pi = 'hello;world'
if pi == '3.1415926535897932385'
puts "got it"
end
if pi =~ regex
puts "stop word"
else
puts "incorrect"
end
--output:--
/[;`'<>-]/
stop word
And ARGV[0] is a string already. But, a shell/console also recognizes special characters when you enter them on the command line:
special = "[;\`'<>-]"
#regex = /[#{special.gsub(/./){|char| "\\#{char}"}}]/
regex = /#{special}/
p regex
pi = ARGV[0] #takes in console argument to test
if pi == '3.1415926535897932385'
puts "got it"
end
if pi =~ regex
puts "stop word"
else
puts "incorrect"
end
--output:--
~/ruby_programs$ ruby 1.rb ;
/[;`'<>-]/
incorrect
~/ruby_programs$ ruby 1.rb <
-bash: syntax error near unexpected token `newline'
If you want the shell/console to treat the special characters that it recognizes--as literals, then you have to quote them. There are various ways to quote things in a shell/console:
~/ruby_programs$ ruby 1.rb \;
/[;`'<>-]/
stop word
~/ruby_programs$ ruby 1.rb \<
/[;`'<>-]/
stop word
Note you can use String#[] too:
special = "[;\`'<>-]"
regex = /#{special}/
...
...
if pi[regex]
puts "stop word"
else
puts "incorrect"
end
Related
I have started learning Ruby today and so far I am loving the easy to read syntax! However, I have made a calculator app to learn the language and am struggling to get it to work. Below is the code for the app.
def add(first_number, second_number)
first_number + second_number
end
def subtract(first_number, second_number)
first_number - second_number
end
def multiply(first_number, second_number)
first_number * second_number
end
def divide(first_number, second_number)
first_number / second_number
end
def mod(first_number, second_number)
first_number % second_number
end
def main()
puts "First number: "
first_number = gets
puts "Operator (+, -, *, /, %): "
operator = gets
puts "Second number: "
second_number = gets
if operator == "+"
result = add(first_number, second_number)
elsif operator == "-"
result = subtract(first_number, second_number)
elsif operator == "*"
result = multiply(first_number, second_number)
elsif operator == "/"
result = divide(first_number, second_number)
elsif operator == "%"
result = mod(first_number, second_number)
else
result = "Invalid operator. Please try again."
end
puts "Result: " + result
end
main()
It keeps going to the else and printing invalid operator and I am unsure why. Am I making a stupid mistake, or am I going about this program the wrong way? Thank you in advance and sorry for such a simple question, I have only started learning Ruby today :)
The answer is quite simple: gets isn't doing what you think. It's preserving the trailing newline.
irb(main):003:0> gets
hello
=> "hello\n"
You need to get rid of the trailing newline.
irb(main):004:0> gets.chomp
hello
=> "hello"
You can see the impact of this on comparisons:
irb(main):013:0> gets.chomp == "hello"
hello
=> true
irb(main):014:0> gets == "hello"
hello
=> false
If you want to get rid of all leading or trailing whitespace, you may want to use #strip.
irb(main):015:0> gets.strip
+
=> "+"
You'll also need to convert your inputs for operands to numbers.
first_number = gets.to_f
When converting this way, there is no need to chomp off the trailing newline, though you could: gets.chomp.to_f.
This program is way longer and more complex then it needs to be. In Ruby operators are just implemented as methods so you can use Object#send to perform all of these simple mathematical operations:
# This is Ruby - not C/Java/Rust etc - there is no need for a "main" method.
puts "First number: "
first_number = gets.chomp.to_f
# Get the user input in a loop until the user provides a valid operator
operator = loop do
puts "Operator (+, -, *, /, %): "
operator = gets.chomp
if ["+", "-", "*", "/", "%"].include?(operator)
break operator
else
puts "Invalid operator. Please try again."
end
end
puts "Second number: "
second_number = gets.chomp.to_f
puts "Result: " + first_number.send(operator, second_number)
If you want to be able to take more advanced input and map it to methods in this way using a lookup table (a hash) as suggested by Tadman is a good idea.
This is my PigLatin code and it works well but I need make it interactive with ARGV, it should be:
$ ruby pig_latin.rb pig banana trash apple elephant
=> igpay ananabay ashtray appleway elephantway
def pig_latin(input)
first_char = input[0,1]
vowels = "aeiouAEIOU"
if vowels.include?(first_char)
word = input[1..-1] + first_char + "way"
else
word = input[1..-1] + first_char + "ay"
end
end
Add this at the end of the program:
if __FILE__ == $0 # if file is being run as script from command line
puts(ARGV.map { |string| pig_latin(string) }.join(" "))
end
ARGV is an array of strings. You can use map to apply the pig_latin changes, and then print them on the same line, joined by " "
The benefit of using if __FILE__ == $0 is that it doesn't require your program to use ARGV. E.g. you could still use it with require.
Here's a cleaned up version that's more Ruby-like:
def pig_latin(input)
case (first_char = input[0,1])
when /aeiou/i
# Uses a simple regular expression to detect vowels
input[1..-1] + first_char + "way"
else
input[1..-1] + first_char + "ay"
end
end
# Transform the input arguments into their Pig Latin equivalents
# and combine into a single string by joining with spaces.
piglatined = ARGV.map do |arg|
pig_latin(arg)
end.join(' ')
puts piglatined
I try to catch only cases b and d from sample below (ie. END should be the only word on a line (or at least be a word not part of longer word, and END should be at beginning of line (not necessarily ^, could start from column #2, case \i.)
I cannot combine this all togethernin one regex, can I have more then 1 flag in regex? I also need this OR in this regex too.
Thanks all.
M
regexDrop = /String01|String2|\AEND/i #END\n/i
a = "the long END not begin of line"
b = "ENd" # <#><< need this one
c = "END MORE WORDs"
d =" EnD" # <#><< need this one
if a =~ regexDrop then puts "a__Match: " + a else puts 'a_' end
if b =~ regexDrop then puts "b__Match: " + b else puts 'b_' end
if c =~ regexDrop then puts "c__Match: " + c else puts 'c_' end
if d =~ regexDrop then puts "d__Match: " + d else puts 'd_' end
## \w Matches word characters.
## \A Matches beginning of string. (could be not column 1)
Note that \A is an anchor (a kind of a built-in lookehind, or "zero width assertion", that matches the beginning of a whole string. The \w is a shorthand class matching letters, digits and an underscore (word characters).
Judging by your description and sample input and expected output, I think you are just looking for END anywhere in a string as a whole word and case-insensitive.
You can match the instances with
regexDrop = /String01|String2|\bEND\b/i
Here is a demo
Output:
a__Match: the long END not begin of line
b__Match: ENd
c__Match: END MORE WORDs
d__Match: EnD
When looping through lines of text, what is the neatest way (most 'Ruby') to do an if else statement (or similar) to check if the string is a single word or not?
def check_if_single_word(string)
# code here
end
s1 = "two words"
s2 = "hello"
check_if_single_word(s1) -> false
check_if_single_word(s2) -> true
Since you're asking about the 'most Ruby' way, I'd rename the method to single_word?
One way is to check for the presence of a space character.
def single_word?(string)
!string.strip.include? " "
end
But if you want to allow a particular set of characters that meet your definition of word, perhaps including apostrophes and hyphens, use a regex:
def single_word?(string)
string.scan(/[\w'-]+/).length == 1
end
Following your definition of a word given in the comment:
[A] stripped string that doesn't [include] whitespace
the code would be
def check_if_single_word(string)
string.strip == string and string.include?(" ").!
end
check_if_single_word("two words") # => false
check_if_single_word("New York") # => false
check_if_single_word("hello") # => true
check_if_single_word(" hello") # => false
Here some code may help you out :
def check_if_single_word(string)
ar = string.scan(/\w+/)
ar.size == 1 ? "only one word" : "more than one word"
end
s1 = "two words"
s2 = "hello"
check_if_single_word s1 # => "more than one word"
check_if_single_word s2 # => "only one word"
def check_if_single_word(string)
string.scan(/\w+/).size == 1
end
s1 = "two words"
s2 = "hello"
check_if_single_word s1 # => false
check_if_single_word s2 # => true
I would check if a space exists in the string.
def check_if_single_word(string)
return !(string.strip =~ / /)
end
.strip will remove excess white space that may exist at the start and the end of the string.
!(myString =~ / /) means that the string does not match the regular expression of a single space.
Likewise you could also use !string.strip[/ /].
a Ruby Way. Extend the calss String
class String
def one?
!self.strip.include? " "
end
end
Then use "Hello world".one? to Check if string contains one word or more.
So I know in ruby that x.nil? will test if x is null.
What is the simplest way to test if x equals ' ', or ' '(two spaces), or ' '(three spaces), etc?
Basically, I'm wondering what the best way to test if a variable is all whitespace?
If you are using Rails, you can simply use:
x.blank?
This is safe to call when x is nil, and returns true if x is nil or all whitespace.
If you aren't using Rails you can get it from the activesupport gem. Install with gem install activesupport. In your file either require 'active_support/core_ext to get all active support extensions to the base classes, or require 'active_support/core_ext/string' to get just the extensions to the String class. Either way, the blank? method will be available after the require.
"best" depends on the context, but here is a simple way.
some_string.strip.empty?
s =~ /\A\s*\Z/
Regex solution. Here's a short ruby regex tutorial.
If x is all whitespace, then x.strip will be the empty string. So you can do:
if not x.nil? and x.strip.empty? then
puts "It's all whitespace!"
end
Alternatively, using a regular expression, x =~ /\S/ will return false if and only if x is all whitespace characters:
if not (x.nil? or x =~ /\S/) then
puts "It's all whitespace!"
end
a = " "
a.each_byte do |x|
if x == 32
puts "space"
end
end
Based on your comment I think you can extend the String class and define a spaces? method as follows:
$ irb
>> s = " "
=> " "
>> s.spaces?
NoMethodError: undefined method `spaces?' for " ":String
from (irb):2
>> class String
>> def spaces?
>> x = self =~ /^\s+$/
>> x == 0
>> end
>> end
=> nil
>> s.spaces?
=> true
>> s = ""
=> ""
>> s.spaces?
=> false
>>
s.include?(" ")
Examples:
s = "A B C D"
s.include?(" ") #=> true
s = "ABCD"
s.include?(" ") #=> false
Yet another :) string.all? { |c| c == ' ' }