Python 使用不同的条件读取文本文件

Python 使用不同的条件读取文本文件,python,file-io,Python,File Io,我想读取一个arff文件,并将属性和数据分离到不同的列表中。这个文件是。我尝试了以下代码 from itertools import dropwhile attributes = [] with open('balloons.arff', 'r') as f: for l in f.readlines(): ##1 items = l.split(' ')

我想读取一个arff文件,并将属性和数据分离到不同的列表中。这个文件是。我尝试了以下代码

from itertools import dropwhile
attributes = []
with open('balloons.arff', 'r') as f:
    for l in f.readlines():                                     ##1
        items = l.split(' ')                                    ##2
        if items[0] == '@attribute':                            ##3
            attributes.append(items[1])                         ##4
    data = dropwhile(lambda _line: "@data" not in _line, f)     ##5
    next(data,"")                                               ##6
    for line in data:                                           ##7
            print(line.strip())                                 ##8
    print(attributes)                                           ##9

当我运行这段代码时,我只得到属性列表,但是当我注释行号###1到##4(第一个为循环)时,程序正确地给出了数据部分。我有非常大的文件,一个有效的解决方案将受到赞赏。

第5行到第9行不再是for循环的一部分,因此“f”没有定义我猜第5行到第9行不再是for循环的一部分,因此“f”没有定义我猜没有必要重新发明轮子。其他人已经为Python编写了ARFF解析器。使用
pip安装它

pip install liac-arff
然后导入并使用模块:

import arff

with open('balloons-adult-stretch.arff', 'rb') as handle:
    data = arff.load(handle)

print(data['attributes'])
print(data['data'])
输出:

[(u'V1', [u'PURPLE', u'YELLOW']), (u'V2', [u'LARGE', u'SMALL']), (u'V3', [u'DIP', u'STRETCH']), (u'V4', [u'ADULT', u'CHILD']), (u'Class', [u'1', u'2'])]
[[u'YELLOW', u'SMALL', u'STRETCH', u'ADULT', u'2'], [u'YELLOW', u'SMALL', u'STRETCH', u'CHILD', u'2'], [u'YELLOW', u'SMALL', u'DIP', u'ADULT', u'2'], [u'YELLOW', u'SMALL', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'SMALL', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'LARGE', u'STRETCH', u'ADULT', u'2'], [u'YELLOW', u'LARGE', u'STRETCH', u'CHILD', u'2'], [u'YELLOW', u'LARGE', u'DIP', u'ADULT', u'2'], [u'YELLOW', u'LARGE', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'LARGE', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'SMALL', u'STRETCH', u'ADULT', u'2'], [u'PURPLE', u'SMALL', u'STRETCH', u'CHILD', u'2'], [u'PURPLE', u'SMALL', u'DIP', u'ADULT', u'2'], [u'PURPLE', u'SMALL', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'SMALL', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'LARGE', u'STRETCH', u'ADULT', u'2'], [u'PURPLE', u'LARGE', u'STRETCH', u'CHILD', u'2'], [u'PURPLE', u'LARGE', u'DIP', u'ADULT', u'2'], [u'PURPLE', u'LARGE', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'LARGE', u'DIP', u'CHILD', u'1']]

如果您确实希望自己编写此代码,那么代码的问题在于第一个循环读取文件中的所有行。在循环结束后,您必须使用
f.seek(0)
将文件句柄倒回开头,或者通过实现一个简单的状态机一次性解析它:

attributes = {}
data = []

reading_data = False

with open('balloons-adult-stretch.arff', 'r') as handle:
    for line in handle:
        line = line.strip()

        # Ignore comments and whitespace
        if line.startswith('%%') or not line:
            continue

        # If we have already reached the @data section, we just read indefinitely
        # If @data doesn't come last, this will not work
        if reading_data:
            data.append(line)
            continue

        # Otherwise, try parsing the file
        if line.startswith('@attribute'):
            key, value = line.split(' ', 2)[1:]
            attributes[key] = value
        elif line.startswith('@data'):
            reading_data = True
        else:
            #raise ValueError('Cannot parse line {!r}'.format(line))
            pass

没有必要重新发明轮子。其他人已经为Python编写了ARFF解析器。使用
pip安装它

pip install liac-arff
然后导入并使用模块:

import arff

with open('balloons-adult-stretch.arff', 'rb') as handle:
    data = arff.load(handle)

print(data['attributes'])
print(data['data'])
输出:

[(u'V1', [u'PURPLE', u'YELLOW']), (u'V2', [u'LARGE', u'SMALL']), (u'V3', [u'DIP', u'STRETCH']), (u'V4', [u'ADULT', u'CHILD']), (u'Class', [u'1', u'2'])]
[[u'YELLOW', u'SMALL', u'STRETCH', u'ADULT', u'2'], [u'YELLOW', u'SMALL', u'STRETCH', u'CHILD', u'2'], [u'YELLOW', u'SMALL', u'DIP', u'ADULT', u'2'], [u'YELLOW', u'SMALL', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'SMALL', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'LARGE', u'STRETCH', u'ADULT', u'2'], [u'YELLOW', u'LARGE', u'STRETCH', u'CHILD', u'2'], [u'YELLOW', u'LARGE', u'DIP', u'ADULT', u'2'], [u'YELLOW', u'LARGE', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'LARGE', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'SMALL', u'STRETCH', u'ADULT', u'2'], [u'PURPLE', u'SMALL', u'STRETCH', u'CHILD', u'2'], [u'PURPLE', u'SMALL', u'DIP', u'ADULT', u'2'], [u'PURPLE', u'SMALL', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'SMALL', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'LARGE', u'STRETCH', u'ADULT', u'2'], [u'PURPLE', u'LARGE', u'STRETCH', u'CHILD', u'2'], [u'PURPLE', u'LARGE', u'DIP', u'ADULT', u'2'], [u'PURPLE', u'LARGE', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'LARGE', u'DIP', u'CHILD', u'1']]

如果您确实希望自己编写此代码,那么代码的问题在于第一个循环读取文件中的所有行。在循环结束后,您必须使用
f.seek(0)
将文件句柄倒回开头,或者通过实现一个简单的状态机一次性解析它:

attributes = {}
data = []

reading_data = False

with open('balloons-adult-stretch.arff', 'r') as handle:
    for line in handle:
        line = line.strip()

        # Ignore comments and whitespace
        if line.startswith('%%') or not line:
            continue

        # If we have already reached the @data section, we just read indefinitely
        # If @data doesn't come last, this will not work
        if reading_data:
            data.append(line)
            continue

        # Otherwise, try parsing the file
        if line.startswith('@attribute'):
            key, value = line.split(' ', 2)[1:]
            attributes[key] = value
        elif line.startswith('@data'):
            reading_data = True
        else:
            #raise ValueError('Cannot parse line {!r}'.format(line))
            pass

问题是,在for循环中,您已经到达了EOF(文件结尾)。这意味着,一旦启动lambda函数,文件中就没有可读取的内容了。您可以找到一种方法来读取for循环中的数据,或者如果您想(稍微)低效地执行此操作,可以执行以下操作:

from itertools import dropwhile
attributes = []
with open('stuff.txt', 'r') as f:
    for l in f.readlines():                                     ##1
       items = l.split(' ')                                    ##2
       if items[0] == '@attribute':                            ##3
            attributes.append(items[1])
    f.seek(0)                         ##4
    data = dropwhile(lambda _line: "@data" not in _line, f)     ##5
    next(data,"")                                               ##6
    for line in data:                                           ##7
        print(line.strip())                                 ##8
print(attributes)

问题是,在for循环中,您已经到达了EOF(文件结尾)。这意味着,一旦启动lambda函数,文件中就没有可读取的内容了。您可以找到一种方法来读取for循环中的数据,或者如果您想(稍微)低效地执行此操作,可以执行以下操作:

from itertools import dropwhile
attributes = []
with open('stuff.txt', 'r') as f:
    for l in f.readlines():                                     ##1
       items = l.split(' ')                                    ##2
       if items[0] == '@attribute':                            ##3
            attributes.append(items[1])
    f.seek(0)                         ##4
    data = dropwhile(lambda _line: "@data" not in _line, f)     ##5
    next(data,"")                                               ##6
    for line in data:                                           ##7
        print(line.strip())                                 ##8
print(attributes)

我不能在循环中使用它,当我删除缩进时,我得到了错误消息f in not define。所以,我想这不是一个问题。谢谢你的回答对不起,实际上我指的是for循环和“l”;-)所以不要删除,而是添加一个缩进。。。但是@Blender有一个更好的答案;-)我不能在循环中使用它,当我删除缩进时,我得到了错误消息f in not define。所以,我想这不是一个问题。谢谢你的回答对不起,实际上我指的是for循环和“l”;-)所以不要删除,而是添加一个缩进。。。但是@Blender有一个更好的答案;-)非常感谢您的想法和解决方案。我会给arff软件包一些时间。@BlenderI在
attributes[key]=value
处收到错误消息,然后我将其更改为
attributes.append(key)
,因为我需要属性名而不是属性值。这是正确的方法吗?@Abrar:如果有效,就有效。您也可以只使用
attributes.keys()
并将其作为字典。非常感谢您的想法和解决方案。我会给arff软件包一些时间。@BlenderI在
attributes[key]=value
处收到错误消息,然后我将其更改为
attributes.append(key)
,因为我需要属性名而不是属性值。这是正确的方法吗?@Abrar:如果有效,就有效。您也可以只使用
attributes.keys()
并将其作为字典。