Count substituted values with subn
Also published in our primary archive.
re.subn() performs a substitution and returns two values: the resulting string and the number of substitutions made. That count is valuable when code must report exactly how many values were redacted or verify an expected fixture. In this example, a compiled pattern finds synthetic token= fields and replaces each value while leaving the field name and separators intact.
The replacement function receives a match object. It returns token= followed by a fixed marker, which avoids carrying the original synthetic value into the output. The assertions verify both pieces of the subn() result: the count is two and the full transformed string has the intended contents. Printing the transformed line and count produces deterministic output.
The count represents successful non-overlapping pattern substitutions, not a guarantee that every sensitive value in a real input was recognized. A different spelling, quoting convention, or multiline layout may need a different pattern. Regex redaction also deserves careful tests when inputs can contain escaped delimiters or structured formats; parsing that format may be safer and easier to maintain. Here the input is intentionally narrow and synthetic so the behavior is inspectable.
re.subn() is available in supported Python 3 releases; this example relies on no newer standard-library API.
AI assistance disclosure: This article was drafted with AI assistance and checked against the cited Python documentation.
Sources: Python re.subn and Python match objects.
import re
line = "user=ana token=abc123 action=read token=xyz789"
pattern = re.compile(r"token=[A-Za-z0-9]+")
redacted, replacements = pattern.subn(lambda match: "token=<redacted>", line)
assert replacements == 2
assert redacted == "user=ana token=<redacted> action=read token=<redacted>"
assert "abc123" not in redacted and "xyz789" not in redacted
print(redacted)
print(f"replacements={replacements}")
user=ana token=<redacted> action=read token=<redacted>
replacements=2