2013-05-26 3 views
7

Ich möchte ein Python-Skript erstellen, das Fußnoten erstellt. Die Idee ist, alle Zeichenfolgen der Art "Some body text.{^}{Some footnote text.}" zu finden und sie durch "Some body text.^#" zu ersetzen, wobei "^#" die richtige Fußnotennummer ist. (. Ein anderer Teil meines Skript beschäftigt sich mit den Ausdruck tatsächlich die Fußnoten am Ende der Datei) Der aktuelle Code, den ich dafür bin mit ist:Wie ich mit re() in Python richtig iterieren kann

pattern = r"\{\^\}\{(.*?)\}" 
i = 0 
def create_footnote_numbers(match): 
    global i 
    i += 1 
    return "<sup>"+str(i)+"</sup>" 

new_body_text = re.sub(pattern, create_footnote_numbers, text) 

Dies funktioniert gut, aber es scheint seltsam zu haben eine Variable (i) außerhalb der create_footnote_numbers-Funktion deklarieren und dann innerhalb dieser Funktion aufrufen müssen. Ich hätte gedacht, dass es etwas in re geben würde, das die Nummer des Spiels zurückgeben würde.

Antwort

10

Jede aufrufbar verwendet werden kann, so dass Sie eine Klasse verwenden, könnten die Nummerierung zu verfolgen:

class FootnoteNumbers(object): 
    def __init__(self, start=1): 
     self.count = start - 1 

    def __call__(self, match): 
     self.count += 1 
     return "<sup>{}</sup>".format(self.count) 


new_body_text = re.sub(pattern, FootnoteNumbers(), text) 

nun der Zählerstand in der FootnoteNumbers() Instanz enthalten ist, und self.count wird jedes Mal neu Sie beginnen eingestellt werden re.sub() laufen.

+0

Interessant, danke. Warum hast du 'start =' in deinem 'def __init __()'? Warum nicht einfach das weglassen und dann 'self.count = 1 'in dem' __init __() 'machen? Entschuldigung, wenn das eine dumme Frage ist --- Ich versuche immer noch herauszufinden, wie Klassen in Python funktionieren. – Alan

+0

@Alan: Jetzt können Sie 'FußnotenNummern (10)' tun und Ihre erste Fußnote wird diese Nummer erhalten. Es ist ein nettes Extra an Flexibilität; Sie können das weglassen, wenn Sie möchten. –

+0

Oh, sehr nett. Vielen Dank. – Alan

3

Es scheint wie eine gute Passform für a closure:

def make_footnote_counter(start=1): 
    count = [start - 1] # emulate nonlocal keyword 
    def footnote_counter(match): 
     count[0] += 1 
     return "<sup>%d</sup>" % count[0] 
    return footnote_counter 

new_body_text = re.sub(pattern, make_footnote_counter(), text) 
+0

Aber 'make_footnote_counter' würde nicht' count' auf '[start-1]' jedes Mal zurücksetzen, wenn es aufgerufen wurde (da wir es in 'make_footnote_counter' definieren)? Warum sollte mir das nicht einfach jedes Mal '' geben? Es ist möglich, dass ich verstehe, wie Schließungen funktionieren. Vielen Dank. – Alan

+0

@Alan: 're()' ruft die Funktion "footnote_counter" auf, die von einem einzigen Aufruf 'make_footnote_counter()' zurückgegeben wird. 'count' ist beibehalten zwischen Aufrufen von' footnote_counter'. Folgen Sie dem Link in der Antwort, um weitere Beispiele zu sehen. – jfs

3

Eine Variation und Python-3-only Lösung:

def make_create_footnote_numbers(start=1): 
    count = start - 1 
    def create_footnote_numbers(match): 
     nonlocal count 
     count += 1 
     return "<sup>{}</sup>".format(count) 
    return create_footnote_numbers 

new_body_text = re.sub(pattern, make_create_footnote_numbers(), text)