我看到很多在字符串中查找字符串或在列表中查找字符串的示例,但是如何在字符串中查找列表。例如,我有一个包含数据列的csv文件,最后一列是字符串,有时它是一个列表。以下是仅显示最后3列的数据子集。
TRUE, 93877, S26476961
TRUE, 93878, ['S26489167', 'S26492524']
FALSE, 93879, S26476962
FALSE, 93880, ['S26489168', 'S26492527', 'S26492528']
起初我试图用逗号解析csv文件的每一行,但它解析列表中的逗号(创建额外的列)。我只是希望列表被识别为单个数据,因此我可以将其作为'n'项列表使用。 @TemporalWolf的评论很有帮助,因为如果我使用csv模块(特别是csv.reader)就是这样......
reader = csv.reader(inFile)
for row in reader:
print(row)
它将列表保留在一列中。现在的问题仍然是它只是一个字符串。换句话说,row[n][0]
会返回左括号([
),但我想将其添加到列表中。
答案 0 :(得分:4)
这取决于引用列表元素的'
字符。使用此信息时,它仅使用正则表达式:
import re
import pandas as pd
import io
text = """TRUE, 93877, S26476961
TRUE, 93878, ['S26489167', 'S26492524']
FALSE, 93879, S26476962
FALSE, 93880, ['S26489168', 'S26492527', 'S26492528']"""
with io.StringIO(text) as f:
for line in f:
print(re.split("(?<!'), (?!')", line.strip()))
# ['TRUE', '93877', 'S26476961']
# ['TRUE', '93878', "['S26489167', 'S26492524']"]
# ['FALSE', '93879', 'S26476962']
# ['FALSE', '93880', "['S26489168', 'S26492527', 'S26492528']"]
# Or with pandas
with io.StringIO(text) as f:
print(pd.read_csv(f,
header=None,
sep="(?<!'), (?!')",
engine='python'))
# 0 1 2
# 0 True 93877 S26476961
# 1 True 93878 ['S26489167', 'S26492524']
# 2 False 93879 S26476962
# 3 False 93880 ['S26489168', 'S26492527', 'S26492528']
如果您使用的是python2,则需要将文本转换为unicode(通过在文本前放置字符u
)才能使用io.StringIO
:
import re
import pandas as pd
import io
text = u"""TRUE, 93877, S26476961
TRUE, 93878, ['S26489167', 'S26492524']
FALSE, 93879, S26476962
FALSE, 93880, ['S26489168', 'S26492527', 'S26492528']"""
with io.StringIO(text) as f:
for line in f:
print(re.split("(?<!'), (?!')", line.strip()))
# ['TRUE', '93877', 'S26476961']
# ['TRUE', '93878', "['S26489167', 'S26492524']"]
# ['FALSE', '93879', 'S26476962']
# ['FALSE', '93880', "['S26489168', 'S26492527', 'S26492528']"]
# Or with pandas
with io.StringIO(text) as f:
print(pd.read_csv(f,
header=None,
sep="(?<!'), (?!')",
engine='python'))
# 0 1 2
# 0 True 93877 S26476961
# 1 True 93878 ['S26489167', 'S26492524']
# 2 False 93879 S26476962
# 3 False 93880 ['S26489168', 'S26492527', 'S26492528']
如果您不希望依赖引号字符'
的存在,您可以尝试以下操作:
import ast
import re
with io.StringIO(text) as f:
for line in f:
parts = re.split(", (?=\[)", line.strip())
line = []
for part in parts:
if all(char in part for char in ('[]')):
line.append(ast.literal_eval(part))
else:
line += part.split(", ")
print(line)
您拆分位于左方括号前面的逗号,然后按如下方式检查结果:
list
ast.literal_eval
对象,并将其添加到最终输出列表中。这应该与上述解决方案相同。
我希望这会有所帮助。
答案 1 :(得分:2)
这是一个有趣的解决方案:在逗号上拆分每一行,并尝试将每个部分解析为Python代码。如果它无效,这意味着我们不包括整个列表:
import ast
def get_columns(line):
def valid(code):
try:
ast.parse(code.strip())
except SyntaxError:
return False
return True
sections = line.split(',')
columns = []
for i, section in enumerate(sections):
if i == len(sections) - 1 or valid(section):
columns.append(section)
else:
sections[i + 1] = ','.join([section, sections[i + 1]])
return columns
with open(inFile) as f:
for line in f:
for column in get_columns(line):
print(column)
由于这不涉及您的确切情况的正则表达式,这是非常一般的。还要注意,因为没有#34;代码&#34;在您的数据文件中进行评估以执行测试,这是完全安全的。
适用于Python 2和3。
答案 2 :(得分:0)
这是相反的方法。它通过检查行的项目中的前导csv.reader
和尾随[
来查找]
返回的数据中的列表。
import csv
def find_lists(row):
sublist = []
for item in row:
if not sublist:
if item.startswith('['):
if item.endswith(']'):
yield [item[1:-1]]
else:
sublist.append(item[1:])
else:
yield item
else:
if item.endswith(']'):
sublist.append(item[:-1])
yield sublist
sublist = []
else:
sublist.append(item)
for item in sublist:
yield item
with open('test.csv') as infile:
reader = csv.reader(infile, skipinitialspace=True)
for row in reader:
print(list(find_lists(row)))