Code: Alles auswählen
import re
txt = "bla bla %(test1)s und bla %(test2)s xyz %(test3)s"
print re.findall(r"%\(.*?\)s", txt)
Code: Alles auswählen
['%(test1)s', '%(test2)s', '%(test3)s']
Code: Alles auswählen
import re
txt = "bla bla %(test1)s und bla %(test2)s xyz %(test3)s"
print re.findall(r"%\(.*?\)s", txt)
Code: Alles auswählen
['%(test1)s', '%(test2)s', '%(test3)s']
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()
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.Joghurt hat geschrieben:
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"
}
)
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']
Jein... Deine Funktioniert aber nur, wenn in txt und in t die Format-String richtig geschrieben und vollständig erhalten sind...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"henning hat geschrieben:Ich finde meine Version schöner
Code: Alles auswählen
# Schauen ob Datei existiert
if os.path.isfile(datei):
file = open(datei)
... etc ...
else:
print "Datei nicht gefunden
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:Joghurt hat geschrieben:besserCode: Alles auswählen
try: file = open(datei) ... etc ... except: print "Fehler beim lesen"
Code: Alles auswählen
open = "bla"
try:
f = open(datei)
... etc ...
except IOError:
print "Fehler beim lesen"
Code: Alles auswählen
import sys
def test(content, page_dict):
try:
print content % page_dict
except Exception, e:
import re
content_placeholder = []
for i in re.findall(r"%\((.*?)\)s", content):
if not i in content_placeholder:
content_placeholder.append(i)
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'. \n\
*** %s placeholder in internal page: %s \n\
*** %s given placeholder for that page: %s \n\
*** diff: %s" % (
sys.exc_info()[0], e, internal_page_name,
len(content_placeholder), content_placeholder,
len(given_placeholder), given_placeholder,
diff_placeholders
)
)
internal_page_name = "KeinName"
test(
content = "Bla %(platzhalter1)s blup %<-FEHLER..",
page_dict = {
"platzhalter1": "jau",
}
)
Code: Alles auswählen
Exception: exceptions.TypeError: 'not enough arguments for format string': Can't fill internal page 'KeinName'.
*** 1 placeholder in internal page: ['platzhalter1']
*** 1 given placeholder for that page: ['platzhalter1']
*** diff: []
Code: Alles auswählen
import re
txt = """Soll auf alle %-Zeichen treffen, außer %(Beispiel)s und %%
Wobei ein %% quasi Escaped ist.
Soll aber auch auf %(nicht abgeschossene Klammern treffen...
"""
class FindKeys:
def __init__(self, txt):
pattern = re.compile(r"([^%]%[^%(])")
pattern.sub(self.handle, txt)
def handle(self, matchobj):
print matchobj
print matchobj.pos
print matchobj.group(0)
FindKeys(txt)
Code: Alles auswählen
class Find_StringOperators:
"""
Sucht in einem String nach %-StringOperatoren.
Dabei wird zwischen richtigen und falschen unterschieden.
Dient zur besseren Fehlerausgabe, bei String Operationen.
Test-Text:
----------
Hier ist ein Beispieltext mit %(richtigen)s Platzhaltern.
Aber auch mit %(falschen, da die hier Klammer nicht geschlossen ist.
Außerdem müßen einzelne %-Zeichen, immer escaped werden. Das wird
mit doppelten %% Zeichen gemacht, die nach dem String-Operation,
bei dem die %(Platzhalter)s durch Daten aus einem Dict ersetzt werden,
wieder zu einfachen %-Zeichen umgewandelt werden.
"""
cutout = 20
def __init__(self, txt):
self.correct_hit_pos = []
self.incorrect_hit_pos = []
self.txt = txt
# alle %-Zeichen, die nicht mit %%-Escaped sind
pattern = re.compile(r"([^%]%[^%])")
pattern.sub(self._incorrect_hit, txt)
# Richtig %(formatierte)s String
pattern = re.compile(r"([^%]%\(.*?\)s)")
pattern.sub(self._correct_hit, txt)
def _incorrect_hit(self, matchobj):
self.incorrect_hit_pos.append(matchobj.start())
def _correct_hit(self, matchobj):
self.incorrect_hit_pos.remove(matchobj.start())
self.correct_hit_pos.append(matchobj.start())
#_______________________________________________________________________
# Zugriff auf die Daten
def get_incorrect_pos(self):
"Start- & End-Liste der falschen %-Operatoren"
return self.get_pos(self.incorrect_hit_pos)
def get_correct_pos(self):
"Start- & End-Liste der richtigen %-Operatoren"
return self.get_pos(self.correct_hit_pos)
def get_pos(self, poslist):
"""
Wandelt aus der Positionsliste eine Liste mit
Start- und End-Positionen für einen Text-Slice
"""
results = []
for pos in poslist:
start = pos - self.cutout
end = pos + self.cutout
if start<0:
start = 0
if end>len(self.txt):
end = len(self.txt)
results.append((start, end))
return results
def slice_pos_list(self, pos_list):
"""
Liefert eine Liste der Textstellen zurück.
"""
result = []
for start,end in pos_list:
result.append(
"...%s..." % self.txt[start:end].encode("String_Escape")
)
return result
#_______________________________________________________________________
# Debug
def debug_results(self):
print "self.incorrect_hit_pos:", self.incorrect_hit_pos
print "incorrect_pos:", self.get_incorrect_pos()
print ">>> Textstellen mit falsche %-Zeichen im Text:"
for i in self.slice_pos_list(self.get_incorrect_pos()):
print i
print
print "self.correct_hit_pos:", self.correct_hit_pos
print "correct_pos:", self.get_correct_pos()
print ">>> Textstellen mit richtige %-StringOperatoren:"
for i in self.slice_pos_list(self.get_correct_pos()):
print i
doc = Find_StringOperators.__doc__
print doc
print "-"*80
s = Find_StringOperators(doc)
print "incorrect_pos:", s.get_incorrect_pos()
print "correct_pos:", s.get_correct_pos()
print "-"*80
s.debug_results()
Sucht in einem String nach %-StringOperatoren.
Dabei wird zwischen richtigen und falschen unterschieden.
Dient zur besseren Fehlerausgabe, bei String Operationen.
Test-Text:
----------
Hier ist ein Beispieltext mit %(richtigen)s Platzhaltern.
Aber auch mit %(falschen, da die hier Klammer nicht geschlossen ist.
Außerdem müßen einzelne %-Zeichen, immer escaped werden. Das wird
mit doppelten %% Zeichen gemacht, die nach dem String-Operation,
bei dem die %(Platzhalter)s durch Daten aus einem Dict ersetzt werden,
wieder zu einfachen %-Zeichen umgewandelt werden.
--------------------------------------------------------------------------------
incorrect_pos: [(11, 51), (267, 307), (353, 393), (563, 603)]
correct_pos: [(221, 261), (480, 520)]
--------------------------------------------------------------------------------
self.incorrect_hit_pos: [31, 287, 373, 583]
incorrect_pos: [(11, 51), (267, 307), (353, 393), (563, 603)]
>>> Textstellen mit falsche %-Zeichen im Text:
...in einem String nach %-StringOperatoren....
...n.\n Aber auch mit %(falschen, da die ...
...dem m\xc3\xbc\xc3\x9fen einzelne %-Zeichen, immer es...
... wieder zu einfachen %-Zeichen umgewande...
self.correct_hit_pos: [241, 500]
correct_pos: [(221, 261), (480, 520)]
>>> Textstellen mit richtige %-StringOperatoren:
...ein Beispieltext mit %(richtigen)s Platz...
...ion,\n bei dem die %(Platzhalter)s dur...
Code: Alles auswählen
def fill_string_context(self, internal_page_name, content, context):
"""
Mach die Python-String-Operation. Wenn ein key im context fehlt, wird
der Fehler mit page_msg ausgegeben, gleichzeitig wird der fehlende Key
in den context eingefügt und nochmals probiert...
"""
try:
return content % context
except KeyError, key:
key = key[0]
self.page_msg(
"Key-Error: '%s' in internal page '%s'!" % (
key, internal_page_name
)
)
context[key] = "" # Fehlenden Key im context einfügen
# String-Operation nochmals versuchen:
content = self.fill_string_context(
internal_page_name, content, context
)
return content
Code: Alles auswählen
class PlaceholderMissmatch(Exception):
def __init__(self, required, found, diff):
self.required = required
self.found = found
self.diff = diff
Exception.__init__(self, 'required: %s; found: %s; diff: %s' % (
', '.join(required), ', '.join(found), ', '.join(diff)
))
def test(s, page_dict):
found = []
class FakeMap(object):
def __getitem__(self, name):
found.append(name)
return ''
s % FakeMap()
required = page_dict.keys()
if found != required:
diff = set(found).intersection(set(required))
raise PlaceholderMissmatch(required, found, sorted(diff))
test(
'Bla %(platzhalter1)s blup %(Platzhalter2)s...',
{
"platzhalter1": "jau",
"PPPaltzhalter": "Fehler"
}
)