Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: eval string with \n at the end

How can I perform a eval on a string with \n ?

Why does this not work?

a = eval('"hello \n"')
In [70]: eval("\"hello \n\"")
  File "<string>", line 1
    "hello
          ^
SyntaxError: EOL while scanning string literal

Whereas this does

a = "hello \n"

My use case is that a script executed through subprocess is outputing a dictionary as a string of which I am capturing the stdout of it and I would like to perform an eval on it.

'''[
     { "hello": "the description of this is\' \n"}
]'''
like image 358
Har Avatar asked Jan 07 '23 20:01

Har


2 Answers

You need to escape the backslash.

>>> eval('"hello \n"')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    "hello
          ^
SyntaxError: EOL while scanning string literal
>>> eval('"hello \\n"')
'hello \n'
>>> print(eval('"hello \\n"'))
hello

>>>

Without that escape, Python will see this code (which is an obvious error):

"hello 
"

Rather than the desired code:

"hello \n"
like image 113
TigerhawkT3 Avatar answered Jan 15 '23 19:01

TigerhawkT3


If you want to specify a string that has a literal \ and n in it you either need to double the backslash, or use a raw string literal:

>>> '"hello\\n"'
'"hello\\n"'
>>> r'"hello\n"'
'"hello\\n"'

Such a string can then be evaluated as a Python expression containing a string literal:

>>> eval(r'"hello\n"')
'hello\n'

If your output is produced by a child process outputting the value with pprint.pprint(), you are doing more than just read that stream, as that produces perfectly valid Python syntax. Don't copy and paste that output into a Python interpreter, for example, because that'll just interpret the escape sequences directly (so before you pass it to eval()). If you are developing in an interpreter, you could use pprint.pformat() to produce a variable with the output, rather than write to stdout.

If you are trying to use Python repr() or pprint.pprint() output to pass data between systems, however, stop right there. Use a proper serialisation format instead, such as JSON. If that's not an option, at the very least use ast.literal_eval() to limit what your code accepts to only Python literals, and not arbitrary code (such as '__import__("os").system("rm -rf /")).

like image 23
Martijn Pieters Avatar answered Jan 15 '23 20:01

Martijn Pieters