how to select regex matches in jinja2?

I found the following trick if you want to filter a list in Ansible (get the list with null values and make difference with null list) :

---
- hosts: localhost
  connection: local
  vars:
    regexp: '.*a[rp].*'
    empty: [null]
  tasks:
    - set_fact: matches="{{ ['hello', 'apple', 'rare', 'trim', 'three'] | map('regex_search',regexp)  | list|difference(empty) }}"
    - debug: msg="{{ matches }}"

Here is the output :

ok: [localhost] => {
    "msg": [
        "apple", 
        "rare"
    ]
}

Will this do?

---
- hosts: localhost
  connection: local
  vars:
    my_list: ['hello', 'apple', 'rare', 'trim', 'three']
    my_pattern: '.*a[rp].*'
  tasks:
    - set_fact: matches="{{ my_list | map('regex_search',my_pattern) | select('string') | list }}"
      failed_when: matches | count > 1
    - debug: msg="I'm the only one - {{ matches[0] }}"

Update: how it works...

  • map applies filters – filters are not yes/no things, they applied to every item of input list and return list of modified items. I use regex_search filter, which search pattern in every item and return a match if found or None if there is no match. So on this step I get this list: [null, "apple", "rare", null, null].

  • Then we use select, which applies tests – tests are yes/no things, so they reduce the list based on selected test. I use string test, which is true when item of a list is string. So we get: ["apple", "rare"].

  • map and select give us some internal python types, so we convert to list by applying list filter after all.


This design pattern worked for me:

----
- hosts: localhost
  connection: local
  vars:
    my_list: ['hello', 'apple', 'rare', 'trim', "apropos", 'three']
    my_pattern: 'a[rp].*'
  tasks:
    - set_fact:
        matches: "{%- set tmp = [] -%}
                  {%- for elem in my_list | map('match', my_pattern) | list -%}
                    {%- if elem -%}
                      {{ tmp.append(my_list[loop.index - 1]) }}
                    {%- endif -%}
                  {%- endfor -%}
                  {{ tmp }}"
    - debug:
        var: matches
      failed_when: "(matches | length) > 1"