views:

152

answers:

1

In answering this code golf question, I ran across a problem in my answer.

I've been testing this and I cannot even get these two comparisons to work in the code, despite the fact that IRB has the right behavior. I really need some help here.

Here's the code, below that will be an explanation of the problem.

def solve_expression(expr)
  chars = expr.split '' # characters of the expression
  parts = []  # resulting parts
  s,n = '','' # current characters

  while(n = chars.shift)
    if (s + n).match(/^(-?)[.\d]+$/) || (!chars[0].nil? && chars[0] != ' ' && n == '-') # only concatenate when it is part of a valid number
      s += n
    elsif (chars[0] == '(' && n[0] == '-') || n == '(' # begin a sub-expression
      p n # to see what it breaks on, ( or -
      negate = n[0] == '-'
      open = 1
      subExpr = ''
      while(n = chars.shift)
        open += 1 if n == '('
        open -= 1 if n == ')'
        # if the number of open parenthesis equals 0, we've run to the end of the
        # expression.  Make a new expression with the new string, and add it to the
        # stack.
        subExpr += n unless n == ')' && open == 0
        break if open == 0
      end
      parts.push(negate ? -solve_expression(subExpr) : solve_expression(subExpr))
      s = ''
    elsif n.match(/[+\-\/*]/)
      parts.push(n) and s = ''
    else
      parts.push(s) if !s.empty?
      s = ''
    end
  end
  parts.push(s) unless s.empty? # expression exits 1 character too soon.

  # now for some solutions!
  i = 1
  a = parts[0].to_f # left-most value is will become the result
  while i < parts.count
    b,c = parts[i..i+1]
    c = c.to_f
    case b
      when '+': a = a + c
      when '-': a = a - c
      when '*': a = a * c
      when '/': a = a / c
    end
    i += 2
  end
  a
end

The problem occurs in the assignment of negate.

I need negate to be true when the character just before a expression is a dash, but the condition isn't even working. Both n == '-' and n[0] == '-', the form of quotation doesn't matter, wind up FALSE every time. Yet, I've been using this exact comparison and n == '(' works correctly every time!

What is going on? Why doesn't n == '-' work, when n == '(' does? This is encoded in UTF-8 w/o BOM, UNIX linebreaks.

What's wrong with my code?

+2  A: 

You have:

if (s + n).match(/^(-?)[.\d]+$/) || (!chars[0].nil? && chars[0] != ' ' && n == '-')
      s += n
elsif (chars[0] == '(' && n[0] == '-') || n == '('

As n is always a one-character string, if (chars[0] == '(' && n[0] == '-')) is true, then the previous condition, (!chars[0].nil? && chars[0] != ' ' && n == '-'), will also be true. Your code will never enter the second part of the if if n[0]=='-'.

If your p n line is outputting a dash, be sure it is exactly the same character you are looking for, not some character that looks like a dash. Unicode has many kinds of dashes, maybe you have a weird unicode dash character in your code or on your input.

ehabkost
Thank you very much, it hadn't occurred to me that the previous statement had caught my code. Thanks for the fresh eyes.
The Wicked Flea