Regex help...pretty please?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • MooMaster

    #1

    Regex help...pretty please?

    I'm trying to develop a little script that does some string
    manipulation. I have some few hundred strings that currently look like
    this:

    cond(a,b,c)

    and I want them to look like this:

    cond(c,a,b)

    but it gets a little more complicated because the conds themselves may
    have conds within, like the following:

    cond(0,cond(c,c ond(e,cond(g,h, (a<f)),(a<d)),( a<b)),(a<1))

    What I want to do in this case is move the last parameter to the front
    and then work backwards all the way out (if you're thinking recursion
    too, I'm vindicated) so that it ends up looking like this:

    cond((a<1), 0, cond((a<b),c,co nd((a<d), e, cond((a<f), g, h))))

    futhermore, the conds may be multiplied by an expression, such as the
    following:

    cond(-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float(a))

    Here, all I want to do is switch the parameters of the conds without
    touching the expression, like so:

    cond(f,-1,1)*((float(e) *(2**4))+(float (d)*8)+(float(c )*4)+(float(b)* 2)+float(a))

    So that's the gist of my problem statement. I immediately thought that
    regular expressions would provide an elegant solution. I would go
    through the string by conds, stripping them & the () off, until I got
    to the lowest level, then move the parameters and work backwards. That
    thought process became this:
    -------------------------------------CODE--------------------------------------------------------
    import re

    def swap(left, middle, right):
    left = left.replace("( ", "")
    right = right.replace(" )", "")
    temp = left
    left = right
    right = temp
    temp = middle
    middle = right
    right = temp
    whole = 'cond(' + left + ',' + middle + ',' + right + ')'
    return whole

    def condReplacer(st ring):
    #regex = re.compile(r'co nd\(.*,.*,.+\)' )
    regex = re.compile(r'co nd\(.*,.*,.+?\) ')
    if not regex.search(st ring):
    print "whole string is: " + string
    [left, middle, right] = string.split(', ')
    right = right.replace(' \'', ' ')
    string = swap(left.strip (), middle.strip(), right.strip())
    print "the new string is:" + string
    return string
    else:
    more_conds = regex.search(st ring)
    temp_string = more_conds.grou p()
    firstParen = temp_string.fin d('(')
    temp_string = temp_string[firstParen:]
    print "there are more conditionals!" + temp_string
    condReplacer(te mp_string)
    def lineReader(file ):
    for line in file:
    regex = r'cond\(.*,.*,. +\)?'
    if re.search(regex ,line,re.DOTALL ):
    condReplacer(li ne)

    if __name__ == "__main__":
    input_file = open("only_cond s2.txt", 'r')
    lineReader(inpu t_file)
    -------------------------------------CODE--------------------------------------------------------

    I think my problem lies in my regular expression... If I use the one
    commented out I do a greedy search and in my test case where I have a
    conditional * an expression, I grab the expression too, like so:

    INPUT:

    cond(-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float(a))
    OUTPUT:
    whole string is:
    (-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float
    (a))
    the new string
    is:cond(f*((flo at(e*(2**4+(flo at(d*8+(float(c *4+(float(b*2+f loat
    (a,-1,1)

    when all I really want to do is grab the part associated with the cond.
    But if I do a non-greedy search I avoid that problem but stop too early
    when I have an expression like this:

    INPUT:
    cond(a,b,(abs(c ) >= d))
    OUTPUT:
    whole string is: (a,b,(abs(c)
    the new string is:cond((abs(c, a,b)

    Can anyone help me with the regular expression? Is this even the best
    approach to take? Anyone have any thoughts?

    Thanks for your time!

  • Tim Chase

    #2
    Re: Regex help...pretty please?

    cond(a,b,c)
    >
    and I want them to look like this:
    >
    cond(c,a,b)
    >
    but it gets a little more complicated because the conds themselves may
    have conds within, like the following:
    >
    cond(0,cond(c,c ond(e,cond(g,h, (a<f)),(a<d)),( a<b)),(a<1))
    Regexps are *really* *REALLY* *bad* at arbitrarily nested
    structures. really.

    Sounds more like you want something like a lex/yacc sort of
    solution. IIUC, pyparsing may do the trick for you. I'm not a
    pyparsing wonk, but I can hold my own when it comes to crazy
    regexps, and can tell you from experience that regexps are *not*
    a good path to try and go down for this problem.

    Many times, a regexp can be hammered into solving problems
    superior solutions than employing regexps. This case is not even
    one of those.

    If you know the maximum depth of nesting you'll encounter, you
    can do some hackish stunts to shoehorn regexps to solve the
    problem. But if they are truely of arbitrary nesting-depth,
    *good* *luck*! :)

    -tkc




    Comment

    • Simon Forman

      #3
      Re: Regex help...pretty please?

      MooMaster wrote:
      I'm trying to develop a little script that does some string
      manipulation. I have some few hundred strings that currently look like
      this:
      >
      cond(a,b,c)
      >
      and I want them to look like this:
      >
      cond(c,a,b)
      >
      but it gets a little more complicated because the conds themselves may
      have conds within, like the following:
      >
      cond(0,cond(c,c ond(e,cond(g,h, (a<f)),(a<d)),( a<b)),(a<1))
      >
      What I want to do in this case is move the last parameter to the front
      and then work backwards all the way out (if you're thinking recursion
      too, I'm vindicated) so that it ends up looking like this:
      >
      cond((a<1), 0, cond((a<b),c,co nd((a<d), e, cond((a<f), g, h))))
      >
      futhermore, the conds may be multiplied by an expression, such as the
      following:
      >
      cond(-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float(a))
      >
      Here, all I want to do is switch the parameters of the conds without
      touching the expression, like so:
      >
      cond(f,-1,1)*((float(e) *(2**4))+(float (d)*8)+(float(c )*4)+(float(b)* 2)+float(a))
      >
      So that's the gist of my problem statement. I immediately thought that
      regular expressions would provide an elegant solution. I would go
      through the string by conds, stripping them & the () off, until I got
      to the lowest level, then move the parameters and work backwards. That
      thought process became this:
      -------------------------------------CODE--------------------------------------------------------
      import re
      >
      def swap(left, middle, right):
      left = left.replace("( ", "")
      right = right.replace(" )", "")
      temp = left
      left = right
      right = temp
      temp = middle
      middle = right
      right = temp
      whole = 'cond(' + left + ',' + middle + ',' + right + ')'
      return whole
      >
      def condReplacer(st ring):
      #regex = re.compile(r'co nd\(.*,.*,.+\)' )
      regex = re.compile(r'co nd\(.*,.*,.+?\) ')
      if not regex.search(st ring):
      print "whole string is: " + string
      [left, middle, right] = string.split(', ')
      right = right.replace(' \'', ' ')
      string = swap(left.strip (), middle.strip(), right.strip())
      print "the new string is:" + string
      return string
      else:
      more_conds = regex.search(st ring)
      temp_string = more_conds.grou p()
      firstParen = temp_string.fin d('(')
      temp_string = temp_string[firstParen:]
      print "there are more conditionals!" + temp_string
      condReplacer(te mp_string)
      def lineReader(file ):
      for line in file:
      regex = r'cond\(.*,.*,. +\)?'
      if re.search(regex ,line,re.DOTALL ):
      condReplacer(li ne)
      >
      if __name__ == "__main__":
      input_file = open("only_cond s2.txt", 'r')
      lineReader(inpu t_file)
      -------------------------------------CODE--------------------------------------------------------
      >
      I think my problem lies in my regular expression... If I use the one
      commented out I do a greedy search and in my test case where I have a
      conditional * an expression, I grab the expression too, like so:
      >
      INPUT:
      >
      cond(-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float(a))
      OUTPUT:
      whole string is:
      (-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float
      (a))
      the new string
      is:cond(f*((flo at(e*(2**4+(flo at(d*8+(float(c *4+(float(b*2+f loat
      (a,-1,1)
      >
      when all I really want to do is grab the part associated with the cond.
      But if I do a non-greedy search I avoid that problem but stop too early
      when I have an expression like this:
      >
      INPUT:
      cond(a,b,(abs(c ) >= d))
      OUTPUT:
      whole string is: (a,b,(abs(c)
      the new string is:cond((abs(c, a,b)
      >
      Can anyone help me with the regular expression? Is this even the best
      approach to take? Anyone have any thoughts?
      >
      Thanks for your time!
      You're gonna want a parser for this. pyparsing or spark would suffice.
      However, since it looks like your source strings are valid python you
      could get some traction out of the tokenize standard library module:

      from tokenize import generate_tokens
      from StringIO import StringIO

      s =
      'cond(-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float(a))'

      for t in generate_tokens (StringIO(s).re adline):
      print t[1],


      Prints:
      cond ( - 1 , 1 , f ) * ( ( float ( e ) * ( 2 ** 4 ) ) + ( float ( d ) *
      8 ) + ( float ( c ) * 4 ) + ( float ( b ) * 2 ) + float ( a ) )

      Once you've got that far the rest should be easy. :)

      Peace,
      ~Simon



      Source code: Lib/tokenize.py The tokenize module provides a lexical scanner for Python source code, implemented in Python. The scanner in this module returns comments as tokens as well, making it u...


      Comment

      • Paul McGuire

        #4
        Re: Regex help...pretty please?

        "MooMaster" <ntv1534@gmail. comwrote in message
        news:1156358822 .649578.126990@ 74g2000cwt.goog legroups.com...
        I'm trying to develop a little script that does some string
        manipulation. I have some few hundred strings that currently look like
        this:
        >
        cond(a,b,c)
        >
        and I want them to look like this:
        >
        cond(c,a,b)
        <snip>

        Pyparsing makes this a fairly tractable problem. The hardest part is
        defining the valid contents of a relational and arithmetic expression, which
        may be found within the arguments of your cond(a,b,c) constructs.

        Not guaranteeing this 100%, but it did convert your pathologically nested
        example on the first try.

        -- Paul

        ----------
        from pyparsing import *

        ident = ~Literal("cond" ) + Word(alphas)
        number = Combine(Optiona l("-") + Word(nums) + Optional("." + Word(nums)))

        arithExpr = Forward()
        funcCall = ident+"("+delim itedList(arithE xpr)+")"
        operand = number | funcCall | ident
        binop = oneOf("+ - * /")
        arithExpr << ( ( operand + ZeroOrMore( binop + operand ) ) | ("(" +
        arithExpr + ")" ) )
        relop = oneOf("< == <= >= != <>")

        condDef = Forward()
        simpleCondExpr = arithExpr + ZeroOrMore( relop + arithExpr ) | condDef
        multCondExpr = simpleCondExpr + "*" + arithExpr
        condExpr = Forward()
        condExpr << ( simpleCondExpr | multCondExpr | "(" + condExpr + ")" )

        def reorderArgs(t):
        return "cond(" + ",".join(["".join(t.arg3) , "".join(t.arg1) ,
        "".join(t.a rg2)]) + ")"

        condDef << ( Literal("cond") + "(" + Group(condExpr) .setResultsName ("arg1")
        + "," +
        Group(condExpr) .setResultsName ("arg2")
        + "," +
        Group(condExpr) .setResultsName ("arg3")
        + ")" ).setParseActio n( reorderArgs )

        tests = [
        "cond(a,b,c )",
        "cond(1>2,b,c)" ,
        "cond(-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+floa
        t(a))",
        "cond(a,b,(abs( c) >= d))",
        "cond(0,cond(c, cond(e,cond(g,h ,(a<f)),(a<d)), (a<b)),(a<1))",
        ]

        for t in tests:
        print t,"->",condExpr.tra nsformString(t)
        ----------
        Prints:
        cond(a,b,c) -cond(c,a,b)
        cond(1>2,b,c) -cond(c,1>2,b)
        cond(-1,1,f)*((float( e)*(2**4))+(flo at(d)*8)+(float (c)*4)+(float(b )*2)+float
        (a)) ->
        cond(f,-1,1)*((float(e) *(2**4))+(float (d)*8)+(float(c )*4)+(float(b)* 2)+float
        (a))
        cond(a,b,(abs(c ) >= d)) -cond((abs(c)>=d ),a,b)
        cond(0,cond(c,c ond(e,cond(g,h, (a<f)),(a<d)),( a<b)),(a<1)) ->
        cond((a<1),0,co nd((a<b),c,cond ((a<d),e,cond(( a<f),g,h))))


        Comment

        • vbgunz

          #5
          Re: Regex help...pretty please?

          MooMaster Wrote:
          I'm trying to develop a little script that does some string
          manipulation. I have some few hundred strings that currently look like
          this:
          cond(a,b,c)
          and I want them to look like this:
          cond(c,a,b)
          I zoned out on your question and created a very simple flipper.
          Although it will not solve your problem maybe someone looking for a
          simpler version may find it useful as a starting point. I hope it
          proves useful. I'll post my simple flipper here:

          s = 'cond(1,savv(gr ave(3,2,1),y,x) ,maxx(c,b,a),0) '
          def argFlipper(s):
          ''' take a string of arguments and reverse'em e.g.
          >>cond(1,savv(g rave(3,2,1),y,x ),maxx(c,b,a),0 )
          -cond(0,maxx(a,b ,c),savv(x,y,gr ave(1,2,3)),1)

          '''

          count = 0
          keyholder = {}
          while 1:
          if s.find('(') 0:
          count += 1
          value = '%sph' + '%d' % count
          tempstring = [x for x in s]
          startindex = s.rfind('(')
          limitindex = s.find(')', startindex)
          argtarget = s[startindex + 1:limitindex].split(',')
          argreversed = ','.join(revers ed(argtarget))
          keyholder[value] = '(' + argreversed + ')'
          tempstring[startindex:limi tindex + 1] = value
          s = ''.join(tempstr ing)
          else:
          while count and keyholder:
          s = s.replace(value , keyholder[value])
          count -= 1
          value = '%sph' + '%d' % count
          return s

          print argFlipper(s)

          Comment

          Working...