views:

128

answers:

3

Hello all!

I have defined a for loop as follows which scans through a file made up of two columns, when it finds the keyword DEFINE_MENU the second column on this line refers to the title for a screen. The next instance of the keyword will define a title for a seperate screen and so on to the nth screen. At the moment the code is capable of defining the first menu title.

Is it possible, when I reach the second instance of the keyword DEFINE_MENU to repeat the loop for the same line, setting the title_flag = 0 thereby repeating itself, capturing the second menu title?

def getInfo():

    title_flag = 0
    number = 1
    menus = {}
    items = {}
    title = None
    file = open('some_file', 'r')
    for line in file:
        # Test for comments, if they exist pass and move on
        if line[0] == '#':
            continue
        # Hop over blank lines
        if re.search(r'^\s+$', line):
            continue
        # Find the line where the title is defined
        if re.search('DEFINE_MENU', line) and title_flag == 0:
            type, name = line.split()
            title = name
            title_flag = 1
            continue
        # If DEFINE_MENU is found and flag has been raised, this
        # signifies a new menu definition so break.
        if re.search('DEFINE_MENU', line) and title_flag == 1:
            break
        if re.search('PRIV', line):
            (type, name, priv_holder, *description) = line.split()
        else:
            (type, name, *description) = line.split()
        # If flag has been raised, the line must follow the definition
        # of the menu, it must contains info regarding a menu item.
        if title_flag == 1:
            description = ' '.join(description)
            items[str(number)] = name
            number += 1
    file.close()
    menus[title] = items
    return menus

Thank you for your input!

Tom

EDIT: First, apologies for the confusion caused. Perhaps I thought of the problem as being simpler than I thought and gave less information than required. I will delve deeper, the input file i am using is of the form:

# MENU TYPE     NAME            PRIV?   DESCRIPTION
DEFINE_MENU     CRAGINS
MENU            menu_name1              This takes you to menu 1
MENU            menu_name2              This takes you to menu 2
VARIABLE        var_name1               Alter variable1
VARIABLE        var_name2       PRIV    Alter variable1
COMMAND         command1                Perform command1
DEFINE_MENU     MENU2
MENU            menu_name3              This takes you to menu 3
MENU            menu_name4              This takes you to menu 4
VARIABLE        var_name3               Alter variable3
VARIABLE        var_name4       PRIV    Alter variable4
COMMAND         command3                Perform command3

I had raised the flag as I further manipulate the data between the DEFINE_MENU calls. I have edited the code to include the full method that I have written.

The outcome is currently a dictionary where the key is the menu title and value is the another dictionary containing the menu items (values following the title) as follows:

{'title1': {'1': 'menu_name1', '3': 'var_name1', '2': 'menu_name2', '5': 'command1', '4': 'var_name2'}}

What I would like to have is a larger dictionary containing the menu titles as keys with the lowest level dictionary as the value. I understand that this is complicated so I'm sorry if it unclear, let me know if more information is required.

Thanks again

Tom

A: 

Does this somewhat capture your logic?

menus = []
current_menu = None
for line in file:
    # ...
    # Find the line where the title is defined
    if re.search('DEFINE_MENU', line):
        if not current_menu is None:
            menus.append(current_menu)
        current_menu = Menu()
        type, name = line.split()
        current_menu.setTitle(name)
        continue

Menu would be a helper class for storing all the information that belongs to one menu. Also, since it seems all your cases are mutually exclusive, consider using elif instead of continue.

Space_C0wb0y
A: 

I'm not sure exactly what you're after, but would it be possible to just store your titles in a list?

titles = []

for line in infile: # don't shadow "file" keyword...

    if "DEFINE_MENU" in line:
        titles.append(line.split()[-1]) # append the last item

if you only want the first two titles, you could add an extra test:

if len(titles) == 2: break
Ryan Ginstrom
+1  A: 

If I understand your problem description correctly, you want to repeat the loop body (in certain cases) rather than "the iteration". If that's the case, one workable approach is to make the loop body into a possibly-recursive function, returning True if the loop is to break, False if it is to continue, as well as the possible title. For example, a most-direct (though probably not maximally elegant) function:

def body(line):
    global title_flag

    # skip over comments
    if line[0] == '#':
        return None, False
    # skip over blank lines
    if re.search(r'^\s+$', line):
        return None, False

    # Find the line where the title is defined
    if 'DEFINE_MENU' in line and title_flag == 0:
        type, name = line.split()
        title = name
        title_flag = 1
        return title, body(line)

    # If DEFINE_MENU is found and flag has been raised, this
    # signifies a new menu definition.
    if 'DEFINE_MENU' in line and title_flag == 1:
        return None, True

and the main-line code becomes:

title_flag = 0

with open('some_file', 'r') as afile:
    for line in afile:
        thetitle, mustbreak = body(line)
        if thetitle is not Note: title = thetitle
        if mustbreak: break

BTW: do not name your own variables by usurping built-in names like file -- that's a separate subject;-). BTW2: I'm using with (assuming Python 2.6 or better, or 2.5 with an "import from the future") only because it's the right way to open and close a file;-). BTW3: I removed the re.search because it's wanton, inexplicable overkill when a simple in operator clearly does the same job.

I'm posting this code mostly to check in a concrete way whether I understood your specs, because, behavior-wise, this is definitely overkill -- there's no need (from the code you posted) to repeat the checks for comments and empty lines, nor the search for 'DEFINE_MENU", etc... you could just exit as soon as you've set the title (and body could then become inline code again).

But, I imagine that you have a reason for posting your question, i.e., that the simple behavior this has (and which could be had much more simply) is not optimal for you -- maybe by seeing the solution to your literal question you can point out what you want different than this, and then we can actually help you;-).

Alex Martelli
Thankyou for your response, although it did not directly solve my problem, it pointed me in the right direction and has provided me with some better coding techniques, namely using `in` rather than regex and I have renamed `file` to a non-built-in name. :)
Thorsley