Αναζήτηση και αντικατάσταση μιας γραμμής σε ένα αρχείο σε Python

ψήφοι
223

Θέλω να βρόχο πάνω από τα περιεχόμενα ενός αρχείου κειμένου και να κάνετε μια αναζήτηση και αντικατάσταση σε ορισμένες γραμμές και να γράψει το αποτέλεσμα πίσω στο αρχείο. Θα μπορούσα πρώτη φορτώσει ολόκληρο το αρχείο στη μνήμη και στη συνέχεια να το γράψετε πίσω, αλλά αυτό μάλλον δεν είναι ο καλύτερος τρόπος για να το κάνουμε.

Ποιος είναι ο καλύτερος τρόπος για να γίνει αυτό, εντός των επόμενων κωδικό;

f = open(file)
for line in f:
    if line.contains('foo'):
        newline = line.replace('foo', 'bar')
        # how to write this newline back to the file
Δημοσιεύθηκε 02/09/2008 στις 08:19
πηγή χρήστη
Σε άλλες γλώσσες...                            


14 απαντήσεις

ψήφοι
3

Δημιουργήστε ένα νέο αρχείο, αντιγράψετε γραμμές από το παλιό στο νέο, και να κάνει την αντικατάσταση προτού να γράψετε τις γραμμές στο νέο αρχείο.

Απαντήθηκε 02/09/2008 στις 08:24
πηγή χρήστη

ψήφοι
147

Υποθέτω ότι κάτι τέτοιο πρέπει να το κάνουμε. Γράφει ουσιαστικά το περιεχόμενο σε ένα νέο αρχείο και αντικαθιστά το παλιό αρχείο με το νέο αρχείο:

from tempfile import mkstemp
from shutil import move
from os import fdopen, remove

def replace(file_path, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    with fdopen(fh,'w') as new_file:
        with open(file_path) as old_file:
            for line in old_file:
                new_file.write(line.replace(pattern, subst))
    #Remove original file
    remove(file_path)
    #Move new file
    move(abs_path, file_path)
Απαντήθηκε 02/09/2008 στις 08:42
πηγή χρήστη

ψήφοι
10

Όπως υποδηλώνει lassevk, γράψτε το νέο αρχείο όπως πάτε, εδώ είναι μερικά παράδειγμα κώδικα:

fin = open("a.txt")
fout = open("b.txt", "wt")
for line in fin:
    fout.write( line.replace('foo', 'bar') )
fin.close()
fout.close()
Απαντήθηκε 02/09/2008 στις 08:42
πηγή χρήστη

ψήφοι
223

Η συντομότερη διαδρομή θα μπορούσε πιθανότατα να είναι η χρήση της μονάδας fileinput . Για παράδειγμα, η ακόλουθη προσθέτει αριθμούς γραμμών σε ένα αρχείο, επί τόπου:

import fileinput

for line in fileinput.input("test.txt", inplace=True):
    print "%d: %s" % (fileinput.filelineno(), line),

Αυτό που συμβαίνει εδώ είναι:

  1. Το αρχικό αρχείο μετακινείται σε ένα αρχείο αντιγράφου ασφαλείας
  2. Η τυπική έξοδο ανακατευθύνεται προς το αρχικό αρχείο εντός του βρόχου
  3. Έτσι, τυχόν printδηλώσεις γράψετε πίσω στο αρχικό αρχείο

fileinputέχει περισσότερα κουδούνια και σφυρίχτρες. Για παράδειγμα, μπορεί να χρησιμοποιηθεί για να λειτουργήσει αυτόματα όλα τα αρχεία sys.args[1:], χωρίς να χρειάζεται να μετακινηθείτε πάνω τους ρητά. Ξεκινώντας με την Python 3.2 παρέχει επίσης μια βολική διευθυντή πλαίσιο για χρήση σε μια withδήλωση.


Ενώ fileinputείναι μεγάλη για μιας χρήσης σενάρια, θα ήθελα να είναι δύσπιστοι όσον αφορά τη χρήση του σε πραγματικό κώδικα, διότι κατά γενική ομολογία δεν είναι πολύ ευανάγνωστη ή εξοικειωμένοι. Σε πραγματικό κώδικα (παραγωγή) αξίζει τον κόπο να περάσετε μόνο μερικές ακόμα γραμμές κώδικα για να κάνει τη διαδικασία σαφή και έτσι κάνουν το κωδικό αναγνώσιμο.

Υπάρχουν δύο επιλογές:

  1. Το αρχείο δεν είναι υπερβολικά μεγάλο, και μπορείτε να το διαβάσετε μόνο εξ ολοκλήρου στη μνήμη. Στη συνέχεια, κλείστε το αρχείο, ανοίξτε το ξανά σε λειτουργία εγγράφως και να γράψει τα τροποποιημένα περιεχόμενο πίσω.
  2. Το αρχείο είναι πολύ μεγάλο για να αποθηκευτεί στη μνήμη? μπορείτε να το μετακινήσετε πάνω σε ένα προσωρινό αρχείο και ανοίξτε ότι, ανάγνωση γραμμή προς γραμμή, γράφοντας πίσω στο αρχικό αρχείο. Σημειώστε ότι αυτό απαιτεί δύο φορές την αποθήκευση.
Απαντήθηκε 14/11/2008 στις 14:47
πηγή χρήστη

ψήφοι
65

Εδώ είναι ένα άλλο παράδειγμα που εξετάστηκε, και θα αντιστοιχούν στην αναζήτηση & αντικατάσταση πρότυπα:

import fileinput
import sys

def replaceAll(file,searchExp,replaceExp):
    for line in fileinput.input(file, inplace=1):
        if searchExp in line:
            line = line.replace(searchExp,replaceExp)
        sys.stdout.write(line)

Παράδειγμα χρήσης:

replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")
Απαντήθηκε 24/11/2008 στις 18:02
πηγή χρήστη

ψήφοι
49

Αυτό θα πρέπει να εργαστεί: (μοντάζ επι τόπου)

import fileinput

# Does a list of files, and
# redirects STDOUT to the file in question
for line in fileinput.input(files, inplace = 1): 
      print line.replace("foo", "bar"),
Απαντήθηκε 07/09/2009 στις 09:07
πηγή χρήστη

ψήφοι
0

εάν αφαιρέσετε την περίπτωση, στο κάτω, όπως, θα αναζητήσετε και να αντικαταστήσετε σε πολλές γραμμές. Δείτε παρακάτω για παράδειγμα.

def replace(file, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    print fh, abs_path
    new_file = open(abs_path,'w')
    old_file = open(file)
    for line in old_file:
        new_file.write(line.replace(pattern, subst))
    #close temp file
    new_file.close()
    close(fh)
    old_file.close()
    #Remove original file
    remove(file)
    #Move new file
    move(abs_path, file)
Απαντήθηκε 02/08/2012 στις 18:12
πηγή χρήστη

ψήφοι
18

Με βάση την απάντηση από τον Thomas Watnedal. Ωστόσο, αυτό δεν απαντήσει το μέρος του αρχικού ερωτήματος γραμμή προς γραμμή ακριβώς. Η λειτουργία μπορεί ακόμα να αντικαταστήσει με βάση γραμμή προς γραμμή

Αυτή η εφαρμογή αντικαθιστά τα περιεχόμενα του αρχείου χωρίς τη χρήση προσωρινά αρχεία, όπως ένα άδειες αρχείων συνέπεια παραμένουν αμετάβλητες.

Επίσης re.sub αντί να αντικαταστήσει, επιτρέπει την αντικατάσταση regex αντί για αντικατάσταση απλό κείμενο μόνο.

Διαβάζοντας το αρχείο ως ένα ενιαίο κορδόνι αντί για γραμμή προς γραμμή επιτρέπει πολλών γραμμών αγώνα και την αντικατάσταση.

import re

def replace(file, pattern, subst):
    # Read contents from file as a single string
    file_handle = open(file, 'r')
    file_string = file_handle.read()
    file_handle.close()

    # Use RE package to allow for replacement (also allowing for (multiline) REGEX)
    file_string = (re.sub(pattern, subst, file_string))

    # Write contents to file.
    # Using mode 'w' truncates the file.
    file_handle = open(file, 'w')
    file_handle.write(file_string)
    file_handle.close()
Απαντήθηκε 30/11/2012 στις 06:51
πηγή χρήστη

ψήφοι
6

Μια πιο pythonic τρόπος θα ήταν να χρησιμοποιήσετε διαχειριστές πλαίσιο όπως το παρακάτω κώδικα:

from tempfile import mkstemp
from shutil import move
from os import remove

def replace(source_file_path, pattern, substring):
    fh, target_file_path = mkstemp()
    with open(target_file_path, 'w') as target_file:
        with open(source_file_path, 'r') as source_file:
            for line in source_file:
                target_file.write(line.replace(pattern, substring))
    remove(source_file_path)
    move(target_file_path, source_file_path)

Μπορείτε να βρείτε το πλήρες απόσπασμα εδώ .

Απαντήθηκε 07/09/2013 στις 17:39
πηγή χρήστη

ψήφοι
9

Αν θέλουν μια γενική λειτουργία που αντικαθιστά οποιοδήποτε κείμενο με κάποιο άλλο κείμενο, αυτό είναι πιθανόν ο καλύτερος τρόπος να πάει, ειδικά αν είστε fan των regex είναι:

import re
def replace( filePath, text, subs, flags=0 ):
    with open( filePath, "r+" ) as file:
        fileContents = file.read()
        textPattern = re.compile( re.escape( text ), flags )
        fileContents = textPattern.sub( subs, fileContents )
        file.seek( 0 )
        file.truncate()
        file.write( fileContents )
Απαντήθηκε 18/02/2014 στις 12:43
πηγή χρήστη

ψήφοι
1

Χρησιμοποιώντας απάντηση hamishmcn ως πρότυπο ήμουν σε θέση να αναζητήσετε μια γραμμή σε ένα αρχείο που αντιστοιχεί στην τυπική έκφραση και την αντικατάστασή της με την κενή συμβολοσειρά μου.

import re 

fin = open("in.txt", 'r') # in file
fout = open("out.txt", 'w') # out file
for line in fin:
    p = re.compile('[-][0-9]*[.][0-9]*[,]|[-][0-9]*[,]') # pattern
    newline = p.sub('',line) # replace matching strings with empty string
    print newline
    fout.write(newline)
fin.close()
fout.close()
Απαντήθηκε 17/04/2014 στις 01:13
πηγή χρήστη

ψήφοι
3

Επέκταση σε @ απάντηση Kiran, το οποίο συμφωνώ είναι πιο σύντομη και Pythonic, αυτό προσθέτει codecs για να υποστηρίξει την ανάγνωση και τη γραφή του UTF-8:

import codecs 

from tempfile import mkstemp
from shutil import move
from os import remove


def replace(source_file_path, pattern, substring):
    fh, target_file_path = mkstemp()

    with codecs.open(target_file_path, 'w', 'utf-8') as target_file:
        with codecs.open(source_file_path, 'r', 'utf-8') as source_file:
            for line in source_file:
                target_file.write(line.replace(pattern, substring))
    remove(source_file_path)
    move(target_file_path, source_file_path)
Απαντήθηκε 02/05/2014 στις 10:15
πηγή χρήστη

ψήφοι
0

Για τους χρήστες του Linux:

import os
os.system('sed -i \'s/foo/bar/\' '+file_path)
Απαντήθηκε 28/05/2018 στις 17:19
πηγή χρήστη

ψήφοι
0

fileinput είναι αρκετά απλή, όπως αναφέρθηκε σε προηγούμενες απαντήσεις:

import fileinput

def replace_in_file(file_path, search_text, new_text):
    with fileinput.input(file_path, inplace=True) as f:
        for line in f:
            new_line = line.replace(search_text, new_text)
            print(new_line, end='')

Εξήγηση:

  • fileinputμπορεί να δεχτεί πολλαπλά αρχεία, αλλά εγώ προτιμώ να κλείσει κάθε μεμονωμένο αρχείο από τη στιγμή που είναι υπό επεξεργασία. Έτσι, τοποθετούνται μόνο file_pathσε withδήλωση.
  • printδήλωση δεν εκτυπώνεται τίποτα όταν inplace=True, λόγω STDOUTδιαβιβάζεται στο αρχικό αρχείο.
  • end=''στη printδήλωση είναι η εξάλειψη ενδιάμεσο κενό νέες γραμμές.

Μπορεί να χρησιμοποιηθεί ως εξής:

file_path = '/path/to/my/file'
replace_in_file(file_path, 'old-text', 'new-text')
Απαντήθηκε 03/10/2019 στις 12:37
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more