summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlukaslihotzki-f <139768942+lukaslihotzki-f@users.noreply.github.com>2023-09-29 16:33:13 +0200
committerGitHub <noreply@github.com>2023-09-29 16:33:13 +0200
commit27bbff7c22663543bab0bf096f0b0a857ac4bcf7 (patch)
treed554c49920d84bf959636000406b10567b4639b7
parentAdd intentional tests for module_utils/yumdnf.py (#81776) (diff)
downloadansible-27bbff7c22663543bab0bf096f0b0a857ac4bcf7.tar.xz
ansible-27bbff7c22663543bab0bf096f0b0a857ac4bcf7.zip
Add count and mandatory_count parameters in regex_replace filter (#81775)
-rw-r--r--changelogs/fragments/81775-add-regex_replace-parameters.yml3
-rw-r--r--lib/ansible/plugins/filter/core.py8
-rw-r--r--lib/ansible/plugins/filter/regex_replace.yml13
-rw-r--r--test/integration/targets/filter_core/tasks/main.yml21
4 files changed, 43 insertions, 2 deletions
diff --git a/changelogs/fragments/81775-add-regex_replace-parameters.yml b/changelogs/fragments/81775-add-regex_replace-parameters.yml
new file mode 100644
index 0000000000..1bca5c7ded
--- /dev/null
+++ b/changelogs/fragments/81775-add-regex_replace-parameters.yml
@@ -0,0 +1,3 @@
+---
+minor_changes:
+ - filter plugin - Add the count and mandatory_count parameters in the regex_replace filter
diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py
index 09820faa7c..c0aa394b29 100644
--- a/lib/ansible/plugins/filter/core.py
+++ b/lib/ansible/plugins/filter/core.py
@@ -121,7 +121,7 @@ def fileglob(pathname):
return [g for g in glob.glob(pathname) if os.path.isfile(g)]
-def regex_replace(value='', pattern='', replacement='', ignorecase=False, multiline=False):
+def regex_replace(value='', pattern='', replacement='', ignorecase=False, multiline=False, count=0, mandatory_count=0):
''' Perform a `re.sub` returning a string '''
value = to_text(value, errors='surrogate_or_strict', nonstring='simplerepr')
@@ -132,7 +132,11 @@ def regex_replace(value='', pattern='', replacement='', ignorecase=False, multil
if multiline:
flags |= re.M
_re = re.compile(pattern, flags=flags)
- return _re.sub(replacement, value)
+ (output, subs) = _re.subn(replacement, value, count=count)
+ if mandatory_count and mandatory_count != subs:
+ raise AnsibleFilterError("'%s' should match %d times, but matches %d times in '%s'"
+ % (pattern, mandatory_count, count, value))
+ return output
def regex_findall(value, regex, multiline=False, ignorecase=False):
diff --git a/lib/ansible/plugins/filter/regex_replace.yml b/lib/ansible/plugins/filter/regex_replace.yml
index 8c8d0afe15..76f9688817 100644
--- a/lib/ansible/plugins/filter/regex_replace.yml
+++ b/lib/ansible/plugins/filter/regex_replace.yml
@@ -28,6 +28,16 @@ DOCUMENTATION:
description: Force the search to be case insensitive if V(True), case sensitive otherwise.
type: bool
default: no
+ count:
+ description: Maximum number of pattern occurrences to replace. If zero, replace all occurrences.
+ type: int
+ default: 0
+ version_added: "2.17"
+ mandatory_count:
+ description: Except a certain number of replacements. Raises an error otherwise. If zero, ignore.
+ type: int
+ default: 0
+ version_added: "2.17"
EXAMPLES: |
@@ -46,6 +56,9 @@ EXAMPLES: |
# piratecomment => '#CAR\n#tar\nfoo\n#bar\n'
piratecomment: "{{ 'CAR\ntar\nfoo\nbar\n' | regex_replace('(?im)^(.ar)$', '#\\1') }}"
+ # 'foo=bar=baz' => 'foo:bar=baz'
+ key_value: "{{ 'foo=bar=baz' | regex_replace('=', ':', count=1) }}"
+
RETURN:
_value:
description: String with substitution (or original if no match).
diff --git a/test/integration/targets/filter_core/tasks/main.yml b/test/integration/targets/filter_core/tasks/main.yml
index 9d287a187d..9493b69d55 100644
--- a/test/integration/targets/filter_core/tasks/main.yml
+++ b/test/integration/targets/filter_core/tasks/main.yml
@@ -335,6 +335,27 @@
that:
- '"hElLo there"|regex_replace("hello", "hi", ignorecase=True) == "hi there"'
+- name: Verify regex_replace with count
+ assert:
+ that:
+ - '"foo=bar=baz"|regex_replace("=", ":", count=1) == "foo:bar=baz"'
+
+- name: Verify regex_replace with correct mandatory_count
+ assert:
+ that:
+ - '"foo=bar=baz"|regex_replace("=", ":", mandatory_count=2) == "foo:bar:baz"'
+
+- name: Verify regex_replace with incorrect mandatory_count
+ debug:
+ msg: "{{ 'foo=bar=baz'|regex_replace('=', ':', mandatory_count=1) }}"
+ ignore_errors: yes
+ register: incorrect_mandatory_count
+
+- assert:
+ that:
+ - "incorrect_mandatory_count is failed"
+ - "' times, but matches ' in incorrect_mandatory_count.msg"
+
- name: Verify case-insensitive regex_findall
assert:
that: