リストの文字列表現をリストに変換する方法は?


531

私は最も簡単な方法は、変換することであるかと思ったstringに次のようなリストをlist

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

ユーザーがカンマの間にスペースを入れ、引用符の中にスペースを入れる場合でも。私もそれを処理する必要があります:

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

Pythonで。

私は、split演算子を使用してスペースを削除しstrip()split()アルファベット以外をチェックできることを知っています。しかし、コードは非常にぎこちなくなりました。気づかないクイック機能はありますか?


4
実際に何を達成しようとしていますか?Pythonリスト構文を実際のリストに変換しようとするよりもはるかに良い方法があると
Nicholas Knight

1
どのバージョンのPythonを使用していますか?
Mark Byers、

2
@Nicholas Knight:すべてのリストが角括弧の付いたUnicodeリストとして入力されたレガシーアプリでユーザー入力を処理しようとしています。@Mark Byers、私はpython 2.6を使用しているので、ast.literalアプローチが最も効果的です
harijay

回答:


769
>>> import ast
>>> x = u'[ "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式を含む文字列を安全に評価できます。提供される文字列またはノードは、文字列、数値、タプル、リスト、辞書、ブール値、およびNoneのPythonリテラル構造のみで構成されます。


6
以下のコメントによると、これは文字列内のpythonを実行するだけなので危険です。したがって、誰かがそこにあるすべてを削除するための呼び出しを行った場合、それは喜んでそうします。
ポールケンジョラ2017年

16
@PaulKenjora:evalではなくのことを考えていast.literal_evalます。
user2357112はモニカ

19
ast.literal_evalより安全よりもeval、実際にはありません安全ドキュメントの最新バージョンは、説明:「それを警告することは、PythonのASTコンパイラのスタックの深さ制限のために十分に大きい/複雑な文字列でPythonインタプリタをクラッシュさせることができます。」実際、私が知る限り誰もそのための概念実証を構築していませんが、注意深くスタックスマッシング攻撃を介して任意のコードを実行することは可能かもしれません。
abarnert 2018年

さて、リストに引用符がない場合はどうしますか?例[B of
4、1

84

jsonあるたびにモジュールがよりよい解決策である文字列化辞書のリストが。このjson.loads(your_data)関数を使用して、リストに変換できます。

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

同様に

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

ただし、Unicode形式で返されるリストは必要ありません。しかし、文字列からu ''を削除しても、データはUnicodeとして扱われます。
Mansoor Akram 2016年

7
これは整数では機能しますが、私の場合は文字列では機能しません。各文字列は二重引用符ではなく一重引用符で囲まれているためです。
ポールケンジョラ

4
@PaulKenjoraのコメントによると、それはに対しては機能します'["a","b"]'が、に対しては機能しません"['a','b']"
Skippy le Grand Gourou

83

これevalは危険です-ユーザー入力を実行しないでください。

2.6以降の場合は、evalの代わりにastを使用します。

>>> 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を使用している場合は、目的に十分対応できます。


eval危険です-ユーザー入力を実行してはいけない」と言った理由を教えてください。私は3.6を使用しています
Aaryan Dewan 2017

1
@AaryanDewanをeval直接使用すると、有効なすべてのpython式が評価されます。literal_evalは、Pythonのリテラル構造(文字列、数値、タプル、リスト、辞書、ブール値、およびなし)のみを評価することにより、この問題を解決します。
Abhishek Menon 2017

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

10

簡単な解決策があります:

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

リスト要素の不要な空白は、次の方法で削除できます。

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

これにより、引用符内のスペースが保持されます
tosh

17
これは、任意のコード実行へのオープンな招待です。入力が常に100%信頼されることが確実にわかっている場合を除いて、これを実行しないでください。
ニコラスナイト

1
データが常にその形式であり、データ処理作業であることがわかっていたので、この提案を使用できました。
マニッシュランジャン2016年

9

ベースPythonパッケージで動作する上記の回答のいくつかに触発されて、いくつかのパフォーマンスを比較しました(Python 3.7.3を使用)。

方法1: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

方法2: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

方法3:インポートしない

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

最悪の可読性を備えたメソッドが最高のパフォーマンスを備えたメソッドであると私が考えたのを見てがっかりしました...最も可読性の高いオプションを使用するときに考慮すべきトレードオフがあります...私が通常使用しているワークロードのタイプについてわずかにパフォーマンスの高いオプションでの値の読みやすさ。ただし、通常は状況によって異なります。


9

1次元のリストの場合は、何もインポートせずに実行できます。

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

8
注意:リスト内の文字列の間にカンマがある場合、これは潜在的に危険である可能性があります。
Hassan Kamal 2018年

文字列リストがリストのリストである場合、これは機能しません
crypdick

@crypdick良い点、それに関するメモを追加しました:)
ruohola

6

すべての入力がリストであり、入力内の二重引用符が実際には重要ではないと想定すると、これは単純な正規表現置換で実行できます。それは少しperl-yですが、魅力のように動作します。また、出力はユニコード文字列のリストになっていることにも注意してください。必要なことを指定していませんが、与えられたユニコード入力には意味があるようです。

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 ']内のスペースも削除されることに注意してください。これがあなたが望んだものでない場合、正規表現を少し上げる必要があります。


4

リストに引用符で囲まれた文字列のみが含まれていることがわかっている場合、このpyparsingの例では、ストリップされた文字列のリストが提供されます(元のUnicode性も保持されます)。

>>> 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']

あなたのリストはより多くのデータ型を持っている、あるいはリスト内のリストを含めることができる場合は、より完全な文法が必要になります-のように、この1タプル、リスト、int型、浮動小数点数、および引用符で囲まれた文字列を処理するpyparsingのwikiに、。2.4に戻るPythonバージョンで動作します。


「parseString()。asList()」の使用方法を教えていただけますか。この種類の文字列がある場合: '["A"、 "B"、 "C"、["D"]]' pyparsingもそれができると述べました。しかし、それを行う正しい方法を見つけていないようです。
Mansoor Akram 2016年

「リストにさらに多くのデータ型を含めることができる場合、またはリスト内にリストを含めることもできる場合は、より完全な文法が必要になります」-ネストされたリストやその他のさまざまなデータ型を処理するパーサーの回答で提供したリンクを参照してください。
PaulMcG 2016年

Pyparsingはウィキスペースでホストされなくなりました。parsePythonValue.py例はでGitHubの上で今あるgithub.com/pyparsing/pyparsing/blob/master/examples/...
PaulMcG

1

jsonを使用して@Ryanの回答をさらに完成させるために、ユニコードを変換する非常に便利な関数の1つは、ここに投稿されたものです:https ://stackoverflow.com/a/13105359/7599285

二重引用符または単一引用符付きの例:

>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']

0

regexを使用して、より直感的なパターン化ソリューションを提供したいと思います。以下の関数は、任意の文字列を含む文字列化されたリストを入力として受け取ります。

段階的な説明: すべてのwhitespacing、bracketing、および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 "]"



0

Pandas DataFrameとして保存されているスクレイピングデータを処理しているときに、このような問題に遭遇する可能性があります。

リストがテキストとして存在する場合、このソリューションはチャームのように機能します

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

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

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

外部ライブラリは必要ありません。


-1

だから、すべての答えに従って、私は最も一般的な方法を計ることに決めました:

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

結局、正規表現が勝利します!


-1

リストの文字列表現から最初と最後の文字をスライスするだけで、.strip()fcnを節約できます(以下の3行目を参照)

>>> 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'>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.