requestion regarding regular expression

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

    #1

    requestion regarding regular expression

    Hello,

    I'm trying to analyze some autolisp code with python. In the file to
    be analyzed there are many functions. Each function begins with a
    "defun" statement. And before that, there may or may not have comment
    line(s), which begins with ";". My goal is to export each function
    into separate files, with comments, if there is any. Below is the code
    that I'm struggling with:

    Code:
    path = "C:\\AutoCAD\\LSP\\Sub.lsp"
    string = file(path, 'r').read()
    
    import re
    pat = "\\;+.+\\n\\(DEFUN"
    p = re.compile(pat,re.I)
    
    iterator = p.finditer(string)
    spans = [match.span() for match in iterator]
    
    for i in range(min(15, len(spans))):
    print string[spans[i][0]:spans[i][1]]
    The code above runs fine. But it only takes care of the situation in
    which there is exactly one comment line above the "defun" statement.
    How do I repeat the sub-pattern "\\;+.+\\n" here?
    For example if I want to repeat this pattern 0 to 10 times, I know
    "\\;+.+\\n{0:10 }\\(DEFUN" does not work. But don't know where to put
    "{0:10}". As a work around, I tried to use
    pat = "|".join(["\\;+.+\\n" *i+ "\\(DEFUN" for i in range(11)]), and it
    turned out to be very slow. Any help?

    Thank you.

    Kelie

  • Kent Johnson

    #2
    Re: requestion regarding regular expression

    Kelie wrote:[color=blue]
    > Hello,
    >
    > I'm trying to analyze some autolisp code with python. In the file to
    > be analyzed there are many functions. Each function begins with a
    > "defun" statement. And before that, there may or may not have comment
    > line(s), which begins with ";". My goal is to export each function
    > into separate files, with comments, if there is any. Below is the code
    > that I'm struggling with:
    >
    >
    Code:
    >
    > path = "C:\\AutoCAD\\LSP\\Sub.lsp"
    > string = file(path, 'r').read()
    >
    > import re
    > pat = "\\;+.+\\n\\(DEFUN"
    > p = re.compile(pat,re.I)
    >
    > iterator = p.finditer(string)
    > spans = [match.span() for match in iterator]
    >
    > for i in range(min(15, len(spans))):
    >     print string[spans[i][0]:spans[i][1]]
    >
    >
    >
    > The code above runs fine. But it only takes care of the situation in
    > which there is exactly one comment line above the "defun" statement.[/color]

    ISTM you don't need regex here, a simple line processor will work.
    Something like this (untested):

    path = "C:\\AutoCAD\\L SP\\Sub.lsp"
    lines = open(path).read lines()

    # Find the starts of all the functions
    starts = [i for i, line in enumerate(lines ) if line.startswith ('(DEFUN')]

    # Check for leading comments
    for i, start in starts:
    while start > 0 and lines[start-1].startswith(';' ):
    starts[i] = start = start-1

    # Now starts should be a list of line numbers for the start of each function

    Kent

    Comment

    • BartlebyScrivener

      #3
      Re: requestion regarding regular expression

      Kent,

      Running

      path = "d:/emacs files/emacsinit.txt"
      lines = open(path).read lines()
      # my defun lines are lowercase,
      # next two lines are all on one
      starts = [i for i, line in enumerate(lines ) if
      line.startswith ('(defun')]
      for i, start in starts:
      while start > 0 and lines[start-1].startswith(';' ):
      starts[i] = start = start-1
      print starts

      I get

      File "D:\Python\find lines.py", line 7, in __main__
      for i, start in starts:
      TypeError: unpack non-sequence

      Also, I don't understand the "i for i", but I don't understand a lot of
      things yet :)

      thanks,

      rick

      Comment

      • Felipe Almeida Lessa

        #4
        Re: requestion regarding regular expression

        Em Sex, 2006-04-14 às 07:47 -0700, BartlebyScriven er escreveu:[color=blue]
        > starts = [i for i, line in enumerate(lines ) if
        > line.startswith ('(defun')][/color]

        This line makes a list of integers. enumerate gives you a generator that
        yields tuples consisting of (integer, object), and by "i for i, line"
        you unpack the tuple into "(i, line)" and pick just "i".
        [color=blue]
        > for i, start in starts:[/color]

        Here you try to unpack the elements of the list "starts" into "(i,
        start)", but as we saw above the list contains just "i", so an exception
        is raised.

        I don't know what you want, but...

        starts = [i, line for i, line in enumerate(lines ) if
        line.startswith ('(defun')]

        or

        starts = [x for x in enumerate(lines ) if x[1].startswith('(d efun')]

        ....may (or may not) solve your problem.

        --
        Felipe.

        Comment

        • Kent Johnson

          #5
          Re: requestion regarding regular expression

          BartlebyScriven er wrote:[color=blue]
          > Kent,
          >
          > Running
          >
          > path = "d:/emacs files/emacsinit.txt"
          > lines = open(path).read lines()
          > # my defun lines are lowercase,
          > # next two lines are all on one
          > starts = [i for i, line in enumerate(lines ) if
          > line.startswith ('(defun')]
          > for i, start in starts:
          > while start > 0 and lines[start-1].startswith(';' ):
          > starts[i] = start = start-1
          > print starts
          >
          > I get
          >
          > File "D:\Python\find lines.py", line 7, in __main__
          > for i, start in starts:
          > TypeError: unpack non-sequence[/color]

          Sorry, should be
          for i, start in enumerate(start s):

          start is a specific start line, i is the index of that start line in the
          starts array (so the array can be modified in place).

          Kent

          Comment

          • BartlebyScrivener

            #6
            Re: requestion regarding regular expression

            That's it. Thank you! Very instructive.

            Final:

            path = "d:/emacs files/emacsinit.txt"
            lines = open(path).read lines()
            # next two lines all on one
            starts = [i for i, line in enumerate(lines ) if
            line.startswith ('(defun')]
            for i, start in enumerate(start s):
            while start > 0 and lines[start-1].startswith(';' ):
            starts[i] = start = start-1
            print starts

            Comment

            • Scott David Daniels

              #7
              Re: requestion regarding regular expression

              BartlebyScriven er wrote:[color=blue]
              > That's it. Thank you! Very instructive.
              >
              > Final:
              >
              > path = "d:/emacs files/emacsinit.txt"
              > lines = open(path).read lines()
              > # next two lines all on one
              > starts = [i for i, line in enumerate(lines ) if
              > line.startswith ('(defun')]
              > for i, start in enumerate(start s):
              > while start > 0 and lines[start-1].startswith(';' ):
              > starts[i] = start = start-1
              > print starts
              >[/color]
              If you don't want to hold the whole file in memory, this gets the
              starts a result at a time:

              def starts(source):
              prelude = None
              for number, line in enumerate(sourc e): # read and number a line
              if line[0] == ';':
              if prelude is None:
              prelude = number # Start of commented region
              # else: this line just extends previous prelude
              else:
              if line.startswith ('(defun'):
              # You could append to a result here, but yield lets
              # the first found one get out straightaway.
              if prelude is None:
              yield number
              else:
              yield prelude
              prelude = None


              path = "d:/emacs files/emacsinit.txt"
              source = open(path)
              try:
              for line in starts(source):
              print line,
              # could just do: print list(starts(sou rce))
              finally:
              source.close()
              print

              --
              -Scott David Daniels
              scott.daniels@a cm.org

              Comment

              • BartlebyScrivener

                #8
                Re: requestion regarding regular expression

                This is very helpful.

                I wasn't the OP. I'm just learning, but I'm on the verge of making my
                own file searching scripts. This will be a huge help. Thanks for
                posting, and especially thanks for the comments in the code. Big help!

                rick

                Comment

                • Kelie

                  #9
                  Re: requestion regarding regular expression

                  Thanks to both of you, Kent and Scott.

                  Comment

                  Working...