Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

IsModified()

2005-07-04
2013-05-14
  • F.A. Pinkse
    F.A. Pinkse
    2005-07-04

    Hi All,

    I am stuck.
    I have a wxTextCtrl with an event on it.For this control there is a function IsModified() to check whether the text was changed by the user or by the program.
    I have check this and it works.
    So when I do this:

        def OnWaarde_sText(self, event):
            if self.Waarde_s.IsModified():
                self.Waarde_s.SetValue('ok')
            event.Skip()
    The event is triggerd twice but the IsModified is only true the first time.

    Even when I call another method which returns a string and do this.

        def OnWaarde_sText(self, event):
            if self.Waarde_s.IsModified():
                a = CheckWaarde_sSyntax(self)
                self.Waarde_s.SetValue(a)
            event.Skip()

    The event is triggered twice, but the IsModified() is only true the first time.

    But when I do this
        def OnWaarde_sText(self, event):
            if self.Waarde_s.IsModified():
                a =ParseWaarde(self,self.Waarde_s.GetValue())
                self.Waarde_s.SetValue(a)
            event.Skip()

    The IsModified() stays true.

    This is what ParseWaarde looks like, it is not finished and certainly not perfect.

    from pyparsing import Word,nums,Optional,ParseException,alphas,CharsNotIn,SkipTo,srange,ZeroOrMore

    # these are for PyParsing.
    testdata = """0001vFF000"""
    LowerGoodalphas = 'FNUerkgt'
    Goodalphas = 'fpnumERKMGTP'
    GoodalphasExtended = Goodalphas+LowerGoodalphas+srange('[0-9]')
    units = Optional(Word(nums))
    prefactor = Optional(CharsNotIn(GoodalphasExtended))
    flower = Word(LowerGoodalphas)
    fupper = Word(Goodalphas,max = 1)
    factor = Optional(fupper.setResultsName('upper')|flower.setResultsName('lower'))
    postfactor = Optional(Word(alphas))
    fraction = Optional(Word(nums))
    Waarde = units.setResultsName("unit")+prefactor.setResultsName('pre')+factor.setResultsName("factor")+postfactor.setResultsName('post')+fraction.setResultsName("fraction")
    def doswapcase(s,l,t):
        return t[0].swapcase()
    flower.setParseAction(doswapcase)
    def dostrip(s,l,t):
        b = t[0]
        return '1'
    units.setParseAction(dostrip)

    # end PyParsing

    def ParseWaarde(self,testdata):
        try:
            a = testdata
        #    a = units.transformString( testdata )
            a = flower.transformString( a )
            a = Waarde.parseString(a)
        except ParseException, err:
            print err.line
            print " "*(err.column-1) + "^"
            print err
        return a.unit.lstrip('0')+a.factor+a.fraction

    What I want the parser to do is check an electronic component value like 1R10, meaning 1.10 Ohm or 10M
    Meaning 10 MegaOhm.
    The digits before the factor, R or M in the example should be geater than 0 and I called them units, the digits after the factor are called fraction.

    Hopefully someone recognizes the error or other nasties I have done.

    Thanks,

    Frans.

     
    • Paul McGuire
      Paul McGuire
      2005-07-04

      Frans -

      Welcome to pyparsing!  It looks like you have definitely made a good head start in breaking up your problem into component pieces.  If I had any recommendations, they would mostly be in code organization, not in technical pyparsing usage.

      I would start by writing a BNF representing what it is you are trying to parse.  I'm trying to guess what the text structure is, but it's a bit mixed together, between flower, fupper, and all of the Optionals.  In general, I would not use Optional until defining my final Waarde expression.  For example, units = Word(nums).  The fact that units may be omitted can be given later when creating the Waarde expression.

      I would also test that ParseWaarde is doing the right thing, by itself.  Create some unit tests that can run in isolation, that exercise the different formats that you want to recognize.  You provided two samples in your e-mail, "1R10" and "10M", but it is not clear what they are supposed to parse as.

      Look at the minor changes I made to ParseWaarde, and the test cases I used to call it.  Once you get this working, then you can move on to wx events and such.

      def ParseWaarde(testdata):
          try:
              a = testdata
          #    a = units.transformString( testdata )
              a = flower.transformString( a )
              a = Waarde.parseString(a)
              print a
              for k in a.keys():
                  print k,a[k]
              print
          except ParseException, err:
              print err.line
              print " "*(err.column-1) + "^"
              print err
          return a.unit.lstrip('0')+a.factor+a.fraction

      ParseWaarde("1R10")
      ParseWaarde("10M")

      This prints:
      ['1', 'R', '10']
      upper R
      fraction 10
      unit 1
      factor R

      ['10', 'M']
      upper M
      unit 10
      factor M

      Also, it is a little confusing trying to follow your two-pass parse, first where you transform the string (conversion of some uppers to lowers, and other lowers to uppers?), and then calling Waarde.parseString.
      In dostrip, what does the 'b' variable do?

      Lastly, the Goodalphas, LowerGoodalphas, etc. are confusing to me.  For one thing, why isn't LowerGoodalphas = Goodalphas.lower()?  Is it really necessary to transform the string before parsing it?  I think you might be able to create a single grammar that handles the upper/lower cases, without doing a transformation pass first.

      I can't help you much (any!) with the wx toolkit, I'm afraid, so if you can narrow this down to the ParseWaarde function, and get that working, then I'll best be able to help.

      Thanks again for using pyparsing!

      -- Paul

       
    • F.A. Pinkse
      F.A. Pinkse
      2005-07-04

      Hi Paul,

      Thanks for your swift answer.
      Yes, I under stand you can not do much for the wx part, but since the problem is only after I call the parse bit, I thought to have a go first here, before the wx guys sent me back.
      I did a series of trial runs on a stand alone module and used the print ..... method to test the output. Next I changed the print to a return.

      Ok I will do a step backwards and revert to the stand alone as you suggested. To polish the code and parser and evaluate your suggestions.

      I want to use pyparsing to check the format of a value
      of a partname the user is typing into the tool I am making. This tool  aids the user to generate the names for library parts for an Electronics PCB design program in the format we have agreed upon. The names of the parts are now recognizable by all users :-)

      I am not a pro in BNF.but..

      <onewaardealpha>==: 'f' | 'p ' | 'n' | 'm' | 'E' | 'R' | 'K' | 'M' | 'G' | 'T' | 'P'
      Waarde==:<digits>,<onewaardealpha>,<digits>

      When I read that you could do transfromString() I thought I could help the user by changing the goodalphas when they were typed in the wrong case, instead of throwing an error. That is the reason for the two pass stuff.

      In dostrip I wanted to strip any leading zero's from the units. Instead of this '1' on the return there was b.lstrip('0'). but that did not work, it gave an error. On the final return It did work.

      Thanks for offering help.

      Enough typing for now. Time for testing your suggestions.

      Frans.

       
    • F.A. Pinkse
      F.A. Pinkse
      2005-07-04

      Hi Paul,

      Ok, finished with creating a standalone testbed as a module separate from my other stuff.
      Your changes workout to be the same as I had on my prototype.
      To repeat my aim, I want to check the format of a partname the user is typing and at the same time I want to correct him when he makes a mistake I think is a mistake.

      Now I can comment on your last few paragraphs.
      I came up with this two-pass parse, because I wanted to make corrections where the user might have made a typing error, like typing the correct factor letter but forgot the case.
      I could not make it work in one run. If it can be done, that would be nice.
      My first code used IF's but when I read about transfromString it tried it instead.

      Goodalphas are the letters we agreed upon to use in the value description. The name LowerGoodalphas is a left over, but these are the Goodalphas the user could have typed in and forgot about the case.
      I cannot correct the p,m,M,P, because they all are in Goodalphas, so the user must recognize this by himself.

      I forgot to tell what the Goodalphas are. They represent the letters you use when abbreviating 1000gram into 1kilogram or 1kg. in Electronics we do the same 1000 Ohms is 1kOhm or short 1k.

      To morrow I will start thinking about this single grammer.

      Frans.

       
    • F.A. Pinkse
      F.A. Pinkse
      2005-07-05

      Hi Paul,

      Solved the puzzle.
      The IsModified() function does some stuff one does not expect it to do. I made a work around, with my own flagging.
      Pressure is off now, the tool is workable.

      I still want to improve the grammar though.
      If you still feel like helping me that would be nice.

      Frans.