diff options
author | lukaslihotzki-f <139768942+lukaslihotzki-f@users.noreply.github.com> | 2023-09-29 16:33:13 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-29 16:33:13 +0200 |
commit | 27bbff7c22663543bab0bf096f0b0a857ac4bcf7 (patch) | |
tree | d554c49920d84bf959636000406b10567b4639b7 | |
parent | Add intentional tests for module_utils/yumdnf.py (#81776) (diff) | |
download | ansible-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.yml | 3 | ||||
-rw-r--r-- | lib/ansible/plugins/filter/core.py | 8 | ||||
-rw-r--r-- | lib/ansible/plugins/filter/regex_replace.yml | 13 | ||||
-rw-r--r-- | test/integration/targets/filter_core/tasks/main.yml | 21 |
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: |