cannot puts the variable I just assigned on the same line - ruby

I cannot puts the variable on the same line but could on different lines
my input
word = 'e2ed2d' puts word
my output
bundle exec ruby main.rb
main.rb:21: syntax error, unexpected tIDENTIFIER, expecting end-of-input
word = 'e2ed2d' puts word
^~~~
exit status 1

In Ruby, parentheses are optional in argument lists for message sends, as is the receiver (implicitly defaulting to self). Therefore,
foo bar baz
is equivalent to
foo(bar(baz))
which is equivalent to
self.foo(self.bar(self.baz))
# or, depending on whether `baz` is a local variable or a message
self.foo(self.bar(baz))
More generally, whenever you see two tokens next to each other, the only valid interpretation is that the first token is a message and the second token is an argument. (The only exception being operator messages, e.g. a + b.)
However, there is no meaningful way of interpreting your code as a message send:
word = 'e2ed2d' puts word
What would that be equivalent to?
word = self.'e2ed2d'(self.puts(word))
or
word = 'e2ed2d'(puts(word))
That makes no sense: String literals don't take any arguments (only message sends and block invocations do), and a String literal is also not a valid message identifier.
What you actually want are two separate expressions, so you need to separate those two separate expressions with an expression separator. Ruby has two general expression separators: you can either use a semicolon ; or a newline, so either
word = 'e2ed2d'
puts word
or
word = 'e2ed2d'; puts word
would be okay.
In some specific contexts, there are also context-specific additional expression separators. For example, in a conditional expression, you can separate the condition from the consequence using the keyword then as an additional context-specific separator:
if 2 < 3 then '2 is less than 3' else '2 is greater than or equal to 3' end
if 2 < 3; '2 is less than 3' else '2 is greater than or equal to 3' end
if 2 < 3
'2 is less than 3' else '2 is greater than or equal to 3' end

Use ;:
word = 'e2ed2d'; puts word

Related

So I want the answer for the user just to include numbers from 0 to 9.. How do I do this?

So as I ask for in the title. How do I make a loop that breaks when the user has entered some values that contain only number, and if not it will say try again.
prompt = "> "
puts "What is the salary for the accountant: "
print prompt
while accountant = gets.chomp
if accountant == (0..9)
puts "Nice"
break
else
"try again"
print prompt
end
end
end
A simple solution with no regex would be:
accountant.chars.all?{|n| ("0".."9") === n}
You may want to read about the "===" operator in Ruby if you don't how it works yet as it may be confusing if you come from PHP or Javascript.
What does the "===" operator do in Ruby?
Your problem is in this line:
if accountant == (0..9)
This is checking whether the value is equal to a range - which is not what you wanted.
Since the input from gets.chomp will always be a string, you need to check whether it only contains the characters: "0", "1", "2", ... and "9".
One way to do this is with a regular expression:
if accountant =~ /\A\d+\z/
\A means "start of string"
\z means "end of string"
\d+ means "one or more digit" (0-9)
Note that the solution you suggested in the comments, /^-?[0-9]+$/, is flawed since:
^ means "start of line" (so it would be possible to insert arbitrary other characters before a newline)
$ means "end of line" (so it would be possible to insert arbitrary other characters after a newline)
-? also allows an optional hyphen character. Which is presumably not what you want in this context, since the input is a salary - which surely cannot be negative!

What's different about this ruby regex?

I was trying to substitute either a comma or a percent sign, and it continually failed, so I opened up IRB and tried some things out. Can anyone explain to me why the first regex (IRB line 13) doesn't work but the flipped version does (IRB line 15)? I've looked it up and down and I don't see any typos, so it must be something to do with the rule but I can't see what.
b.gsub(/[%]*|[,]*/,"")
# => "245,324"
b.gsub(/[,]*/,"")
# => "245324"
b.gsub(/[,]*|[%]*/,"")
# => "245324"
b
# => "245,324"
Because ruby happily finds [%]* zero times throughout your string and does the substitution. Check out this result:
b = '232,000'
puts b.gsub(/[%]*/,"-")
--output:--
-2-3-2-,-0-0-0-
If you put all the characters that you want to erase into the same character class, then you will get the result you want:
b = "%245,324,000%"
puts b.gsub(/[%,]*/, '')
--output:--
245324000
Even then, there are a lot of needless substitutions going on:
b = "%245,324,000%"
puts b.gsub(/[%,]*/, '-')
--output:--
--2-4-5--3-2-4--0-0-0--
It's the zero or more that gets you into trouble because ruby can find lots of places where there are 0 percent signs or 0 commas. You actually don't want to do substitutions where ruby finds zero of your characters, instead you want to do substitutions where at least one of your characters occurs:
b = '%232,000,000%'
puts b.gsub(/%+|,+/,"")
--output:--
232000000
Or, equivalently:
puts b.gsub(/[%,]+/, '')
Also, note that regexes are like double quoted strings, so you can interpolate into them--it's as if the delimiters // are double quotes:
one_or_more_percents = '%+'
one_or_more_commas = ',+'
b = '%232,000,000%'
puts b.gsub(/#{one_or_more_percents}|#{one_or_more_commas}/,"")
--output:--
232000000
But when your regexes consist of single characters, just use a character class: [%,]+

Use regular expression to fetch 3 groups from string

This is my expected result.
Input a string and get three returned string.
I have no idea how to finish it with Regex in Ruby.
this is my roughly idea.
match(/(.*?)(_)(.*?)(\d+)/)
Input and expected output
# "R224_OO2003" => R224, OO, 2003
# "R2241_OOP2003" => R2244, OOP, 2003
If the example description I gave in my comment on the question is correct, you need a very straightforward regex:
r = /(.+)_(.+)(\d{4})/
Then:
"R224_OO2003".scan(r).flatten #=> ["R224", "OO", "2003"]
"R2241_OOP2003".scan(r).flatten #=> ["R2241", "OOP", "2003"]
Assuming that your three parts consist of (R and one or more digits), then an underbar, then (one or more non-whitespace characters), before finally (a 4-digit numeric date), then your regex could be something like this:
^(R\d+)_(\S+)(\d{4})$
The ^ indicates start of string, and the $ indicates end of string. \d+ indicates one or more digits, while \S+ says one or more non-whitespace characters. The \d{4} says exactly four digits.
To recover data from the matches, you could either use the pre-defined globals that line up with your groups, or you could could use named captures.
To use the match globals just use $1, $2, and $3. In general, you can figure out the number to use by counting the left parentheses of the specific group.
To use the named captures, include ? right after the left paren of a particular group. For example:
x = "R2241_OOP2003"
match_data = /^(?<first>R\d+)_(?<second>\S+)(?<third>\d{4})$/.match(x)
puts match_data['first'], match_data['second'], match_data['third']
yields
R2241
OOP
2003
as expected.
As long as your pattern covers all possibilities, then you just need to use the match object to return the 3 strings:
my_match = "R224_OO2003".match(/(.*?)(_)(.*?)(\d+)/)
#=> #<MatchData "R224_OO2003" 1:"R224" 2:"_" 3:"OO" 4:"2003">
puts my_match[0] #=> "R224_OO2003"
puts my_match[1] #=> "R224"
puts my_match[2] #=> "_"
puts my_match[3] #=> "00"
puts my_match[4] #=> "2003"
A MatchData object contains an array of each match group starting at index [1]. As you can see, index [0] returns the entire string. If you don't want the capture the "_" you can leave it's parentheses out.
Also, I'm not sure you are getting what you want with the part:
(.*?)
this basically says one or more of any single character followed by zero or one of any single character.

Ruby backslash to continue string on a new line?

I'm reviewing a line of Ruby code in a pull request. I'm not sure if this is a bug or a feature that I haven't seen before:
puts "A string of Ruby that"\
"continues on the next line"
Is the backslash a valid character to concatenate these strings? Or is this a bug?
That is valid code.
The backslash is a line continuation. Your code has two quoted runs of text; the runs appear like two strings, but are really just one string because Ruby concatenates whitespace-separated runs.
Example of three quoted runs of text that are really just one string:
"a" "b" "c"
=> "abc"
Example of three quoted runs of text that are really just one string, using \ line continuations:
"a" \
"b" \
"c"
=> "abc"
Example of three strings, using + line continuations and also concatenations:
"a" +
"b" +
"c"
=> "abc"
Other line continuation details: "Ruby interprets semicolons and newline characters as the ending of a statement. However, if Ruby encounters operators, such as +, -, or backslash at the end of a line, they indicate the continuation of a statement." - Ruby Quick Guide
The backslash character does not concatenate any strings. It prevents the line-break from meaning that those two lines are different statements. Think of the backslash as the opposite of the semicolon. The semicolon lets two statements occupy one line; the backslash lets one statement occupy two lines.
What you are not realizing is that a string literal can be written as multiple successive literals. This is legal Ruby:
s = "A string of Ruby that" "continues on the same line"
puts s
Since that is legal, it is legal to put a line break between the two string literals - but then you need the backslash, the line-continuation character, to tell Ruby that these are in fact the same statement, spread over two lines.
s = "A string of Ruby that" \
"continues on the same line"
puts s
If you omit the backslash, it is still legal, but doesn't give the result you might be hoping for; the string literal on the second line is simply thrown away.
This is not a case of concatenated strings. It is one single string. "foo" "bar" is a syntactic construct that allows you to break up a string in your code, but it is identical to "foobar". In contrast, "foo" + "bar" is the true concatenation, invoking the concatenation method + on object "foo".
You can verify this by dumping the YARV instructions. Compare:
RubyVM::InstructionSequence.compile('"foo" + "bar"').to_a
// .... [:putstring, "foo"], [:putstring, "bar"] ....
RubyVM::InstructionSequence.compile('"foo" "bar"').to_a
// .... [:putstring, "foobar"] ....
The backslash in front of the newline will cancel the newline, so it does not terminate the statement; without it, it would not be one string, but two strings in separate lines.

Ruby extract data from string using regex

I'm doing some web scraping, this is the format for the data
Sr.No. Course_Code Course_Name Credit Grade Attendance_Grade
The actual string that i receive is of the following form
1 CA727 PRINCIPLES OF COMPILER DESIGN 3 A M
The things that I am interested in are the Course_Code, Course_Name and the Grade, in this example the values would be
Course_Code : CA727
Course_Name : PRINCIPLES OF COMPILER DESIGN
Grade : A
Is there some way for me to use a regular expression or some other technique to easily extract this information instead of manually parsing through the string.
I'm using jruby in 1.9 mode.
Let's use Ruby's named captures and a self-describing regex!
course_line = /
^ # Starting at the front of the string
(?<SrNo>\d+) # Capture one or more digits; call the result "SrNo"
\s+ # Eat some whitespace
(?<Code>\S+) # Capture all the non-whitespace you can; call it "Code"
\s+ # Eat some whitespace
(?<Name>.+\S) # Capture as much as you can
# (while letting the rest of the regex still work)
# Make sure you end with a non-whitespace character.
# Call this "Name"
\s+ # Eat some whitespace
(?<Credit>\S+) # Capture all the non-whitespace you can; call it "Credit"
\s+ # Eat some whitespace
(?<Grade>\S+) # Capture all the non-whitespace you can; call it "Grade"
\s+ # Eat some whitespace
(?<Attendance>\S+) # Capture all the non-whitespace; call it "Attendance"
$ # Make sure that we're at the end of the line now
/x
str = "1 CA727 PRINCIPLES OF COMPILER DESIGN 3 A M"
parts = str.match(course_line)
puts "
Course Code: #{parts['Code']}
Course Name: #{parts['Name']}
Grade: #{parts['Grade']}".strip
#=> Course Code: CA727
#=> Course Name: PRINCIPLES OF COMPILER DESIGN
#=> Grade: A
Just for fun:
str = "1 CA727 PRINCIPLES OF COMPILER DESIGN 3 A M"
tok = str.split /\s+/
data = {'Sr.No.' => tok.shift, 'Course_Code' => tok.shift, 'Attendance_Grade' => tok.pop,'Grade' => tok.pop, 'Credit' => tok.pop, 'Course_Name' => tok.join(' ')}
Do I see that correctly that the delimiter is always 3 spaces? Then just:
serial_number, course_code, course_name, credit, grade, attendance_grade =
the_string.split(' ')
Assuming everything except for the course description consists of single words and there are no leading or trailing spaces:
/^(\w+)\s+(\w+)\s+([\w\s]+)\s+(\w+)\s+(\w+)\s+(\w+)$/
Your example string will yield the following match groups:
1. 1
2. CA727
3. PRINCIPLES OF COMPILER DESIGN
4. 3
5. A
6. M
This answer isn't very idiomatic Ruby, because in this case I think clarity is better than being clever. All you really need to do to solve the problem you described is to split your lines with whitespace:
line = '1 CA727 PRINCIPLES OF COMPILER DESIGN 3 A M'
array = line.split /\t|\s{2,}/
puts array[1], array[2], array[4]
This assumes your data is regular. If not, you will need to work harder at tuning your regular expression and possibly handling edge cases where you don't have the required number of fields.
A Note for Posterity
The OP changed the input string, and modified the delimiter to a single space between fields. I'll leave my answer to the original question as-is (including the original input string for reference) as it may help others besides the OP in a less-specific case.

Resources