Using Python3 to search a file for a string, add the results on the next lines to an array before stopping at the next string

Viewed 136

I am using Python 3 to process a results file. The structure of the file is a combination of string identifiers followed by lists of integer values in this format:

ENERGY_BOUNDS 
  1.964033E+07  1.733253E+07  1.491825E+07  1.384031E+07  1.161834E+07  1.000000E+07  8.187308E+06  6.703200E+06
  6.065307E+06  5.488116E+06  4.493290E+06  3.678794E+06  3.011942E+06  2.465970E+06  2.231302E+06  2.018965E+06
EIGENVALUE 
  1.219034E+00

There are maybe 50 different sets of data with unique identifiers in this file. What I want to do is write a code that will search for a specific identifier (e.g. ENERGY_BOUNDS), then read the values that follow into a list, stopping at the next identifier (in this case EIGENVALUE). I then need to be able to manipulate the list (finding its length, printing its values, etc.).

I am writing this as a function so I can call it multiple times in my code when I want to search for different identifiers. So far what I have is:

def read_data_from_file(file_name, identifier):

    list_of_results = [] # Create list_of_results to put results in for future manipulation
    
    # Open the file in read only mode
    with open(file_name, 'r') as read_obj:

        # Read all lines in the file one by one
        for line in read_obj:

            # For each line, check if line contains the string
            if identifier in line:

                # If yes, read the next line
                nextValue = next(line)
                list_of_results.append(nextValue.rstrip())

    return list_of_results

It works fine up until it comes to reading the next line after the identifier, and I am stuck on how to continue reading the results after that line and how to make it stop at the next identifier.

4 Answers

Following is simple and tested answer.

You are making two mistakes

  1. line is a string and not iterator so doing next(line) is causing error.
  2. You are just reading one line after identifier has been found while you need to keep on reading until another identifier appears.

Following is the code after doing little modification of your code. It's also tested on your data

def read_data_from_file(file_name, identifier):
    with open(file_name, 'r') as read_obj:
        list_of_results = []
            # Read all lines in the file one by one
        for line in read_obj:

            # For each line, check if line contains the string
            if identifier in line:
                # If yes, read the next line
                nextValue = next(read_obj)
                while(not nextValue.strip().isalpha()): #keep on reading untill next identifier appears
                    
                    list_of_results.extend(nextValue.split())
                    nextValue = next(read_obj)
        print(list_of_results)

I would suggest adding a variable that indicates whether you have found a line containing an identifier. Afterwards, simply add the values into the array until the next identifier has been reached.

def read_data_from_file(file_name, identifier):

    list_of_results = [] # Create list_of_results to put results in for future manipulation
    identifier_found = False
    
    # Open the file in read only mode
    with open(file_name, 'r') as read_obj:

        # Read all lines in the file one by one
        for line in read_obj:

            # For each line, check if line contains the string
            if identifier in line:
                identifier_found = True
            elif identifier_found:
                if line.strip().isalpha(): # Next identifier reached, exit loop
                    break

                list_of_results += line.split() # Add values to result

    return list_of_results

Use booleans, continue, and break!

Try to implement logic as follows:

  • Set a boolean (I'll use in_range) to False
  • Look through the lines and see if they match the identifier.
    • If it does, set the boolean to True and continue
    • If it does not, continue
  • If the boolean is False AND the line begins with a space: continue
  • If the boolean is True AND the line begins with a space: Add the line to the list.
  • If the boolean is True AND the line doesn't begin with a space: break.

This ends the searching process once a new identifier has been started.

The other 2 answers are already helpful. Here is my method incase that you need something else. With comments to explain. If you dont want to use the end_identifier you can use .isAlpha() which checks if the string only contains letters.

def read_data_from_file(file_name, start_identifier, end_identifier):

    list_of_results = []

    with open(file_name, 'r') as read_obj:
        start_identifier_reached = False  # variable to check if we reached the needed identifier_reached
        for line in read_obj:
            if start_identifier in line:
                start_identifier_reached = True  # now we reached the identifier
                continue  # We go back to the start so we dont write the identifier into the list
            if start_identifier_reached and (end_identifier not in line):  # Put the values into the list until we reach the end_identifier
                list_of_results.append(line.rstrip())
            else:
                return list_of_results
Related