2

次のようなエントリを含むテキスト ファイルがあります。

JohnDoe

Assignment 9  
Reading: NO  
header: NO  
HW: NO  
Solutions: 0 
show: NO  
Journals: NO  
free: NO  
Finished: NO  
Quiz: 0  
Done     
Assignment 3  
E-book: NO  
HW: NO  
Readings: NO  
Show: 0  
Journal: NO 
Study: NO  
Test: NO  
Finished: NO  
Quiz: 0  
Done

これは小さなサンプルです。ファイルには複数の学生が含まれています。各生徒の名前の下に 2 つの課題があり、各課題の「終了」で始まる行に「終了: はい」と表示されている場合にのみ合格となります。各課題の下のすべてのデータはまとまりがありませんが、各課題の下のどこかに「終了: はい (またはいいえ)」という行があります。ファイルを読み取って、学生が合格したかどうかを判断する方法が必要です。これまでのところ、私は

def get_entries( file ):
with open( "dicrete.txt.rtf", 'rt') as file:
    for line in file:
        if "Finished" in line:
            finished, answer = line.split(':')
            yield finished, answer

# dict takes a sequence of  `(key, value)` pairs and turns in into a dict
print dict(get_entries( file ))

このコードを取得して単一のエントリを返すことしかできません(最初の「終了」をキーとして読み取り、「YESまたはNO」を値として読み取りますが、これは私が望むものですが、開始するファイル内のすべての行を返すようにしたいですだから私が提供したサンプルデータは、2つのエントリを持つdictを返したいです {Finished:"NO" , Finished:"NO"}

4

2 に答える 2

2

Dictionaries can only store one mapping per key. So, you can never have a dictionary that has two different entries for the same key.

Consider using a list of two-tuples instead, like [("Finished", "NO"), ("Finished", "NO")].

于 2013-02-07T22:32:25.843 に答える
0

より良いデータ モデルが必要なようです。それを見てみましょう。

Assignmentの間のすべてのテキスト行で呼び出すことができるクラスを定義しましょう。Assignment: #Finished: YES/NO

class Assignment(object):
    def __init__(self, id, *args, **kwargs):
        self.id = id
        for key,val in kwargs.items():
            setattr(self, key.lower(), val)
        finished = getattr(self, 'finished', None)
        if finished is None:
            raise AttributeError("All assignments must have a 'finished' value")
        else:
            self.finished = True if finished.lower() == "yes" else False

    @classmethod
    def from_string(cls, s):
        """Builds an Assignment object from a string

        a = Assignment.from_string('''Assignment: 1\nAttributes: Go Here\nFinished: yes''')
        >>> a.id
        1
        >>> a.finished
        True"""
        d = dict()
        id = None
        for line in s.splitlines():
            key,*val = map(str.strip, line.split(":"))
            val = ' '.join(val) or None
            if key.lower().startswith('assignment'):
                id = int(key.split()[-1])
                continue
            d[key.lower()] = val
        if id is not None:
            return cls(id, **d)
        else:
            raise ValueError("No 'Assignment' field in string {}".format(s))

モデルを取得したら、入力を解析する必要があります。幸いなことに、これは実際には非常に簡単です。

def splitlineson(s, sentinel):
    """splits an iterable of strings into a newline separated string beginning with each sentinel.

    >>> s = ["Garbage", "lines", "SENT$", "first", "group", "SENT$", "second", "group"]
    >>> splitlineson(s, "SENT$")
    iter("SENT$\nfirst\ngroup",
         "SENT$\nsecond\ngroup")"""

    lines = []
    for line in s:
        if line.lower().strip().startswith(sentinel.lower()):
            if any((sentinel.lower() in line.lower() for line in lines)):
                yield "\n".join(lines)
            lines = [line.strip()]
        else:
            if line:
                lines.append(line.strip())
    yield "\n".join(lines)

with open('path/to/textfile.txt') as inf:
    assignments = splitlineson(inf, "assignment ")

assignment_list = [Assignment.from_string(a) for a in assignments]
于 2015-04-09T05:59:01.200 に答える