Search code examples
pythonpandastext-filesswaptext-processing

Is there a way to swap two lines of text in a text file using python?


I am trying to write a python script that would take a file (lets call it input.txt), and look for a line that ends with the text "move to first perimeter point." Then it needs to replace this line with the line following it, and replace the line following it with the first line. The rest of the file must be unchanged. There are tons of instances where this needs to occur in the file.

My thought process was this. Look for the line that ends with "move to first perimeter point." Once the code finds it, it will save the line as a variable and then delete the line from the file. Then, if the next line ends with "restore layer Z" (which will always be the case with the following line) it needs to add the previously deleted line after this line.

Here is what I am trying to do:

  1. Open a file ('input.txt').
  2. Swap each occurrence of two consecutive lines, where,
    • First line ends with: 'move to first perimeter point'
    • Second line ends with: 'restore layer Z'
    • Note: It is known that all such occurrences will always happen in pairs (first-second lines placed consecutively).
  3. Write this change into a new file ('output.txt').

I have tried putting this together using python. I played with python years ago, and vaguely remember how to use it. It threw error. Here is my code after making corrections suggested in the comments' section: (a) str.endwith --> str.endswith, (b) For --> for. Any suggestions would be very helpful and appreciated.

inp = open('input.txt','r')
out = open('output.txt', 'w')
prev = inp.readline()
for line in inp:
    if line.endswith('move to first perimeter point')
        prev = line
        if line.endswith('restore layer Z')
            out.write(line)
            out.write(prev)
    else:
        out.write(prev)
    prev = line
out.write(prev)
out.close()
inp.close

I expected the input file to remain unchanged, while a new output file was created. Instead, nothing happened.

Thanks for your help in advance! I'm very new to this.


Solution

  • Solution

    Here we read in the lines from the txt file into variable s (a list of strings). The custom function swap_lines_in_text() then does the swapping and returns a dataframe df for further processing (if needed). Finally you could convert it into a list of lines using df.Text.tolist() and write it to a new file with file.writelines() as shown below.
    Since, no sample data was provided, I made my own (See: Dummy Data below). For the sake of testing the solution I will use the dummy data.

    # Read-in the lines from input file
    with open('input.txt', 'r') as f:
        s = f.readlines()
    
    # Execute Swap
    df = swap_lines_in_text(s, 
                            first_line_text = 'move to first perimeter point', 
                            second_line_text = 'restore layer Z')
    
    # Show output (comment out the following line if need be)
    # print(df)
    print('\n'.join(df.Text.tolist()))
    
    # Write to output file
    with open('output.txt', 'w') as f:
        f.writelines(df.Text.tolist())
    

    Output:

    A
    B
    D restore layer Z
    C move to first perimeter point
    E
    F
    H restore layer Z
    G move to first perimeter point
    I
    K restore layer Z
    J move to first perimeter point
    L
    M
    N
    

    Custom Function to Process the Text (Swapping of Target Lines)

    This function would return a pandas.DataFrame object.

    import pandas as pd
    
    def swap_lines_in_text(s, first_line_text='move to first perimeter point', second_line_text='restore layer Z'):
        """
        s = string or a list of strings.
        """
        if isinstance(s, list):
            lines = s.copy()
        else:
            lines = s.strip().split('\n')
        df = pd.DataFrame({'Text': lines})
        df.Text = df.Text.str.strip()
        # Detect Target Lines (both first and second kinds)
        first_lines = df.Text.str.contains(first_line_text)
        second_lines = df.Text.str.contains(second_line_text)
        # Swap lines
        df.Text.loc[first_lines], df.Text.loc[second_lines] = df.Text[second_lines].tolist(), df.Text[first_lines].tolist()
        return df
    

    Dummy Data

    s = """
    A 
    B 
    C move to first perimeter point 
    D restore layer Z
    E 
    F 
    G move to first perimeter point
    H restore layer Z
    I 
    J move to first perimeter point
    K restore layer Z
    L 
    M 
    N
    """
    print(s.strip())