String-Formatter finden...

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

Samstag 1. Oktober 2005, 21:52

Gibt's eine bessere/direktere Möglichkeit an die Platzhalter in einem Text zu kommen, als:

Code: Alles auswählen

import re

txt = "bla bla %(test1)s und bla %(test2)s xyz %(test3)s"

print re.findall(r"%\(.*?\)s", txt)
Ausgabe:

Code: Alles auswählen

['%(test1)s', '%(test2)s', '%(test3)s']

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Samstag 1. Oktober 2005, 22:35

Ich wüsste keine, aber Dein regulärer Ausdruck ist etwas zu einfach wenn Du wirklich alle Platzhalter finden willst. Es ja nicht nur '%s' und man kann noch die Parameter zum formatieren einbauen, also z.B. '%(name)10s %(pi).2f' usw.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Samstag 1. Oktober 2005, 22:37

BlackJack hat geschrieben:Dein regulärer Ausdruck ist etwas zu einfach
Da hast du recht, aber erstmal gibt's bei mir nur die einfache %(name)s Version...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Sonntag 2. Oktober 2005, 08:35

Was meinst du mit einfachere Methode?
Was willst du denn mit den Platzhaltern machen?
Wenn du sie durch Werte ersetzen willst, solltest du natürlich den %-Operator verwenden.

Wenn du nen längeren Text hast und wissen willst, welche Platzhalter darin verlangt werden und du den Text ändern kannst, würde ich eine Template-Engine empfehlen, z.B. cheetah.

Du kannst natürlich auch sowas machen (ungetestet):

Code: Alles auswählen

class FindKey(dict):
  def __init__(self, *args, **kwargs):
     dict.__init__(self, *args, **kwargs)
     self.found_keys = {}
  def __getattr__(self, attr):
     self.found_keys[attr] = True
     return ""

txt = "bla bla %(test1)s und bla %(test2)s xyz %(test3)s"

f = FindKey()
dumy = txt % f
print f.found_keys.keys()
Ich weiß nicht, ob das eleganter oder direkter als ne re ist, aber auf jeden Fall findet es alle Platzhalter.

Achso: Wenn in txt nach was anderem als strings gefragt wird, solltest du bei __getattr__ natürlich was zurückgeben, was sich zumindest problemlos casten lässt.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sonntag 2. Oktober 2005, 11:28

Ich brauche das ganze zum Fehler-Handling. Um besser Anzeigen zu können, wo der Fehler steckt ;)
Ich werd erstmal bei der re-Lösung bleiben, weil's kleiner ist und bisher nur die eine Form %(name)s vorkommt.
Werd aber deine Lösung mal im Hinterkopf behalten, wer weiss...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Sonntag 2. Oktober 2005, 14:51

jens hat geschrieben:Ich brauche das ganze zum Fehler-Handling. Um besser Anzeigen zu können, wo der Fehler steckt ;)
:?: :?:
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sonntag 2. Oktober 2005, 19:33

Joghurt hat geschrieben: :?: :?:
Also es geht natürlich mal wieder um PyLucid. Dort gibt es interne-Seiten, die halt String-Formater als Platzhalter beinhalten. Die Seiten kann der Admin allerdings editieren. Wenn er nun einen String-Formater löscht/umbenennt, funktioniert die internal_page nicht mehr richtig.
In dem Fall ist es hilfreich einen gescheiten Fehler anzuzeigen ;)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 19. Dezember 2005, 17:49

Das ist meine aktuelle Version um bei einem "not enough arguments for format string" Fehler, mehr Informationen auszugeben.

Dabei ist content, ein String mit den String-Formatter-Platzhalter und page_dict das Dict. mit den Angaben:

Code: Alles auswählen

import sys

def test(content, page_dict):
    try:
        print content % page_dict
    except Exception, e:
        import re
        content_placeholder = re.findall(r"%\((.*?)\)s", content)
        content_placeholder.sort()
        given_placeholder = page_dict.keys()
        given_placeholder.sort()
        diff_placeholders = []
        for i in content_placeholder:
            if (not i in given_placeholder) and (not i in diff_placeholders):
                diff_placeholders.append(i)
        for i in given_placeholder:
            if (not i in content_placeholder) and (not i in diff_placeholders):
                diff_placeholders.append(i)
        diff_placeholders.sort()
        raise Exception(
            "%s: '%s': Can't fill internal page '%s'. \
            *** placeholder in internal page: %s *** given placeholder for that page: %s *** diff: %s" % (
                sys.exc_info()[0], e, internal_page_name, content_placeholder, given_placeholder, diff_placeholders
            )
        )

internal_page_name = "KeinName"

test(
    content = "Bla %(platzhalter1)s blup %(Platzhalter2)s...",
    page_dict = {
        "platzhalter1": "jau",
        "PPPaltzhalter": "Fehler"
    }
)
Ausgabe:
Exception: exceptions.KeyError: ''Platzhalter2'': Can't fill internal page 'KeinName'. *** placeholder in internal page: ['Platzhalter2', 'platzhalter1'] *** given placeholder for that page: ['PPPaltzhalter', 'platzhalter1'] *** diff: ['PPPaltzhalter', 'Platzhalter2']

Was mir nicht gefällt sind die beiden for-Schleifen um diff_placeholders zusammen zu bauen...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Montag 19. Dezember 2005, 17:56

Ich finde meine Version schöner ;-)
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 19. Dezember 2005, 18:57

henning hat geschrieben:Ich finde meine Version schöner ;-)
Jein... Deine Funktioniert aber nur, wenn in txt und in t die Format-String richtig geschrieben und vollständig erhalten sind...

Meine *Fehler*abfrage ist aber für den Fall, das halt die Operatoren nicht passen!

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 19. Dezember 2005, 19:02

Eine andere Möglichkeit wäre, str.__mod__ selbst zu implementieren und dort ein anderes Error-Handling zu machen, welches bessere Fehlermeldungen wirft.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Montag 19. Dezember 2005, 19:39

henning hat geschrieben:Ich finde meine Version schöner ;-)
Man sollte allgemein so Programmieren, dass man nicht versucht, die Ursachen für einen Fehler abzufangen (da man immer etwas übersehen kann). Besser ist es, und das ist ja auch die Pythonphilosophie, auf Fehler zu reagieren, und das macht Jens ja. Von daher finde ich seine Lösung auch "eleganter"

Beispiel:

Code: Alles auswählen

# Schauen ob Datei existiert
if os.path.isfile(datei):
  file = open(datei)
  ... etc ...
else:
  print "Datei nicht gefunden
ist schlecht, denn das fängt nicht die Möglichkeit ab, dass die Datei nicht lesbar ist, etc. besser

Code: Alles auswählen

try:
  file = open(datei)
  ... etc ...
except:
  print "Fehler beim lesen"
joe

Montag 19. Dezember 2005, 20:45

Joghurt hat geschrieben:besser

Code: Alles auswählen

try:
  file = open(datei)
  ... etc ...
except:
  print "Fehler beim lesen"
Immer nur ausnahmen abfangen, die man auch erwartet (also IOError beim lesen von dateien). Wenn z.B. open() vorher versehentlich überschrieben wurde, wird man oben mit einer falschen fehlermeldung in die irre geführt. Besser:

Code: Alles auswählen

open = "bla"
try: 
  f = open(datei) 
  ... etc ...
except IOError: 
  print "Fehler beim lesen"
joe
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Montag 19. Dezember 2005, 20:52

Ja, hast ja Recht. Nur wenn jemand schon open überschreibt, kann er sie auch so modifizieren, dass sie bei jeder Exception ein IOError zurückgibt :twisted:
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 20. Dezember 2005, 08:21

Also ich komm irgendwie doch nicht weiter...

Es kommt immer noch zu einem 'not enough arguments for format string' Fehler :( Trotz meiner Fehlermeldung kann ich nicht erkennen woran es liegt :(

Somit ist es vielleicht doch keine schlechte Idee, tiefer anzufangen. d.H. vielleicht den String-Operator direkt zu manipulieren und darin eine Fehlermeldung einzubauen...
Allerdings weiß ich nicht wirklich wo ich ansetzten kann :(

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten