Seite 1 von 1

Halbwegs einfachen Ausdruck finden möglichst ohne re?

Verfasst: Freitag 21. Oktober 2005, 07:34
von henning
Wie kann ich am schnellsten einen Docstring nach einem Ausdruck der Form "<<XXX>>" durchsuchen, wobei XXX ein unbekannter String ist (welche natürlich nicht ">>" enthält) und nicht bekannt ist, ob der Docstring meinen Ausdruck überhaupt enthält?

Ist es in dem Fall schneller mit re's oder mit string-eigenen Funktionen?
Das "<<" und ">>"-Geraffel kann ich auch beliebig ändern, ich will nur einen bestimmten String innerhalb meines Docstrings markieren, so dass ich ihn mit möglichst wenig Laufzeitaufwand wieder rausfischen kann.

Verfasst: Freitag 21. Oktober 2005, 08:46
von jens
In PyLucid gibt es den sourcecode_parser.py:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

"""
Source Code Parser

Based on J&#56551;en Hermann's "MoinMoin - Python Source Parser"
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298/
"""

__version__="0.2.0"

__history__="""
v0.2.0
    - Einige Optimierungen
    - Bug mit den speziellen Zeilenumbrüche mit \ am ende (kein Zeilenumbruch) behoben
v0.1.0
    - aus SourceCode.py Plugin entnommen, damit er auch f&#56480;tinyTextile genutzt werden kann
"""

import sys, cgi, cStringIO, \
    keyword, token, tokenize

token.KEYWORD = token.NT_OFFSET + 1

class python_source_parser:

    def parse( self, raw_txt ):
        """
        Parse and send the colored source.
        """
        self.special_not_newline = False
        self.raw = raw_txt.expandtabs()

        # store line offsets in self.lines
        self.lines = [0, 0]
        pos = 0
        while 1:
            pos = self.raw.find( '\n', pos ) + 1
            if not pos: break
            self.lines.append( pos )
        self.lines.append( len(self.raw) )

        # parse the source and write it
        self.pos = 0
        text = cStringIO.StringIO( self.raw )

        try:
            tokenize.tokenize(text.readline, self)
        except tokenize.TokenError, ex:
            msg = ex[0]
            line = ex[1][0]
            print "<h3>ERROR: %s</h3>%s\n" % (
                msg, self.raw[self.lines[line]:]
            )

        print "<br />\n"


    def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
        """ Token handler.
        """
        # calculate new positions
        oldpos = self.pos
        newpos = self.lines[srow] + scol
        self.pos = newpos + len(toktext)

        # Patch for special not newline with \
        if line.endswith("\\\n") and toktype!=tokenize.COMMENT:
            self.special_not_newline = True
        elif self.special_not_newline == True:
            self.special_not_newline = False
            print "\\<br />\n"

        # handle newlines
        if toktype in (token.NEWLINE, tokenize.NL):
            sys.stdout.write( '<br />\n' )
            return

        # Spaces
        if newpos > oldpos:
            sys.stdout.write(" " * (newpos-oldpos))

        if toktext=="":
            return

        # map token type to a color group
        if token.LPAR <= toktype and toktype <= token.OP:
            toktype = token.OP
        elif toktype == token.NAME and keyword.iskeyword(toktext):
            toktype = token.KEYWORD

        # Text Escapen
        toktext = cgi.escape( toktext )

        # Non-Breaking-Spaces
        toktext = toktext.replace(" "," ")

        # Zeilenumbrüche umwandeln
        toktext = toktext.replace("\n","<br />\n")

        if toktype==token.NAME:
            sys.stdout.write(toktext)
        else:
            sys.stdout.write('<span class="t%s">%s</span>' % (toktype,toktext))

        #~ print "\n>>>",toktype

if __name__ == '__main__':
    python_source_parser().parse(open(__file__).read())
Wenn du die __call__ Methode umschreibst, kannst du dammit nur DocStrings rausfiltern. Im Weiteren Schritt, kannst du dann nach deinen Markierungen Suche...

Verfasst: Freitag 21. Oktober 2005, 08:55
von mawe
Hi!

Also das Muster rausfiltern würde ich schon mit einer Regex machen. Mit den string-Funktionen fällt mir auf die Schnelle keine Lösung ein, die einfach und schnell sein sollte. Und re's sind ja auch nicht so langsam ;) Schneller programmiert ist auf jedenfall die Version mit re :)

Gruß, mawe

Verfasst: Freitag 21. Oktober 2005, 09:14
von Francesco
Vielleicht so in etwa:

Code: Alles auswählen

a = "ababa<<teststring1>>cbcbc<<teststring2>>dcdc"
lastfoundindex = 0
s1 = '<<'
s2 = '>>'
found = []

while 1:
  lf1 = a.find(s1, lastfoundindex) + len(s1)
  lf2 = a.find(s2, lastfoundindex)
  if lf1 > -1 and lf2 > -1 and lf1 < lf2:
    found.append (a[lf1:lf2])
    lastfoundindex = lf2 + 1
  else:
    break

print "Strings found:" 
for s in found:
  print s

Verfasst: Freitag 21. Oktober 2005, 11:34
von henning
Vielleicht hätte ich dazu sagen sollen, dass der Ausdruck höchstens einmal vorkommen soll, da die docstrings nicht von den endnutzern manipuliert werden kann ich schon davon ausgehen, dass das auch eingehalten wird.
Von daher hätte ich jetzt überlegt, evtl. mit str.find ranzugehen und den linken und rechten delimiter einzeln zu suchen.

Wobei mir gerade in meinem Bsp auffällt, dass ">>" eine ungünstige Wahl ist, wenn z.B. doctest im Spiel ist...