2013-05-26 21 views
7

Chcę, aby skrypt Pythona, który tworzy przypisy. Chodzi o to, aby znaleźć wszystkie ciągi sortowania "Some body text.{^}{Some footnote text.}" i zastąpić je "Some body text.^#", gdzie "^#" jest właściwą liczbę przypis. (. Inna część mojego skryptu zajmuje się rzeczywiście drukowanie przypisy na końcu pliku) Aktualny kod używam tego jest:Jak prawidłowo iteracyjne z re.sub() w Pythonie

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) 

Działa to dobrze, ale wydaje się dziwne, aby mieć zadeklarować zmienną (i) poza funkcją create_footnote_numbers i następnie wywołać ją wewnątrz tej funkcji. Pomyślałbym, że coś będzie wewnątrz re, które zwróci numer meczu.

Odpowiedz

10

Wszelkie wymagalne mogą być używane, więc można użyć klasy śledzić numerację:

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) 

Teraz stan licznika jest zawarte w instancji FootnoteNumbers() i self.count będzie za każdym razem, kiedy rozpocząć ustawić na nowo re.sub() uruchom.

+0

Ciekawe, dziękuję. Dlaczego masz 'start =' w swoim 'def __init __()'? Dlaczego po prostu tego nie pomijać, a następnie utworzyć 'self.count = 1' w' __init __() '? Przepraszam, jeśli to głupie pytanie --- wciąż próbuję zrozumieć, jak klasy działają w Pythonie. – Alan

+0

@Alan: Teraz możesz zrobić "FootnoteNumbers (10)", a twój pierwszy przypis otrzyma ten numer. To miły dodatkowy kawałek elastyczności; możesz to pominąć, jeśli chcesz. –

+0

Och, bardzo miło. Dziękuję Ci. – Alan

3

Wydaje się, że dobrym rozwiązaniem dla 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

Ale nie '' count' make_footnote_counter' zresetować do '[start - 1]' za każdym razem był nazywany (ponieważ jesteśmy definiowania go wewnątrz 'make_footnote_counter')? Dlaczego nie dałoby mi to "za każdym razem" '? Możliwe, że rozumiem, jak działają zamknięcia. Dzięki. – Alan

+0

@Alan: 're.sub()' wywołuje funkcję 'footnote_counter', która jest zwracana przez pojedyncze wywołanie' make_footnote_counter() '. 'count' jest zachowane między wywołaniami do' footnote_counter'. Kliknij link w odpowiedzi, aby zobaczyć inne przykłady. – jfs

3

Odmianą i Python-3-jedynie rozwiązanie:

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) 
Powiązane problemy