我正在研究一些循环txt文件的代码,并创建一个包含单独行的列表。我需要每行的特定内容,其中逗号用作分隔符。但是,当其中一个列表项中有逗号时,我遇到了一个问题。列表推导线将此单个项目分为两个项目。该项目作者用括号括起来。我可以让列表理解忽略括号中包含的项目吗?
inventory = open("inventory.txt").readlines()
seperated_inventory = [x.split(",") for x in inventory]
isbn_list = [item[0] for item in seperated_inventory]
author_list = [item[1] for item in seperated_inventory]
title_list = [item[2] for item in seperated_inventory]
category_list = [item[3] for item in seperated_inventory]
active_list = [item[4] for item in seperated_inventory]
有两位作者的行的例子
0520085477,['Richard L. Abel', 'Philip Simon Coleman Lewis'],Lawyers in Society,['Law’],False
答案 0 :(得分:0)
我认为使用单个字符split
并不是一个很好的策略,当你有可以包含你正在拆分的角色的子列表时。
有三种主要方法可以解决这个问题(我已经想到了)。 。 。好吧,有两种方式和另一种选择:
split(',')
并重新加入子阵列。这是相当脆弱,冗长,并且不如第二种方法。我把它放在首位,因为它直接回答了问题,而不是因为它是你应该做的:
line="0520085477,['Richard L. Abel', 'Philip Simon Coleman Lewis'],Lawyers in Society,['Law’],False"
# Index of the left hand side of any found sub-arrays.
left = 0
# Iterator position, also used as the index of the right hand side of any found sub-arrays.
right = 0
array = line.split(',')
while right < len(array):
if array[right].startswith('['):
array[right] = array[right][1:] # Remove the bracket
left = right
if array[right].endswith(']'):
array[right] = array[right][:-1] # Remove the bracket
# Pull the stuff between brackets out into a sub-array, and then
# replace that segment of the original array with a single element
# which is the sub-array.
array[left:right+1] = [array[left:right+1]]
# Preserve the "leading search position", since we just changed
# the size of the array.
right = left
right += 1
print(array)
正如您所看到的,该代码比理解更难清晰。它也很复杂;它可能有我没有测试过的bug和边缘情况。
这仅适用于单级嵌套子阵列。
尽管what xkcd says about regex,但在这种情况下,提取子阵列是一个更清晰,更简单的解决方案。有关如何使用正则表达式的更多信息,请参阅re
模块的文档。在线正则表达式测试人员也很容易获得,在调试正则表达式时非常有用。
import re
line="0520085477,['Richard L. Abel', 'Philip Simon Coleman Lewis'],Lawyers in Society,['Law’],False"
r = re.compile(r'(?:\[(?P<nested>.*?)\]|(?P<flat>[^,]+?)),')
array = []
# For each matched part of the line, figure out if we matched a
# sub-array (in which case, split it on comma and add the resulting
# array to the final list) or a normal item (just add it to the final
# list).
# We append a comma to the string we search so our regex always matches
# the last element.
for match in r.finditer(line + ","):
if match.group('nested'): # It's a sub-array
array.append(match.group('nested').split(","))
else: # It's a normal top-level element
array.append(match.group('flat'))
print(array)
正则表达式粗略地说:
?:
)。就像括号在数学公式中强制操作的顺序一样,这使得显式的是这个正则表达式末尾的尾随逗号不是任何一个捕获组的一部分。这不是绝对必要的,但会让事情变得更加清晰。?
),匹配中的任何内容都应该可以使用名称为“regex API”的正则表达式API嵌套”。这个名字是完全可选的;匹配对象上的数组索引也可以使用,但这对代码阅读器更明确。[^,]
)的字符。根据正则表达式引擎的急切程度,您可以用“任何字符”替换它,并且相信外部非捕获?:
组之外的逗号会阻止这些匹配逃跑,但是说“不是逗号” “对读者来说更明确。与此组匹配的任何内容都应以“flat”名称存储。一旦理解了正则表达式,其余部分就很简单:遍历每个匹配,看看它是“平面”还是“嵌套”,如果它是嵌套的,则根据逗号将其拆分并将其作为子数组添加结果。
这不适用于多级嵌套子数组,并且如果逗号最终彼此相邻或者子数组未“关闭”(格式错误的输入,则会中断/执行意外事务)基本上),这带给我的。 。
这两种解析器都容易出错。数组中的元素可能包含特殊字符(例如,如果this之类的标题在其名称中包含方括号,会怎样?),在“空”字段周围可能出现多个逗号,您可能需要多个级别嵌套的子数组(您可以使前两个选项中的任何一个递归,但代码将变得更难以阅读),或者,也许最常见的是,您可能会被输入稍微损坏/不符合您的输入期待,无论如何都要解析它。
处理所有这些问题可以通过更多代码来完成,但该代码通常会使解析系统不那么可靠,而不是更多。
相反,请考虑将数据交换格式切换为类似JSON的格式。您提供的行已经是几乎有效的JSON,因此您可以直接使用json
Python模块并使事情“正常工作”而无需编写单行解析代码。结构化数据解析还有许多其他选项,包括YAML和TOML。您在该区域中选择的任何内容都可能比手动滚动解析逻辑更强大。
当然,如果这是为了娱乐/教育而您希望从头开始制作某些东西,那么请编码!解析器是一个很好的教育项目,因为有一个很多的角落案例,但是每个角落案例往往是离散的/与其他奇怪案例的交互很少。