# backslashes in regex\_replace filter

**URL:** <https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642>\
**Category:** Ansible Project\
**Created:** [January 8, 2024, 9:15pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642 "2024-01-08T21:15:54Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [January 8, 2024, 9:15pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/1 "2024-01-08T21:15:54Z")

</div>

Hi - Does anyone (who understands how backslashes work in Ansible/YAML) know why both of the following tasks work:

(ansible2\_15\_8) rowagn@localhost:~#\> cat d.yml

- hosts: all  
gather\_facts: no  
vars:  
s: ‘This is a string containing 1 and 2.’  
t:
- p1\_xyz
- p2\_xyz
- p4\_xyz

tasks:

- name: single backslash  
debug:  
msg: ‘{{ item }} is in s’  
loop: ‘{{ t }}’  
when: ( item | regex\_replace(‘^p(\d+).\*$’, ‘\1’) ) in s

- name: double backslash  
debug:  
msg: ‘{{ item }} is in s’  
loop: ‘{{ t }}’  
when: ( item | regex\_replace(‘^p(\d+).\*$’, ‘\1’) ) in s

(ansible2\_15\_8) rowagn@localhost:~#\> ansible-playbook -i l d.yml

PLAY [all] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

TASK [single backslash] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> (item=p1\_xyz) =\> {  
“msg”: “p1\_xyz is in s”  
}  
ok: [localhost] =\> (item=p2\_xyz) =\> {  
“msg”: “p2\_xyz is in s”  
}  
skipping: [localhost] =\> (item=p4\_xyz)

TASK [double backslash] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> (item=p1\_xyz) =\> {  
“msg”: “p1\_xyz is in s”  
}  
ok: [localhost] =\> (item=p2\_xyz) =\> {  
“msg”: “p2\_xyz is in s”  
}  
skipping: [localhost] =\> (item=p4\_xyz)

PLAY RECAP \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

The tasks are extracting the number from the strings in list t and then looking for that number in string s. What is strange is the second example at [https://docs.ansible.com/ansible/latest/collections/ansible/builtin/regex\_replace\_filter.html#examples](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/regex_replace_filter.html#examples) indicates the backslashes in both parameters need to be doubled, but the above testing shows double backslashes are not required in the first parameter (they are required in the second parameter).

Thanks  
Rob

---

<div class="post-metadata">

**Author:** ![Walter\_Rowe](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/walter_rowe/32/4506_2.png) [@Walter\_Rowe](https://forum.ansible.com/u/Walter_Rowe)\
**Post date:** [January 8, 2024, 9:27pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/2 "2024-01-08T21:27:45Z")

</div>

> regex\_replace(‘^p(\d+).\*$’, ‘\1’)

‘\1’ in the second argument is a “backref” (backwards reference) to the (\d+) in the first argument. It seems it is looking for an expression with digits and extracting the digits.

Your list ‘t’ has names with p1\_xyz, p2\_xyz, p4\_xyx so this regex would extract the 1, 2, 4 digits from those strings.

Your string ‘s’ has digits 1 and 2. You are getting two lines of output as expected.

Walter

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [January 8, 2024, 9:51pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/3 "2024-01-08T21:51:50Z")

</div>

This is a result of some normalization code in jinja2 that attempts to unescape strings:

[https://github.com/pallets/jinja/blob/d594969d722ceb4e8f3da8861befc9c0ac87ae1b/src/jinja2/lexer.py#L647-L653](https://github.com/pallets/jinja/blob/d594969d722ceb4e8f3da8861befc9c0ac87ae1b/src/jinja2/lexer.py#L647-L653)

That code results in those becoming ‘^p(\d+).\*$’ and ‘\1’.

Those 2 when statements, when processed by pyyaml become:

[“( item | regex\_replace(‘^p(\d+)._$‘, ‘\\1’) ) in s",  
"( item | regex\_replace(’^p(\\d+)._$’, ‘\\1’) ) in s”]

Then if we apply the .encode/.decode:

> > > “( item | regex\_replace(‘^p(\d+)._$‘, ‘\\1’) ) in s".encode(“ascii”, “backslashreplace”).decode(“unicode-escape”)  
> > > "( item | regex\_replace(’^p(\d+)._$’, ‘\1’) ) in s”

> > > “( item | regex\_replace(‘^p(\\d+)._$‘, ‘\\1’) ) in s".encode(“ascii”, “backslashreplace”).decode(“unicode-escape”)  
> > > "( item | regex\_replace(’^p(\d+)._$’, ‘\1’) ) in s”

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [January 8, 2024, 11:57pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/4 "2024-01-08T23:57:49Z")

</div>

Thanks Matt, but I still don’t get why the first parameter (\d) MAY be double backslashed but the second parameter (\1) MUST be double backslashed. However, I’m starting to think it’s at the python level. [https://stackoverflow.com/a/33582215](https://stackoverflow.com/a/33582215) says Python’s string parser causes both \d and \d to become \d. But why? A little more searching takes me to [https://docs.python.org/3/reference/lexical\_analysis.html#escape-sequences](https://docs.python.org/3/reference/lexical_analysis.html#escape-sequences), where I think I see why \1 becomes \1 and \1 becomes a non-printable character (octal 1). But then, by analogy, \d should become \d (it does) but why doesn’t \d become an error (since it’s not listed as a valid escape sequence).

Maybe I’ll take this over to the Python list.

---

<div class="post-metadata">

**Author:** ![Walter\_Rowe](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/walter_rowe/32/4506_2.png) [@Walter\_Rowe](https://forum.ansible.com/u/Walter_Rowe)\
**Post date:** [January 9, 2024, 12:53pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/5 "2024-01-09T12:53:17Z")

</div>

The \1 must be double-backslashed because the backref needs to be backslash-digit (\1). Doubling the backslash escapes the backslash.

Walter

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [January 9, 2024, 2:04pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/6 "2024-01-09T14:04:14Z")

</div>

Right, but why doesn’t the \d need to be double-backslashed? Backslash-d is regex for matching on a digit. I just don’t get why doubling the backslash is needed on the 1 but not on the d.

---

<div class="post-metadata">

**Author:** ![Walter\_Rowe](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/walter_rowe/32/4506_2.png) [@Walter\_Rowe](https://forum.ansible.com/u/Walter_Rowe)\
**Post date:** [January 9, 2024, 2:19pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/7 "2024-01-09T14:19:14Z")

</div>

Perhaps because you have single quotes inside double quotes so everything inside the single quotes is automatically escaped?

Walter

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [January 9, 2024, 2:36pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/8 "2024-01-09T14:36:50Z")

</div>

But the \1 is also inside single and double quotes, so if that were the reason, I wouldn’t have to double backslash the 1

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [January 11, 2024, 11:18pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/9 "2024-01-11T23:18:39Z")

</div>

Part of the problem is also knowing what characters are escape sequences in python.

\1 is an escape sequence, equivalent to `\x01`, and not equivalent to the literal `\1`. As such a literal `\1` needs to be represented in python as `\\1`. \d is not an escape sequence and thus can be written as a literal `\d` without escaping the `\`

There is also a difference with quoting in YAML as mentioned above, between single quotes and double quotes. But note that the behavior of YAML with quotes only applies to quotes that surround the entire YAML value. So the single quotes you have in the middle of your string do not affect the YAML quoting differences. When not using quotes surrounding the full value in YAML, you are using “Plain Style” which has different rules than both single and double quoted values.

YAML single quotes are basically equivalent to python raw strings, where a backslash is always treated as literal. Double quotes require escaping backslashes. You can read more about the flow scalar styles of YAML at [https://yaml.org/spec/1.2.2/#73-flow-scalar-styles](https://yaml.org/spec/1.2.2/#73-flow-scalar-styles)

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [January 17, 2024, 6:43pm UTC](https://forum.ansible.com/t/backslashes-in-regex-replace-filter/38642/10 "2024-01-17T18:43:37Z")

</div>

Thanks everyone. I’m going to chalk this up to a Python anomaly. IMO, since \d is not a valid escape sequence, Python should raise an error rather than transparently converting it into \d.
