1

Background: I am trying to automate some parts of a work process. Manual steps I take: I get a ticket to change an ID inside a text file. I have to go through a network shared folder, create a backup of the file, push the copied file into an archive folder, and edit the existing file with the ID from the ticket.

What I am trying to create: A small program that will ask me what ID I am wanting to change(there are pre-existing ID's inside the text file) then it will go inside the file and find the match. Then I want the program to ask me what I want to change the ID to. I want the program to edit the existing file with my input, save it, then close it.

So far I have the following code that completes the first portion (copying the file and pushing it into the archive folder). I have the second function which I am stuck on. I know the second function isn't working, but would like input from others on what they think I should try. I have seen the fileinput module, but I have read that it's not the best module and I should try to program this without the fileinput module.

Code:

import shutil
import datetime
import os
import fileinput

original_file = "\\network\\path\\to\\file"

def date_rename_file():
    todays_date = datetime.datetime.now()
    stripped_time = todays_date.strftime('%Y%m%d')    
    shutil.copyfile(original_file, "\\network\\path\\to\\backupfolder\\device_"+str(stripped_time)+".txt")

def device_id_replace():
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(original_file, 'w') as devicetxt:
        for line in devicetxt:
            print(line)
            if original_id in line:
                print("Found "+original_id)

date_rename_file()
device_id_replace()

Thanks, feel free to demolish my code :) I'm still learning and would appreciate any input. Also, feel free to let me know if I left any pertinent information out!

2
  • 1
    Welcome to StackOverflow. Please read and follow the posting guidelines in the help documentation, as suggested when you created this account. Minimal, complete, verifiable example applies here. We cannot effectively help you until you post your MCVE code and accurately describe the problem. We should be able to paste your posted code into a text file and reproduce the problem you described. StackOverflow is not a coding, review, or tutorial resource. Commented Dec 18, 2018 at 22:09
  • 1
    Most of all, "I am stuck" and "isn't working" are not problem specifications. Commented Dec 18, 2018 at 22:09

3 Answers 3

1

You can try this:

def device_id_replace():
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(original_file, 'r+') as devicetxt: #r+ is for read and write
        string = devicetxt.read() #read into one string
        string = string.replace(original_id, new_id) #replacement
        devicetxt.truncate(0) #To clear contents of file before writeback
        devicetxt.seek(0) #Put the file's current position at 0
        devicetxt.write(string) #writeback to file

Also, it is better practice to pass the original_file as a string to the functions. See editted code below:

import shutil
import datetime
import os
import fileinput

original_file = "\\network\\path\\to\\file"

def date_rename_file(filepath):
    todays_date = datetime.datetime.now()
    stripped_time = todays_date.strftime('%Y%m%d')    
    shutil.copyfile(filepath, "\\network\\path\\to\\backupfolder\\device_"+str(stripped_time)+".txt")

def device_id_replace(filepath):
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(filepath, 'r+') as devicetxt: #r+ is for read and write
        string = devicetxt.read() #read into one string
        string = string.replace(original_id, new_id) #replacement
        devicetxt.truncate(0) #To clear contents of file before writeback
        devicetxt.seek(0) #Put the file's current position at 0
        devicetxt.write(string) #writeback to file

date_rename_file(original_file)
device_id_replace(original_file)
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks ycx! This seems to work mostly, but I believe it adds all the content back into the same file so I get duplicate data. Going to work on fixing that. Thanks though, exactly what I was looking for.
@ZookiePookie Thanks for spotting that out. I've added an additional line devicetxt.truncate(0) to fix exactly that problem. It will clear all contents before the writeback so that you do not get duplicate data. Let me know if it helps. Functionally, it is also better to open the file once in a for loop and do read/write than to open it twice in 2 for loops separately to do read, then write.
so I tried the new truncate in my code. It doesn't create duplicates which is good, but it adds a lot of white space into the top of the text file. I will try to debug what step is causing that. Thank you!
if you have time could you explain the comment you made here: "Also, it is better practice to pass the original_file as a string to the functions. See editted code below:" I am trying to understand why we pass parameters into the functions. Also, where does the 'filepath' parameter come from? Any reading you could send link me to to understand that better?
@ZookiePookie To solve the white space problem, I've added a .seek(0) to set the cursor at the file's 0 position. Sorry I missed that out during testing. What happens is that .truncate(0) deletes everything from 0 position, but the cursor is still at the last place it was at. So .seek(0) solves that.
|
1

Try this one:

original_file = ""\\network\\path\\to\\file""

def device_id_replace(filepath):                   
    original_id = input("What device ID are you needing to replace?") 
    new_id = input("What is the new device ID?")   
    with open(filepath, 'r') as devicetxt:
        new_content = []
        for line in devicetxt:
            new_content.append(line.replace(original_id, new_id))
    with open(filepath, "w") as devicetxt:
        for line in new_content:
            devicetxt.write(line)

device_id_replace(original_file)

The answer of @ycx was not working in the past. So I fixed your old code:

original_file = "test.txt"


def device_id_replace(filepath):
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(filepath, 'r+') as devicetxt: #r+ is for read and write
        contents = devicetxt.readlines() #put all lines into a list
        for line_i, line in enumerate(contents):
            if original_id in line:
                contents[line_i] = line.replace(original_id, new_id) # CHANGED LINE
        devicetxt.truncate(0)
        devicetxt.seek(0)
        devicetxt.writelines(contents) #writeback to file

device_id_replace(original_file)

12 Comments

Tried this as well! Saved me from troubleshooting ycx's suggestion. Thanks very much for your help! This is working as I want it to! I see there's an empty list that we append each line into, are we essentially rewriting each line into the same file?
The code block with open(..., 'r')... reads the file and the code block with open(..., "w")... overwrites the old file. It is also possible to open the file once and rewrite it with the "r+" parameter.
@ZookiePookie would you be interested in code, which does open the file once and does the replacement directly? If yes, I would like it to solve this problem too.
thanks for looking into that for me. Your method works and @ycx method works as well. I'd like you to look at ycx's method as it only has one for loop in it and makes the code more readable and succinct which from what I've learned so far is part of the 'python zen'.
I think you're right about ycx's method. I am not seeing any substitution occurring when I run it. I am trying to add an if statement below 'for line in devicetxt:'. I want the if else to say 'if original_id in line:' 'print("Found " + original_id)' then perform 'new_content.append(line.replace(original_id, new_id))'. 'else:' 'print("Please ensure the PC ID was typed in correctly"). However, when I do this it always goes straight to the 'else' portion of the code. Any idea on why it's not working as expected?
|
0

You have a few options here, either use an internal tool like sed if you are using Unix/Unix like, or create a new file on top of the old one.

  1. Read all the file.
  2. Replace occurrences.
  3. Rewrite all lines.

This a pythonic version

with open(filepath) as f:
    transformedLines = [line.replace(old, new) if (old in line) else (line) for line in f]
with open(filepath, 'w') as f:
    f.writelines(transformedLines);

A less Pythonic version is similar:

transformedLines = []
with open(filepath) as f:
    for line in f:
        if old in line:
            transformedLines.append(line.replace(old, new))
        else:
            transformedLines.append(line)

A functional way (albeit very inefficient) can be done with map:

    transformedLines = list(map(lambda line : line.replace(old, new), f.readlines()))

This should be alright if your file isn’t huge, otherwise you will have to think about using a different type of data store like a DB.

Your approach works well at the moment but you will want to open it in read mode, for each line append it to a new list, if your id is found append the new line instead.

Write the new array to the file opened in write mode, which will wipe out the contents.

2 Comments

Great suggestion - I will try this. I tried @ycx method and it seems to get close to what I am wanting, but I believe it is updating the ID and then it is writing everything it read into the file again so I am getting duplicate data.
I added some details

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.