Incorrect output when processing batch of inputs from file (converting pre-to-postfix)

Question:

I am having trouble writing my results into my output file. I’m trying to recursively convert from prefix to postfix. If I copy the input all at once separately, the output overwrites it. If there is a way that I could print a block of input followed by a block of output that would also work.

import sys


def isoperator(i):  # check if the input is an operator
    if i in ['$', '^', '*', '/', '+', '-']:
        return True
    else:
        return False

def isoperandoroperator(i):  # check if the input is an operand
    if i.isalpha and i.isnumeric or isoperator(i):
        return True
    else:
        return False

my_list = sys.argv[1]
my_output = sys.argv[2]


def recursivepretopost(input):  # method to convert from pre to postfix, takes input file as argument
    char = input.read(1)
    if char == 'n':
        return ''
    if char == ' ':
        return ''
    if isoperator(char):   # if the character is an operator, perform recursive call to check the next character
        return recursivepretopost(input) + recursivepretopost(input) + char
    else:  # if the character is an operand, return the operand
        return char


with open(my_list, 'r') as file, open(my_output, 'w') as i:  # use file to refer to the file object and open output file
    for d in file:
        i.write('Input: ' + d)
        i.write('Output: ')
        i.write(recursivepretopost(file) + 'n')

Here is the input of prefix expressions:

-+ABC
-A+BC
$+-ABC+D-EF
-*A$B+C-DE*EF
**A+BC+C-BA
/A+BC +C*BA  
*-*-ABC+BA  
/+/A-BC-BA  
*$A+BC+C-BA 
//A+B0-C+BA
*$A^BC+C-BA     

This is my output:

Input: -+ABC
Output: ABC+-
Input: 
Output: AB-C+DEF-+$
Input: 
Output: ABCDE-+$*EF*-
Input: 
Output: ABC+*CBA-+*
Input: 
Output: ABC+/
Input:  +C*BA  
Output: AB-C*BA+-*
Input:  
Output: ABC-/BA-+/
Input:  
Output: ABC+$CBA-+*
Input:  
Output: AB0+/CBA+-/
Input: 
Output: ABC^$CBA-+*

But this is the intended output:

Input: -+ABC
Output: AB+C-
Input: -A+BC
Output: ABC+-
Input: $+-ABC+D-EF
Output: $+-ABC+D-EF
Input: -*A$B+C-DE*EF
Output: ABCDE-+$*EF*-
Input: **A+BC+C-BA
Output: ABC+*CBA-+*
Input: /A+BC +C*BA
Output: ABC+/
Input: *-*-ABC+BA
Output: AB-C*BA+-*
Input: /+/A-BC-BA
Output: ABC-/BA-+/
Input: *$A+BC+C-BA
Output: ABC+$CBA-+*
Input: //A+B0-C+BA
Output: AB0+/CBA+-/
Input: *$A^BC+C-BA
Output: ABC^$CBA-+*
Asked By: abiwink

||

Answers:

The problem isn’t in how you’re writing to your output file, it’s in how you’re reading from your input file. Your for loop iterates through the open file, line by line. You then also call that file’s read method, which advances the current position in the file, which screws up your loop. This is essentially the same problem as the classic "Don’t remove items from a list while you’re iterating through it" gotcha.

The simplest way to fix your existing recursive function would be to create a StringIO instance of each string you wish to process. A StringIO supports reading as if it were a file, even though it’s simply a string stored in memory.

Other things I changed:

  • Gave variables more descriptive names, and put function names in snake_case
  • Changed function comments to docstrings
  • Stripped each line of left and right whitespace, including n, and removed spaces, so that you don’t need to handle those within your function
  • Simplified how is_operator returns its boolean, and checked membership in a set rather than a list
  • Removed unused isoperandoroperator
  • Used f-strings for formatting output
from io import StringIO
import sys


def is_operator(char):
    """Check if the input is an operator."""
    return char in {'$', '^', '*', '/', '+', '-'}

def recursive_pre_to_post(stream):
    """Convert from pre to postfix.
    Takes input file or string buffer as argument
    """
    char = stream.read(1)
    if is_operator(char):
        # If the character is an operator, perform recursive call to
        # check the next character.
        return (recursive_pre_to_post(stream) +
                recursive_pre_to_post(stream) + 
                char)
    else:
        # If the character is an operand, return the operand.
        return char


in_name = sys.argv[1]
out_name = sys.argv[2]

with open(in_name) as in_file, open(out_name, 'w') as out_file:
    for line in in_file:
        line = line.strip().replace(' ', '')
        out_file.write(f'Input: {line}n')
        result = recursive_pre_to_post(StringIO(line))
        out_file.write(f'Output: {result}n')
Answered By: CrazyChucky
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.