Halbwegs einfachen Ausdruck finden möglichst ohne re?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

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.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

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
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

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...
Antworten