66

I'm trying to escape the characters -]\^$*. each with a single backslash \.

For example the string: ^stack.*/overflo\w$arr=1 will become:

\^stack\.\*/overflo\\w\$arr=1

What's the most efficient way to do that in Python?

re.escape double escapes which isn't what I want:

'\\^stack\\.\\*\\/overflow\\$arr\\=1'

I need this to escape for something else (nginx).

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Tom
  • 9,275
  • 25
  • 89
  • 147
  • 1
    "`re.escape` double escapes which isn't what I want:" No, it doesn't; and yes, it is. The string shown here contains single backslashes, not double backslashes. They are **represented as** double backslashes for the same reason that there are single quotes surrounding it: because you are looking at a **representation of** the string as though it were Python source code. See [why do backslashes appear twice?](https://stackoverflow.com/questions/24085680/). – Karl Knechtel Aug 07 '22 at 11:33

6 Answers6

154

This is one way to do it (in Python 3.x):

escaped = a_string.translate(str.maketrans({"-":  r"\-",
                                          "]":  r"\]",
                                          "\\": r"\\",
                                          "^":  r"\^",
                                          "$":  r"\$",
                                          "*":  r"\*",
                                          ".":  r"\."}))

For reference, for escaping strings to use in regex:

import re
escaped = re.escape(a_string)
rlms
  • 10,650
  • 8
  • 44
  • 61
  • @hcwhsa `string.translate` as in `a_variable_called_string.translate`, rather than a function called translate in the module string. – rlms Sep 21 '13 at 18:23
  • 2
    Should mention, maketrans is in python 3, not python 2.x – Ashwini Khare Jun 23 '15 at 17:50
  • 3
    `maketrans()` is still in Python 2. It's in the string module, not the str object: https://docs.python.org/2/library/string.html#string.maketrans – OozeMeister Oct 13 '17 at 17:25
  • 1
    maketrans in python2 behaves very differently, requiring the input and output strings to be of the same length, and it doesn't accept dictionary inputs. It's not so good for doing these kinds of translations. – Twirrim Dec 04 '19 at 17:43
23

Just assuming this is for a regular expression, use re.escape.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Note in lieu of dv: The author edited the question after this answer was posted to clarify that re.escape isn't what they're looking for. – Air Apr 28 '15 at 23:24
  • 5
    @Air: I’ll look into exact incompatibilities at some point, but the author of the question was under the impression that it didn’t work because it double-escaped, but that was because they were using it in the REPL and that was the `repr()`. It doesn’t actually do that and does work in Nginx for the example given. – Ry- Apr 29 '15 at 02:24
15

We could use built-in function repr() or string interpolation fr'{}' escape all backwardslashs \ in Python 3.7.*

repr('my_string') or fr'{my_string}'

Check the Link: https://docs.python.org/3/library/functions.html#repr

Saguoran
  • 177
  • 1
  • 5
  • 3
    Doing `fr'{my_string}'` **will not change the string contents**. It is equivalent to `f'{my_string}'` (because the `r` only applies at the time the *string literal* is interpreted, and none of `{`, `m`, `y`, `_`, `s`, `t`, `r`, `i`, `n`, `g`, `}` require escaping), which is equivalent to `str(my_string)` (because that's what the f-string will end up doing), which is equivalent to `my_string` (because it was already a string). This doesn't solve the problem because it requires the *code that created `my_string` to have already solved the problem*. – Karl Knechtel Aug 08 '22 at 04:21
  • As for `repr`, it will also surround the string in quotes, which may not be desired; and out of the characters described, it will **only** escape the backslash - did you **try it**? *This answer is completely wrong.* – Karl Knechtel Aug 08 '22 at 04:23
13

re.escape doesn't double escape. It just looks like it does if you run in the repl. The second layer of escaping is caused by outputting to the screen.

When using the repl, try using print to see what is really in the string.

$ python
>>> import re
>>> re.escape("\^stack\.\*/overflo\\w\$arr=1")
'\\\\\\^stack\\\\\\.\\\\\\*\\/overflo\\\\w\\\\\\$arr\\=1'
>>> print re.escape("\^stack\.\*/overflo\\w\$arr=1")
\\\^stack\\\.\\\*\/overflo\\w\\\$arr\=1
>>>
rjmunro
  • 27,203
  • 20
  • 110
  • 132
4

Simply using re.sub might also work instead of str.maketrans. And this would also work in python 2.x

>>> print(re.sub(r'(\-|\]|\^|\$|\*|\.|\\)',lambda m:{'-':'\-',']':'\]','\\':'\\\\','^':'\^','$':'\$','*':'\*','.':'\.'}[m.group()],"^stack.*/overflo\w$arr=1"))
\^stack\.\*/overflo\\w\$arr=1
Akshay Hazari
  • 3,186
  • 4
  • 48
  • 84
-1

Utilize the output of built-in repr to deal with \r\n\t and process the output of re.escape is what you want:

re.escape(repr(a)[1:-1]).replace('\\\\', '\\')
cyining
  • 23
  • 4