Unexpected keyword_end error, yet syntax seems fine - ruby

This function is supposed to pull names from a Comma Separated Values file, and place them into an array.
def xprt_csv_to_ary(csv_file)
namecatcher_regex = "/^[\.{1}]([A-Z]+)\.{3}/" # Matches up to char before next name
current_word = 0
names_array = []
while current_word < 5000
if current_word == 0
name = csv_file.readline.match(namecatched_regex)
else
name = csv_file.past_match.match(namecatcher_regex)
end
names_array[current_word] = name
current_word ++
end
return names_array
end
I'm getting the following error:
syntax error, unexpected keyword_end
I would be as happy to be referred to an existing question that solves my problem as to have someone answer me directly.

Your error comes from line:
current_word ++
There's no such syntax in Ruby. It should be:
current_word += 1
What's more, you create your regexp incorrectly. It should be:
namecatcher_regex = /^[\.{1}]([A-Z]+)\.{3}/
There may be some other errors that I didn't notice.

On this line:
current_word ++
You are telling Ruby to add something to current_word, but you never tell it what to add, instead there's an end directly on the next line. You are missing the operand to the unary +. It should be something like
current_word + something_else
or
current_word + +something_else
In Ruby, whitespace is allowed around operators, so
a +
b
# equivalent to a + b, which is equivalent to a.+(b)
and even
+
a
# equivalent to +a, which is equivalent to a.+#()
is perfectly fine, so if you combine the two, you get that
a + +
b
# equivalent to a + +b, which is equivalent to a.+(b.+#())
is also perfectly fine, and since whitespace around operands is perfectly fine but optional,
a+b
and
a ++
b
# equivalent to a + +b as above
is also perfectly fine.
That's why you only get the error on the next line with the end, because only there can Ruby tell that you are missing the operand to the unary prefix + operator.

Related

String concatenation with constants in ruby 2.7.2

I'm trying to concatenate a constant into a string but I'm getting syntax error, unexpected unary+, expecting end' (SyntaxError)`
This is an example of what I have to do:
NAME = "Jane"
def a_function
s = 'Hi' + NAME +' !'
puts s
end
I know you can do "Hi #{NAME}!" but in my case the string has to be with single quotes.
How can I achieve this?
You are missing a space between + and ' !'.
This is a special case of confusing Ruby, because a single expression like +x is actually a valid unary expression meaning just x, the same way as +1 means 1.
Because of this it's likely Ruby is interpreting your expression a + b +c, as a + b c, which is invalid, and hence the error.
The fix:
s = 'Hi ' + NAME + ' !'
^------ Note the space here!

Ruby unexpected |, expecting =

I am trying to create a do block with index. But I keep getting: syntax error, unexpected '|'
This is my code:
def same_char_collapse(str)
chars = str.split("")
while chars.each.with_index do | letter, i |
if letter[i] == letter[i + 1]
letter[i] = ""
letter[i +1] = ""
end
break
end
end
The error I am getting:
/tmp/file.rb:5: syntax error, unexpected '|'
...hile chars.each.with_index do | letter, i |
... ^
/tmp/file.rb:5: syntax error, unexpected '|', expecting '='
...ach.with_index do | letter, i |
... ^
What am I doing wrong?
This line doesn't make sense:
while chars.each.with_index do |letter, i|
I think you just meant to use:
chars.each.with_index do |letter, i|
A while loop, in any language, takes the form: while(conditional) ..... You don't have a conditional here, so it's not a valid use case for while.
On the other hand, methods such as each will:
Call the given block once for each element in self, passing that element as a parameter.
Note: You also could have used chars.each_with_index instead of .each.with_index.

How can I logically OR two include? conditions in Ruby?

I am starting learn Ruby, need some help with the include? method.
The below code works just fine:
x = 'ab.c'
if x.include? "."
puts 'hello'
else
puts 'no'
end
But when I code it this way:
x = 'ab.c'
y = 'xyz'
if x.include? "." || y.include? "."
puts 'hello'
else
puts 'no'
end
If gives me error when I run it:
test.rb:3: syntax error, unexpected tSTRING_BEG, expecting keyword_then or ';' o
r '\n'
if x.include? "." || y.include? "."
^
test.rb:5: syntax error, unexpected keyword_else, expecting end-of-input
Is this because the include? method cannot have handle logic operator?
Thanks
The other answer and comment are correct, you just need to include parenthesis around your argument due to Ruby's language parsing rules, e.g.,
if x.include?(".") || y.include?(".")
You could also just structure your conditional like this, which would scale more easily as you add more arrays to search:
if [x, y].any? {|array| array.include? "." }
puts 'hello'
else
puts 'no'
end
See Enumerable#any? for more details.
It's because of Ruby parser, it can't recognize the difference between the passing an arguments and logical operators.
Just modify your code a little bit to distinguish the arguments and operator for Ruby parser.
if x.include?(".") || y.include?(".")
puts 'hello'
else
puts 'no'
end

Remove unmatched parentheses from a string

I want to remove "un-partnered" parentheses from a string.
I.e., all ('s should be removed unless they're followed by a ) somewhere in the string. Likewise, all )'s not preceded by a ( somewhere in the string should be removed.
Ideally the algorithm would take into account nesting as well.
E.g.:
"(a)".remove_unmatched_parents # => "(a)"
"a(".remove_unmatched_parents # => "a"
")a(".remove_unmatched_parents # => "a"
Instead of a regex, consider a push-down automata, perhaps. (I'm not sure if Ruby regular expressions can handle this, I believe Perl's can).
A (very trivialized) process may be:
For each character in the input string:
If it is not a '(' or ')' then just append it to the output
If it is a '(' increase a seen_parens counter and add it
If it is a ')' and seen_parens is > 0, add it and decrease seen_parens. Otherwise skip it.
At the end of the process, if seen_parens is > 0 then remove that many parens, starting from the end. (This step can be merged into the above process with use of a stack or recursion.)
The entire process is O(n), even if a relatively high overhead
Happy coding.
The following uses oniguruma. Oniguruma is the regex engine built in if you are using ruby1.9. If you are using ruby1.8, see this: oniguruma.
Update
I had been so lazy to just copy and paste someone else's regex. It seemed to have problem.
So now, I wrote my own. I believe it should work now.
class String
NonParenChar = /[^\(\)]/
def remove_unmatched_parens
self[/
(?:
(?<balanced>
\(
(?:\g<balanced>|#{NonParenChar})*
\)
)
|#{NonParenChar}
)+
/x]
end
end
(?<name>regex1) names the (sub)regex regex1 as name, and makes it possible to be called.
?g<name> will be a subregex that represents regex1. Note here that ?g<name> does not represent a particular string that matched regex1, but it represents regex1 itself. In fact, it is possible to embed ?g<name> within (?<name>...).
Update 2
This is simpler.
class String
def remove_unmatched_parens
self[/
(?<valid>
\(\g<valid>*\)
|[^()]
)+
/x]
end
end
Build a simple LR parser:
tokenize, token, stack = false, "", []
")(a))(()(asdf)(".each_char do |c|
case c
when '('
tokenize = true
token = c
when ')'
if tokenize
token << c
stack << token
end
tokenize = false
when /\w/
token << c if tokenize
end
end
result = stack.join
puts result
running yields:
wesbailey#feynman:~/code_katas> ruby test.rb
(a)()(asdf)
I don't agree with the folks modifying the String class because you should never open a standard class. Regexs are pretty brittle for parser and hard to support. I couldn't imagine coming back to the previous solutions 6 months for now and trying to remember what they were doing!
Here's my solution, based on #pst's algorithm:
class String
def remove_unmatched_parens
scanner = StringScanner.new(dup)
output = ''
paren_depth = 0
while char = scanner.get_byte
if char == "("
paren_depth += 1
output << char
elsif char == ")"
output << char and paren_depth -= 1 if paren_depth > 0
else
output << char
end
end
paren_depth.times{ output.reverse!.sub!('(', '').reverse! }
output
end
end
Algorithm:
Traverse through the given string.
While doing that, keep track of "(" positions in a stack.
If any ")" found, remove the top element from the stack.
If stack is empty, remove the ")" from the string.
In the end, we can have positions of unmatched braces, if any.
Java code:
Present # http://a2ajp.blogspot.in/2014/10/remove-unmatched-parenthesis-from-given.html

Syntax error, unexpected '='

I have the following as part of a class
def to_s
i = 0
first_line? = true
output = ''
#selections.each do | selection |
i += 1
if first_line?
output << selection.to_s(first_line?)
first_line? = false
else
output << selection.to_s
end
if i >= 5
output << "\r"
i = 0
else (output << " $ ")
end
end
return output
end
And i am getting the following syntax errors
SyntaxError: list2sel.rb:45: syntax error, unexpected '='
first_line? = true
^
list2sel.rb:47: syntax error, unexpected keyword_do_block, expecting keyword_end
#selections.each do | selection |
^
list2sel.rb:51: syntax error, unexpected '='
first_line? = false
^
What give, also thanks in advance, this is driving me nuts.
I suppose, you can't name variables with '?' at the end.
Variable names (with a few exceptions noted below) can only contain letters, numbers and the underscore. (Also, they must begin with a letter or the underscore; they can't begin with a number.) You can't use ? or ! in a variable name.
Beyond that rule, there is a strong convention in Ruby that a question mark at the end of something indicates a method that returns a boolean value:
4.nil? # => returns false....
So even if you could use it, a variable like first_line? would confuse (and then annoy) the hell out of Rubyists. They would expect it be a method testing whether something was the first line of something (whatever exactly that means in context).
Exceptions about variable names:
Global variables begin with $ - e.g., $stdin for standard input.
Instance variables begin with # - e.g. #name for an object
Class variables begin with ## - e.g. ##total for a class
I believe this is a more concise way of doing the above (untested):
def to_s
output = ""
#selections.each_with_index do | selection,line |
output << line==0 ? selection.to_s(true) and next : selection.to_s
output << line % 5 ? " $ " : "\r"
end
return output
end
If you are not a fan of the ternary operator (x ? y : z) then you can make them ifs:
def to_s
output = ""
#selections.each_with_index do | selection,line |
if line==0
output << selection.to_s(true)
else
output << selection.to_s
if line % 5
output << " $ "
else
output << "\r"
end
end
end
return output
end
Variable names allow non-ASCII letters, and there are non-ASCII versions of the question mark, so you can put question marks (and also some forms of space characters) into variable names.

Resources