简体   繁体   中英

How to read a specific part of a text file (Py 3x)

Other questions don't seem to be getting answered or are not getting answered for Python. I'm trying to get it to find the keyword "name", set the position to there, then set a variable to that specific line, and then have it use only that piece of text as a variable. In shorter terms, I'm trying to locate a variable in the .txt file based on "name" or "HP" which will always be there.

I hope that makes sense...

I've tried to use different variables like currentplace instead of namePlace but neither works.

import os

def savetest():
    save = open("nametest_text.txt", "r")
    print("Do you have a save?")
    conf = input(": ")
    if conf == "y" or conf == "Y" or conf == "Yes" or conf == "yes":
        text = save.read()
        namePlace = text.find("name")
        currentText = namePlace + 7
        save.seek(namePlace)
        nameLine = save.readline()
        username = nameLine[currentText:len(nameLine)]
        print(username)

        hpPlace = text.find("HP")
        currentText = hpPlace + 5
        save.seek(hpPlace)
        hpLine = save.readline()
        playerHP = hpLine[currentText:len(hpLine)]
        print(playerHP)
        os.system("pause")
        save.close()
savetest()

My text file is simply:

name = Wubzy

HP = 100

I want it to print out whatever is put after the equals sign at name and the same for HP , but not name and HP itself.

So it should just print

Wubzy
100
Press any key to continue . . .

But it instead prints

Wubzy


Press any key to continue . . .

Use a regex to extract based on a pattern:

'(?:name|HP) = (.*)'

This captures anything that follows an equal to sign preceded by either name or HP .

Code :

import re

with open("nametest_text.txt", "r") as f:    
    for line in f:
        m = re.search(r'(?:name|HP) = (.*)', line.strip())
        if m:
            print(m.group(1))

Simplest way may be to use str.split() and then print everything after the '=' character:

with open("nametest_text.txt", "r") as f:    
    for line in f:
        if line.strip():
            print(line.strip().split(' = ')[1])

output:

Wubzy
100

This looks like a good job for a regex . Regexes can match and capture patterns in text, which seems to be exactly what you are trying to do.

For example, the regex ^name\\s*=\\s*(\\w+)$ will match lines that have the exact text "name", followed by 0 or more whitespace characters, an '=', and then another 0 or more whitespace characters then a one or more letters. It will capture the word group at the end.

The regex ^HP\\s*=\\s*(\\d+)$ will match lines that have the exact text "HP", followed by 0 or more whitespace characters, an '=', and then another 0 or more whitespace characters then one or more digits. It will capture the number group at the end.


# This is the regex library
import re

# This might be easier to use if you're getting more information in the future.
reg_dict = {
    "name": re.compile(r"^name\s*=\s*(\w+)$"),
    "HP": re.compile(r"^HP\s*=\s*(\d+)$")
}


def savetest():
    save = open("nametest_text.txt", "r")
    print("Do you have a save?")
    conf = input(": ")
    # instead of checking each one individually, you can check if conf is
    # within a much smaller set of valid answers
    if conf.lower() in ["y", "yes"]:
        text = save.read()

        # Find the name
        match = reg_dict["name"].search(text)
        # .search will return the first match of the text, or if there are
        # no occurrences, None
        if(match):
            # With match groups, group(0) is the entire match, group(1) is
            # What was captured in the first set of parenthesis
            username = match.group(1)
        else:
            print("The text file does not contain a username.")
            return
        print(username)

        # Find the HP
        match = reg_dict["HP"].search(text)
        if(match):
            player_hp = match.group(1)
        else:
            print("The text file does not contain a HP.")
            return
        print(player_hp)

        # Using system calls to pause output is not a great idea for a 
        # variety of reasons, such as cross OS compatibility
        # Instead of os.system("pause") try
        input("Press enter to continue...")

        save.close()
savetest()

Instead of trying to create and parse a proprietary format (you will most likely hit limitations at some point and will need to change your logic and/or file format), better stick to a well-known and well-defined file format that comes with the required writers and parsers, like yaml , json , cfg , xml , and many more.

This saves a lot of pain; consider the following quick example of a class that holds a state and that can be serialized to a key-value-mapped file format (I'm using yaml here, but you can easily exchange it for json , or others):

#!/usr/bin/python

import os
import yaml


class GameState:
    def __init__(self, name, **kwargs):
        self.name = name
        self.health = 100

        self.__dict__.update(kwargs)

    @staticmethod
    def from_savegame(path):
        with open(path, 'r') as savegame:
            args = yaml.safe_load(savegame)
            return GameState(**args)

    def save(self, path, overwrite=False):
        if os.path.exists(path) and os.path.isfile(path) and not overwrite:
            raise IOError('Savegame exists; refusing to overwrite.')

        with open(path, 'w') as savegame:
            savegame.write(yaml.dump(self.__dict__))

    def __str__(self):
        return (
            'GameState(\n{}\n)'
            .format(
                '\n'.join([
                    '  {}: {}'.format(k, v)
                    for k, v in self.__dict__.iteritems()
                ]))
        )

Using this simple class exemplarily:

SAVEGAMEFILE = 'savegame_01.yml'

new_gs = GameState(name='jbndlr')
print(new_gs)
new_gs.health = 98
print(new_gs)
new_gs.save(SAVEGAMEFILE, overwrite=True)

old_gs = GameState.from_savegame(SAVEGAMEFILE)
print(old_gs)

... yields:

GameState(
  health: 100
  name: jbndlr
)
GameState(
  health: 98
  name: jbndlr
)
GameState(
  health: 98
  name: jbndlr
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM