3 回答
TA贡献1829条经验 获得超13个赞
使用ast.literal_eval(...)会起作用,但它需要其他 CSV 读取软件无法识别的特殊语法,并使用一个eval危险信号。
使用 eval 可能很危险,即使在这种情况下您使用的literal_eval是比原始eval函数更受限制的更安全的选项。
通常,您会在单列中有多个值的 CSV 文件中看到它们将使用简单的分隔符并引用该字段。
例如:
ID,Country,Cities
1,Canada,"Toronto;Ottawa;Montreal"
然后在 python 或任何其他语言中,无需求助于阅读就变得微不足道eval:
import csv
with open("data.csv") as fobj:
reader = csv.reader(fobj)
field_names = next(reader)
rows = []
for row in reader:
row[-1] = row[-1].split(";")
rows.append(row)
问题ast.literal_eval
尽管该ast.literal_eval功能比在用户输入上使用常规功能要安全得多eval,但它仍然可能是可利用的。的文档literal_eval有这个警告:
警告:由于 Python 的 AST 编译器中的堆栈深度限制,使用足够大/复杂的字符串可能会使 Python 解释器崩溃。
可以在这里找到一个演示:
>>> import ast
>>> ast.literal_eval("()" * 10 ** 6)
[1] 48513 segmentation fault python
我绝对不是专家,但让用户能够使程序崩溃并可能利用一些模糊的内存漏洞是不好的,在这种用例中可以避免。
如果您要使用的原因literal_eval是为了获得正确的输入,并且您肯定输入数据是 100% 受信任的,那么我想它可以使用。但是,您始终可以包装该函数以执行一些健全性检查:
def sanely_eval(value: str, max_size: int = 100_000) -> object:
if len(value) > max_size:
raise ValueError(f"len(value) is greater than the max_size={max_size!r}")
return ast.literal_eval(value)
但是,根据您创建和使用 CSV 文件的方式,这可能会降低数据的可移植性,因为它是一种特定于 python 的格式。
TA贡献1820条经验 获得超2个赞
如果您可以控制 CSV,则可以将项目与其他一些不会出现在城市中且不是逗号的已知字符分开。说冒号 ( :
)。
例如,第一行将如下所示:
1,Canada,Toronto:Ottawa:Montreal
在处理数据时,您将拥有整个元素,您可以这样做
cities.split(':')
如果你想走另一条路(你有一个 Python 列表中的城市,并且你想创建这个字符串)你可以使用join()
':'.join(['Toronto', 'Ottawa', 'Montreal'])
TA贡献1831条经验 获得超10个赞
对于 csv 的特定结构,您可以将城市转换为这样的列表:
cities = '''"['Rome','Milan','Naples', 'Palermo']"'''
cities = cities[2:-2] # remove "[ and ]"
print(cities) # 'Rome','Milan','Naples', 'Palermo'
cities = cities.split(',') # convert to list
print(cities) # ["'Rome'", "'Milan'", "'Naples'", " 'Palermo'"]
cities = [x.strip() for x in cities] # remove leading or following spaces (if exists)
print(cities) # ["'Rome'", "'Milan'", "'Naples'", "'Palermo'"]
cities = [x[1:-1] for x in cities] # remove quotes '' from each city
print(cities) # ['Rome', 'Milan', 'Naples', 'Palermo']
添加回答
举报