简体   繁体   中英

More efficient and general way to prepend text before lines of a file?

I am new to python. In one of task I have to add a character before specific lines.For example, in my text file the

Name

and

Surname

are the fixed lines on which I have to either add or delete ; based on flag

hey : see
;Name:blah
;Surname:blah

This is the code I have written for the same... Is it efficient enough? Can we write more efficient and can we pass

Name and Surname

as arguments I mean the keywords as an arguments to the function to which add

;

def changefile(filepath,flag):
   # flag = 1
    final = ""
    with open(filepath) as content:
        for line in content:
            if flag==1:
                if line.split(":")[0]==";Name" or line.split(":")[0]==";Surname":
                    final += line[1:]
                else:
                    final += line
            else:
                if line.split(":")[0]=="Name" or line.split(":")[0]=="Surname":
                    final += ";"
                final += line
    f = open(filepath, 'r+')
    f.truncate()
    f.write(final)
    f.close()


changefile("abc.txt",0)

I poked at it a lot, and borrowed martineau's ideas, and ended up with this:

def change_file(filepath, add_comment, trigger_words):

    def process(line):
        line_word = line.lstrip(';').split(':')[0]

        if line_word in trigger_words:
            if add_comment:
                line = line if line.startswith(';') else ';' + line
            else:
                line = line.lstrip(';')

        return line


    with open(filepath) as f:
        content = [process(line) for line in f]


    with open(filepath, 'r+') as f:
        f.truncate()
        f.write(''.join(content))


change_file('abc.txt', add_comment=True, trigger_words=["sys", "netdev"])

The main "nice" bit (that I like) is using a list comprehension [process(line) for line in f] , because it does away with the whole final = ''; final += blah final = ''; final += blah arrangement. It processes every line and that's the output.

I've changed the flag so instead of reading " flag is 0 or 1 " (what does that mean?) it now reads " add_comment is True or False ", to more clearly indicate what it does.

In terms of efficiency, it could be better; (make "trigger_words" a set so that testing membership was faster, change the way it normalizes every line for testing); but if you're processing a small file it won't make much difference Python is fast enough, and if you're processing an enormous file, it's more likely IO limited than CPU limited.

Try it online here: https://repl.it/CbTo/0 (it reads, and prints the results, it doesn't try to save).

(NB. .lstrip(';') will remove all semicolons at the start of the line, not just one. I'm assuming there's only one).


Edit from the comments. Here's a version which will process the SQL Server UTF-16 install file without screwing it up, however I don't know of a general fix for this that will work for all files. Note this reads the file as a specific data encoding, and writes a binary file with a specific data encoding. And changes the split to = for the SQL ini format. And doesn't truncate because w mode does that.

import codecs

def change_file(filepath, add_comment, trigger_words):

    def process(line):
        line_word = line.lstrip(';').split('=')[0]

        if line_word in trigger_words:
            if add_comment:
                line = line if line.startswith(';') else ';' + line
            else:
                line = line.lstrip(';')

        return line


    with codecs.open(filepath, encoding='utf-16') as f:
        content = [process(line) for line in f]

    with codecs.open(filepath, 'wb', encoding='utf-16') as f:
        f.write(''.join(content))


change_file('d:/t/ConfigurationFile - Copy.ini', add_comment=True, trigger_words=["ACTION", "ENU"])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM