簡體   English   中英

如何將列表的字符串表示形式轉換為列表

[英]How to convert string representation of list to a list

我想知道最簡單的方法是將如下列表的字符串表示形式轉換為list

x = '[ "A","B","C" , " D"]'

即使在用戶在逗號之間放置空格和引號內放置空格的情況下,我也需要處理它並將其轉換為:

x = ["A", "B", "C", "D"] 

我知道我可以用strip()split()去除空格並檢查非字母字符。 但是代碼變得非常笨拙。 有我不知道的快速 function 嗎?

>>> import ast
>>> x = '[ "A","B","C" , " D"]'
>>> x = ast.literal_eval(x)
>>> x
['A', 'B', 'C', ' D']
>>> x = [n.strip() for n in x]
>>> x
['A', 'B', 'C', 'D']

ast.literal_eval

使用ast.literal_eval ,您可以安全地評估表達式節點或包含 Python 文字或容器顯示的字符串。 提供的字符串或節點只能由以下 Python 文字結構組成:字符串、字節、數字、元組、列表、字典、布爾值和None

每當有一個字符串化的字典列表時, json模塊是一個更好的解決方案。 json.loads(your_data)函數可用於將其轉換為列表。

>>> import json
>>> x = '[ "A","B","C" , " D"]'
>>> json.loads(x)
['A', 'B', 'C', ' D']

相似地

>>> x = '[ "A","B","C" , {"D":"E"}]'
>>> json.loads(x)
['A', 'B', 'C', {'D': 'E'}]

eval很危險——你不應該執行用戶輸入。

如果您有 2.6 或更高版本,請使用 ast 而不是 eval:

>>> import ast
>>> ast.literal_eval('["A","B" ,"C" ," D"]')
["A", "B", "C", " D"]

一旦你有了它, strip琴弦。

如果您使用的是舊版本的 Python,則可以使用簡單的正則表達式非常接近您想要的:

>>> x='[  "A",  " B", "C","D "]'
>>> re.findall(r'"\s*([^"]*?)\s*"', x)
['A', 'B', 'C', 'D']

這不如 ast 解決方案好,例如它不能正確處理字符串中的轉義引號。 但這很簡單,不涉及危險的 eval,如果您使用的是沒有 ast 的較舊的 Python,它可能足以滿足您的目的。

有一個快速的解決方案:

x = eval('[ "A","B","C" , " D"]')

可以通過以下方式刪除列表元素中不需要的空格:

x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]

受上述與基本 python 包一起使用的一些答案的啟發,我比較了一些(使用 Python 3.7.3)的性能:

方法一:ast

import ast
list(map(str.strip, ast.literal_eval(u'[ "A","B","C" , " D"]')))
# ['A', 'B', 'C', 'D']

import timeit
timeit.timeit(stmt="list(map(str.strip, ast.literal_eval(u'[ \"A\",\"B\",\"C\" , \" D\"]')))", setup='import ast', number=100000)
# 1.292875313000195

方法二:json

import json
list(map(str.strip, json.loads(u'[ "A","B","C" , " D"]')))
# ['A', 'B', 'C', 'D']

import timeit
timeit.timeit(stmt="list(map(str.strip, json.loads(u'[ \"A\",\"B\",\"C\" , \" D\"]')))", setup='import json', number=100000)
# 0.27833264000014424

方法三:不導入

list(map(str.strip, u'[ "A","B","C" , " D"]'.strip('][').replace('"', '').split(',')))
# ['A', 'B', 'C', 'D']

import timeit
timeit.timeit(stmt="list(map(str.strip, u'[ \"A\",\"B\",\"C\" , \" D\"]'.strip('][').replace('\"', '').split(',')))", number=100000)
# 0.12935059100027502

我很失望地看到我認為可讀性最差的方法是性能最好的方法......在使用最具可讀性的選項時需要考慮權衡......對於我通常使用 python 的工作負載類型比性能稍高的選項更重視可讀性,但像往常一樣,這取決於。

import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]

如果它只是一個一維列表,則無需導入任何內容即可完成:

>>> x = u'[ "A","B","C" , " D"]'
>>> ls = x.strip('[]').replace('"', '').replace(' ', '').split(',')
>>> ls
['A', 'B', 'C', 'D']

這個你能做到

**

x = '[ "A","B","C" , " D"]'
print(list(eval(x)))

** 最好的一個是公認的答案

盡管這不是一種安全的方法,但最好的答案是公認的。 發布答案時不知道評估危險。

假設您的所有輸入都是列表並且輸入中的雙引號實際上並不重要,這可以通過簡單的正則表達式替換來完成。 它有點 perl-y,但就像一個魅力。 另請注意,輸出現在是一個 unicode 字符串列表,您沒有指定您需要它,但考慮到 unicode 輸入,這似乎是有意義的。

import re
x = u'[ "A","B","C" , " D"]'
junkers = re.compile('[[" \]]')
result = junkers.sub('', x).split(',')
print result
--->  [u'A', u'B', u'C', u'D']

junkers 變量包含我們不想要的所有字符的編譯正則表達式(用於速度),使用 ] 作為字符需要一些反斜杠技巧。 re.sub 將所有這些字符都替換為空,我們在逗號處拆分結果字符串。

請注意,這也會從條目 u'["oh no"]' ---> [u'ohno'] 中刪除空格。 如果這不是您想要的,則需要對正則表達式進行一些改進。

無需導入任何東西,也無需評估。 對於大多數基本用例,包括原始問題中給出的用例,您可以在一行中執行此操作。

一個班輪

l_x = [i.strip() for i in x[1:-1].replace('"',"").split(',')]

解釋

x = '[ "A","B","C" , " D"]'
# str indexing to eliminate the brackets
# replace as split will otherwise retain the quotes in returned list
# split to conv to list
l_x = x[1:-1].replace('"',"").split(',')

輸出

for i in range(0, len(l_x)):
    print(l_x[i])
# vvvv output vvvvv
'''
 A
B
C 
  D
'''
print(type(l_x)) # out: class 'list'
print(len(l_x)) # out: 4

您可以根據需要使用列表推導解析和清理此列表。

l_x = [i.strip() for i in l_x] # list comprehension to clean up
for i in range(0, len(l_x)):
    print(l_x[i])
# vvvvv output vvvvv
'''
A
B
C
D
'''

嵌套列表

如果你有嵌套列表,它確實會更煩人。 不使用正則表達式(這將簡化替換),並假設您要返回一個扁平列表(並且python 的禪宗說 flat 比 nested 更好):

x = '[ "A","B","C" , " D", ["E","F","G"]]'
l_x = x[1:-1].split(',')
l_x = [i
    .replace(']', '')
    .replace('[', '')
    .replace('"', '')
    .strip() for i in l_x
]
# returns ['A', 'B', 'C', 'D', 'E', 'F', 'G']

如果您需要保留嵌套列表,它會變得有點丑陋,但仍然可以通過 re 和列表理解來完成:

import re
x = '[ "A","B","C" , " D", "["E","F","G"]","Z", "Y", "["H","I","J"]", "K", "L"]'
# clean it up so regex is simpler
x = x.replace('"', '').replace(' ', '') 
# look ahead for the bracketed text that signifies nested list
l_x = re.split(r',(?=\[[A-Za-z0-9\',]+\])|(?<=\]),', x[1:-1])
print(l_x)
# flatten and split the non nested list items
l_x0 = [item for items in l_x for item in items.split(',') if not '[' in items]
# convert the nested lists to lists
l_x1 = [
    i[1:-1].split(',') for i in l_x if '[' in i 
]
# add the two lists 
l_x = l_x0 + l_x1

最后一個解決方案適用於任何存儲為字符串的列表,無論是否嵌套。

如果您知道您的列表僅包含帶引號的字符串,則此 pyparsing 示例將為您提供已剝離字符串的列表(甚至保留原始的 Unicode-ness)。

>>> from pyparsing import *
>>> x =u'[ "A","B","C" , " D"]'
>>> LBR,RBR = map(Suppress,"[]")
>>> qs = quotedString.setParseAction(removeQuotes, lambda t: t[0].strip())
>>> qsList = LBR + delimitedList(qs) + RBR
>>> print qsList.parseString(x).asList()
[u'A', u'B', u'C', u'D']

如果您的列表可以有更多的數據類型,甚至在列表中包含列表,那么您將需要一個更完整的語法 - 就像 pyparsing 示例目錄中的這個語法,它將處理元組、列表、整數、浮點數和帶引號的字符串。

numpy這是一個非常簡單的方法

x = u'[ "A","B","C" , " D"]'
list_string = str(x)
import numpy as np
print np.array(list_string)

>>> 
[ "A","B","C" , " D"]

要使用 json 進一步完成@Ryan 的答案,轉換 unicode 的一個非常方便的功能是此處發布的功能: https ://stackoverflow.com/a/13105359/7599285

ex 帶雙引號或單引號:

>print byteify(json.loads(u'[ "A","B","C" , " D"]')
>print byteify(json.loads(u"[ 'A','B','C' , ' D']".replace('\'','"')))
['A', 'B', 'C', ' D']
['A', 'B', 'C', ' D']

當您將存儲為字符串的列表加載到 CSV 時,通常會發生這種情況

如果您將列表存儲在 CSV 格式中,例如 OP 詢問:

x = '[ "A","B","C" , " D"]'

以下是如何將其加載回列表:

import csv
with open('YourCSVFile.csv') as csv_file:
    reader = csv.reader(csv_file, delimiter=',')
    rows = list(reader)

listItems = rows[0]

listItems現在是列表

在處理存儲為 Pandas DataFrame 的抓取數據時,您可能會遇到此類問題。

如果值列表以 text 形式存在,則此解決方案的作用就像魅力一樣。

def textToList(hashtags):
    return hashtags.strip('[]').replace('\'', '').replace(' ', '').split(',')

hashtags = "[ 'A','B','C' , ' D']"
hashtags = textToList(hashtags)

Output: ['A', 'B', 'C', 'D']

不需要外部庫。

我想用正則表達式提供更直觀的模式解決方案。 下面的函數將包含任意字符串的字符串化列表作為輸入。

逐步解釋:您刪除所有空格、括號和 value_separators(前提是它們不是您要提取的值的一部分,否則會使正則表達式更復雜)。 然后將清理后的字符串拆分為單引號或雙引號,並取非空值(或奇數索引值,無論偏好如何)。

def parse_strlist(sl):
import re
clean = re.sub("[\[\],\s]","",sl)
splitted = re.split("[\'\"]",clean)
values_only = [s for s in splitted if s != '']
return values_only

testsample : "['21',"foo" '6', '0', "A"]"

因此,根據所有答案,我決定對最常用的方法進行計時:

from time import time
import re
import json


my_str = str(list(range(19)))
print(my_str)

reps = 100000

start = time()
for i in range(0, reps):
    re.findall("\w+", my_str)
print("Regex method:\t", (time() - start) / reps)

start = time()
for i in range(0, reps):
    json.loads(my_str)
print("json method:\t", (time() - start) / reps)

start = time()
for i in range(0, reps):
    ast.literal_eval(my_str)
print("ast method:\t\t", (time() - start) / reps)

start = time()
for i in range(0, reps):
    [n.strip() for n in my_str]
print("strip method:\t", (time() - start) / reps)



    regex method:    6.391477584838867e-07
    json method:     2.535374164581299e-06
    ast method:      2.4425282478332518e-05
    strip method:    4.983267784118653e-06

所以最終正則表達式獲勝!

您可以通過從列表的字符串表示中切掉第一個和最后一個字符來保存 .strip() fcn(請參見下面的第三行)

>>> mylist=[1,2,3,4,5,'baloney','alfalfa']
>>> strlist=str(mylist)
['1', ' 2', ' 3', ' 4', ' 5', " 'baloney'", " 'alfalfa'"]
>>> mylistfromstring=(strlist[1:-1].split(', '))
>>> mylistfromstring[3]
'4'
>>> for entry in mylistfromstring:
...     print(entry)
...     type(entry)
... 
1
<class 'str'>
2
<class 'str'>
3
<class 'str'>
4
<class 'str'>
5
<class 'str'>
'baloney'
<class 'str'>
'alfalfa'
<class 'str'>

並使用純 python - 不導入任何庫

[x for x in  x.split('[')[1].split(']')[0].split('"')[1:-1] if x not in[',',' , ',', ']]

這個解決方案比我上面讀到的更簡單,但需要匹配列表的所有功能

x = '[ "A","B","C" , " D"]'
[i.strip() for i in x.split('"') if len(i.strip().strip(',').strip(']').strip('['))>0]

['A B C D']

假設您的字符串是t_vector = [34,54,52,23],並且您想將其轉換為列表。 您可以使用以下2個步驟:

ls = t_vector.strip('][')
t_vector = ls.split(' ')

t_vector包含列表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM