2011-01-24 24 views
10

Próbuję zastąpić tekst w pliku tekstowym, czytając każdą linię, testując ją, a następnie wpisując, czy ma być aktualizowany. NIE chcę zapisywać jako nowego pliku, ponieważ mój skrypt najpierw tworzy kopie zapasowe plików i działa na kopiach zapasowych.Jak zamienić (zaktualizować) tekst w linii pliku po linii

Oto co mam tak daleko ... I dostać fpath z os.walk() i gwarantuję, że pathmatch var zwraca poprawnie:

fpath = os.path.join(thisdir, filename) 
with open(fpath, 'r+') as f: 
    for line in f.readlines(): 
     if '<a href="' in line: 
      for test in filelist: 
       pathmatch = file_match(line, test) 
        if pathmatch is not None: 
         repstring = filelist[test] + pathmatch 
         print 'old line:', line 
         line = line.replace(test, repstring) 
         print 'new line:', line 
         f.write(line) 

Ale co kończy się dzieje jest to, że tylko dostać kilka wierszy (zaktualizowano poprawnie, pamiętaj, ale powtórzono z wcześniejszych w pliku) poprawiono. Myślę, że to kwestia określania zakresu, afaict.

* Chciałbym również wiedzieć, jak zastąpić tekst tylko w pierwszej instancji meczu, np. Nie chcę dopasować tekstu wyświetlanego, tylko ukrytego href.

+1

Czy bierzesz pod uwagę po prostu za pomocą 'sed' zamiast? – Amber

+0

http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 –

+0

@Amber: In ways. Naprawdę chcę to zakończyć i nauczyć się sed później. Już prawie skończyłem z tym ... :) – jml

Odpowiedz

9

Po pierwsze, chcesz napisać wiersz, czy pasuje do wzorca, czy nie. W przeciwnym razie wypiszesz tylko dopasowane linie.

Po drugie, między odczytaniem linii i zapisaniem wyników, należy albo skrócić plik (można f.seek(0), następnie f.truncate()), albo zamknąć oryginał i ponownie otworzyć. Zbieranie tych pierwszych, ja skończyć z czymś takim:

fpath = os.path.join(thisdir, filename) 
with open(fpath, 'r+') as f: 
    lines = f.readlines() 
    f.seek(0) 
    f.truncate() 
    for line in lines: 
     if '<a href="' in line: 
      for test in filelist: 
       pathmatch = file_match(line, test) 
        if pathmatch is not None: 
         repstring = filelist[test] + pathmatch 
         line = line.replace(test, repstring) 
     f.write(line) 
+0

bardzo pomocna ... dzięki tonom. jedną dziwną rzeczą jest to, że wydawało się, że "prawie" działa za pierwszym razem, a następnie uruchomiłem ją ponownie i nie robi żadnej wymiany ... żadnych myśli? Mogę spróbować go wyśledzić ... – jml

+0

nevermind ... znalazłem problem. Dzięki wielkie!! – jml

+0

cześć ponownie raph: trochę zmodyfikowałem moje pytanie - czy byłbyś tak uprzejmy, aby wyjaśnić mi, jak zaktualizować kod, aby umożliwić ten typ wymiany pojedynczego meczu? dzięki ... – jml

9
  1. Otwórz plik do odczytu i skopiować wszystkie linie w pamięci. Zamknij plik.
  2. Zastosuj transformacje na liniach w pamięci.
  3. Otwórz plik do zapisu i zapisz wszystkie wiersze tekstu w pamięci.

with open(filename, "r") as f: 
    lines = (line.rstrip() for line in f) 
    altered_lines = [some_func(line) if regex.match(line) else line for line in lines] 
with open(filename, "w") as f: 
    f.write('\n'.join(altered_lines) + '\n') 
+0

dzięki za sugestię alt hugh, ale myślę, że podoba mi się pierwsze rozwiązanie lepiej pod względem dopasowania do mojej próby. – jml

1

A (stosunkowo) bezpieczny sposób zastąpić linię w pliku.

#!/usr/bin/python 
# defensive programming style 
# function to replace a line in a file 
# and not destroy data in case of error 

def replace_line(filepath, oldline, newline): 
    """ 
    replace a line in a temporary file, 
    then copy it over into the 
    original file if everything goes well 

    """ 

# quick parameter checks 
    assert os.exists(filepath)   # ! 
    assert (oldline and str(oldline)) # is not empty and is a string 
    assert (newline and str(newline)) 

    replaced = False 
    written = False 

    try: 

    with open(filepath, 'r+') as f: # open for read/write -- alias to f  

     lines = f.readlines()   # get all lines in file 

     if oldline not in lines: 
      pass       # line not found in file, do nothing 

     else: 
     tmpfile = NamedTemporaryFile(delete=True) # temp file opened for writing 

     for line in lines:   # process each line 
      if line == oldline:  # find the line we want 
      tmpfile.write(newline) # replace it 
      replaced = True 
      else: 
      tmpfile.write(oldline) # write old line unchanged 

     if replaced:     # overwrite the original file  
      f.seek(0)     # beginning of file 
      f.truncate()     # empties out original file 

      for tmplines in tmpfile: 
      f.write(tmplines)   # writes each line to original file 
      written = True 

     tmpfile.close()    # tmpfile auto deleted  
     f.close()       # we opened it , we close it 

    except IOError, ioe:     # if something bad happened. 
    printf ("ERROR" , ioe) 
    f.close()       
    return False 

    return replaced and written  # replacement happened with no errors = True 

(uwaga: ta zastępuje całe linie tylko, a wszystkie linie pasujących do pliku)

Powiązane problemy