1

So I am making a parser, but it is doesn't understand numbers that starts with a point. This means that "0.5" is understood by the parser, but not ".5":

>>> evaluate("0.5")
0.5

>>> evaluate(".5")
SyntaxError: Expected {{[- | +] {{{{{{{W:(ABCD...,ABCD...) Suppress:("(") Forward: ...} Suppress:(")")} | 'PI'} | 'E'} | 'PHI'} | 'TAU'} | Combine:({{W:(+-01...,0123...) [{"." [W:(0123...)]}]} [{'E' W:(+-01...,0123...)}]})}} | {[- | +] Group:({{Suppress:("(") Forward: ...} Suppress:(")")})}} (at char 0), (line:1, col:1)

So, my objective is to replace every decimal number without an integer part by "0." followed by the decimals (for instance, replace ".5" by "0.5", "-.2" by "-0.2", ".0" by "0.0", etc...), so that it can be understood by the parser. So, I came up with this code:

expression = "-.2"
expression = list(expression)

for key, char in enumerate(expression):
    # If first character in the string is a point, add "0" before it if there is a digit after the point
    if not key:
        if char == ".":
            try:
                if expression[key+1].isdigit():
                    expression.insert(key, "0")
            except: pass
        continue

    # If a point is not the first character in the string, add "0" before it if there are no digits before the point but one after the point
    if char == "." and not expression[key-1].isdigit():
        try:
            if expression[key+1].isdigit():
                expression.insert(key, "0")
        except: continue

expression = "".join(expression)
print(expression)   # Result is "-0.2"

This code works, but is it the best way to do it?

TheOneMusic
  • 1,776
  • 3
  • 15
  • 39

3 Answers3

3

No. If your language allows numeric literals of the form .5 or -.7 then your parser should be changed to accept such literals.

  • 1
    @TheOneMusic this is a totally different question and should be posted as a new question. – jps Jul 28 '19 at 13:12
  • 1
    Sorry I'm not familiar with the pyparsing framework. Apparently the `fnumber` parsing action does not accept numbers starting with a decimal point, but I wouldn't know where to change this. – Hans-Martin Mosner Jul 28 '19 at 13:16
  • 1
    Or you use that 90 minutes to look for a solution :-) Achieving results is sometimes hard, especially when you do the work yourself ;-) – Hans-Martin Mosner Jul 28 '19 at 13:23
  • 1
    @TheOneMusic that's perfect! – Hans-Martin Mosner Jul 28 '19 at 13:24
  • 2
    If everything is optional, then this expression will also match "", which may make for other issues for your parser. The new version 2.4.2 of pyparsing (currently out as 2.4.2a1 prerelease) contains a `pyparsing_common.fnumber` expression that accepts floating point numbers with no leading digit. – PaulMcG Jul 28 '19 at 16:04
2

did you consider including some regex in your parser? You could do the appropriate check e.g. by

import re
dec_sep = '.'
dec_pattern = '[+-]?[0-9]+['+dec_sep+'][0-9]*|[+-]?[0-9]*['+dec_sep+'][0-9]+'

for s in ['.7', '-.4', '4.', '+3.']:
    print(re.fullmatch(dec_pattern, s))

and get

<re.Match object; span=(0, 2), match='.7'>
<re.Match object; span=(0, 3), match='-.4'>
<re.Match object; span=(0, 2), match='4.'>
<re.Match object; span=(0, 3), match='+3.'>
FObersteiner
  • 22,500
  • 8
  • 42
  • 72
  • 1
    jep sometimes it's better to avoid the "I have a problem -> I need regex -> oh... now I have two problems!" situation ;-) – FObersteiner Jul 28 '19 at 13:34
  • 2
    Pyparsing includes the Regex class for just this kind of thing. The provided `pyparsing_common.fnumber` is defined using Regex, as there is a big performance gain in using a single Regex expression, vs. combination of multiple small expressions. Pyparsing also creates internal regexes for most terminal expressions. – PaulMcG Jul 28 '19 at 16:06
  • 1
    `pyparsing_common` is defined in pyparsing just like any other name. `import pyparsing as pp; ppc=pp.pyparsing_common` is one way. Then you can access `ppc.fnumber`, `ppc.integer`, etc. – PaulMcG Jul 28 '19 at 19:33
1
expression = "-.0"
expression = float(expression)
expression = str(expression)
print(expression)
ComplicatedPhenomenon
  • 4,055
  • 2
  • 18
  • 45