The "[]" is simple since I can just check if value == "[]" then return []
But with "['a','b']" I have tried and get:
a="['a','b']"
b=a[1:-1].split(',')
returns
[ " 'a' "," 'b' " ]
when I want it to return ['a','b'].
How can I do this?
thx,
-wes
The potentially problematic exec or eval options left aside,
if you really need to do this, you might consider pyparsing; check the example
http://pyparsing.wikispaces.com/file/view/parsePythonValue.py
If you know, the input string will always have this exact format
(single quoted comma separated one-character strings between square
brackets), you might use regular expressions to some extent, e.g.
print re.findall(r"(?<=')\w(?=')", "['a','b','c','b','A']")
['a', 'b', 'c', 'b', 'A']
hth,
vbr
> I have been trying to create a list form a string. The string will be
> a list (this is the contents will look like a list). i.e. "[]" or
> "['a','b']"
If your string is trusted (i.e. goes nowhere near a user), just eval() it.
--
Rhodri James *-* Wildebeeste Herder to the Masses
> On Wed, 17 Feb 2010 23:48:38 -0000, Wes James <comp...@gmail.com>
> wrote:
>
>> I have been trying to create a list form a string. The string will be
>> a list (this is the contents will look like a list). i.e. "[]" or
>> "['a','b']"
>
> If your string is trusted (i.e. goes nowhere near a user), just eval()
> it.
Or use something like YAML or JSON to parse it.
Fredrik Lundh has a simple_eval function which should be safe to use:
http://effbot.org/zone/simple-iterator-parser.htm
But it's fairly simple to parse a simple list like this. Here's a quick
and dirty version:
def string_to_list(s):
s = s.strip()
if not s.startswith('[') and s.endswith(']'):
raise ValueError
s = s[1:-1].strip()
items = [item.strip() for item in s.split(',')]
for i, item in enumerate(items):
items[i] = dequote(item)
return items
def dequote(s):
for delimiter in ('"""', "'''", '"', "'"):
if s.startswith(delimiter) and s.endswith(delimiter):
n = len(delimiter)
return s[n:-n]
raise ValueError
>>> s = "['a','b']"
>>> print s
['a','b']
>>> string_to_list(s)
['a', 'b']
>>> x = string_to_list(s)
>>> type(x)
<type 'list'>
>>> x
['a', 'b']
--
Steven
>
> I have been trying to create a list form a string. The string will be
> a list (this is the contents will look like a list). i.e. "[]" or
> "['a','b']"
>
> The "[]" is simple since I can just check if value == "[]" then return []
>
> But with "['a','b']" I have tried and get:
>
> a="['a','b']"
>
> b=a[1:-1].split(',')
>
> returns
>
> [ " 'a' "," 'b' " ]
>
> when I want it to return ['a','b'].
>
> How can I do this?
eval will work, but has a safety issue. It also has the issue of evaluating any
and everything that a user might pass in.
If you are using python 2.6 check out ast.literal_eval. It uses python's built
in ast parser to generate an AST and then traverses it to generate a python
object. Unlike eval though, it will raise an exception if anything other than a
literal is represented in the string. I have used the same function in python
2.5 (copied from 2.6) and it works just fine.
Here is a version modified from the code in python 2.6 that should only parse
lists of strings:
from _ast import List, Str, PyCF_ONLY_AST
def parse(expr, filename='<unknown>', mode='exec'):
"""
Parse an expression into an AST node.
Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST).
"""
return compile(expr, filename, mode, PyCF_ONLY_AST)
def list_eval(text):
"""
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the following
Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
and None.
"""
node = parse(text, mode='eval').body
if not isinstance(node, List):
raise ValueError('malformed string')
def _convert(node):
if isinstance(node, Str):
return node.s
raise ValueError('malformed string')
return list(map(_convert, node.elts))
Matt McCredie
> I have been trying to create a list form a string. The string will be
> a list (this is the contents will look like a list). i.e. "[]" or
> "['a','b']"
Pulling back to ask about the larger problem: Are you trying to create
Python data structures from a serialised representation?
There are several well-implemented solutions, including the standard
library modules ‘pickle’ and ‘json’. Do you have control over the choice
of serialisation format?
--
\ “I went to court for a parking ticket; I pleaded insanity. I |
`\ said ‘Your Honour, who in their right mind parks in the passing |
_o__) lane?’” —Steven Wright |
Ben Finney
I am surprised nobody gave you the simple answer yet that may even
work for your situation:
b=a[2:-2].split("','")
Just to add to the list of solutions I've seen, letting the
built-in csv module do the heavy lifting:
>>> s = "['a','b']"
>>> import csv
>>> no_brackets = s[1:-1] # s.strip(' \t[]')
>>> c = csv.reader([no_brackets], quotechar="'")
>>> c.next()
['a', 'b']
This also gives you a bit of control regarding how escaping is
done, and other knobs & dials to twiddle if you need.
Additionally, if you have more than one string to process coming
from an iterable source (such as a file), you can just pass that
iterator to csv.reader() instead of concocting a one-element list.
-tkc
>
> Just to add to the list of solutions I've seen, letting the built-in csv
> module do the heavy lifting:
>
> >>> s = "['a','b']"
> >>> import csv
> >>> no_brackets = s[1:-1] # s.strip(' \t[]')
> >>> c = csv.reader([no_brackets], quotechar="'")
> >>> c.next()
> ['a', 'b']
>
> This also gives you a bit of control regarding how escaping is done, and
> other knobs & dials to twiddle if you need. Additionally, if you have more
> than one string to process coming from an iterable source (such as a file),
> you can just pass that iterator to csv.reader() instead of concocting a
> one-element list.
Thx, I think this will work for what I want.
-wes
Hmm. When I put csv.reader in a class:
import csv
class IS_LIST():
def __init__(self, format='', error_message='must be a list!'):
self.format = format
self.error_message = error_message
def __call__(self, value):
try:
if value=='[]' or value=='':
value=[]
else:
no_brackets = value[1:-1] # s.strip(' \t[]')
c = csv.reader([no_brackets], quotechar="'")
value=c.next()
return (value, None)
except:
return (value, self.error_message)
def formatter(self, value):
return value
I get an error (when I take the "try" out):
AttributeError: 'function' object has no attribute 'reader'
Why?
-wes
A couple ideas occur to me:
1) you haven't copy/pasted the exact (or entirety of the) code,
and something you're doing is shadowing the "csv" module
2) are you using Python 2.x or 3.x? I don't know if the csv
module has changed in 3.x but it should work in 2.x
The first thing to check would be to pull up a raw python prompt
and see if your csv module has the expected reader:
>>> import csv
>>> csv.reader
<built-in function reader>
If not, something likely changed in 3.x and you'd have to inspect
the docs to see what happened to the reader.
If you get the above evidence of an existing reader, then you're
likely shadowing it.
-tkc
You have a function called "csv" that's defined after the import csv
statement is executed. That function has no attribute 'reader", so you
get the error. By the way, don't use a bare except- it's bad form
because it hides any other problems you have.
Two important points:
* Don't use bare except: clauses
* Put less code in the try: clause to make it easier to track down
problems
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/
"At Resolver we've found it useful to short-circuit any doubt and just
refer to comments in code as 'lies'. :-)"
Because it's really *very* not robust. "Harmless" whitespace defeats it
for starters, and that's one of the most likely things to vary between
example data and reality. If you trust your data to be well-formed enough
for this to work, you might as well use eval() instead. If you don't,
parsing is the only sensible answer.