如何在 jinja2 中 select 正则表达式匹配?

how to select regex matches in jinja2?

玩具示例

基本上,我想做类似的事情:

['hello', 'apple', 'rare', 'trim', 'three'] | select(match('.*a[rp].*'))

这会产生:

['apple', 'rare']

我在说什么?

match filter and select 过滤器。我的问题源于 select 过滤器仅支持一元 "tests".

我在使用 Ansible 1。9.x。

我的实际用例

...更接近于:

lookup('dig', ip_address, qtype="PTR", wantList=True) | select(match("mx\..*\.example\.com"))

所以,我想获取与某个 IP 关联的所有 PTR 记录,然后过滤掉所有不符合给定正则表达式的记录。我还想确保结果列表中只有一个元素,并输出该元素,但这是一个不同的问题。

这样行吗?

---
- 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] }}"

更新:它是如何工作的...

  • map 应用 过滤器 – 过滤器不是 yes/no 东西,它们应用于 输入列表的每个项目和修改项目的 return 列表。我用 regex_search 过滤器,每个项目的搜索模式 return 如果找到匹配项或 None 如果没有匹配项。所以在这一步我得到 此列表:[null, "apple", "rare", null, null].

  • 然后我们使用select,它应用测试——测试是yes/no的东西,所以 他们根据选定的测试减少列表。我使用 string 测试,这是 当列表项为字符串时为真。所以我们得到:["apple", "rare"].

  • mapselect 给了我们一些内部 python 类型,所以我们转换为列表 毕竟应用 list 过滤器。

这个设计模式对我有用:

----
- 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"

如果你想在 Ansible 中过滤列表(获取具有空值的列表并与空列表进行区分),我发现了以下技巧:

---
- 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 }}"

这是输出:

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

您可以这样使用 select

['hello', 'apple', 'rare', 'trim', 'three'] | select('match', '.*a[rp]')

这会产生:

['apple', 'rare']

match uses the re.match 实现,因此匹配字符串的开头。因此你需要 .* 在开头,而不是在正则表达式的结尾。

或者您可以使用 search 来完全避免 .*

['hello', 'apple', 'rare', 'trim', 'three'] | select('search', 'a[rp]')