Regex patterns
Regex patterns
Section titled “Regex patterns”Regular expressions cover what exact lines and wildcards cannot: alternatives, number ranges, “only these and nothing else”. rConfig uses PHP (PCRE) regular expressions in four places, and they do not all treat flags and case the same way. This page shows each, with results asserted by the rConfig Pro test suite.
| Where | Applied to | Case by default |
|---|---|---|
must_match_regex, must_not_match_regex | The whole config as one block of text | Sensitive |
re: line in a code block method | One config line at a time | Insensitive, unless delimited without i |
regex: item in evaluate_block | The whole config, or the whole section when scoped | Sensitive |
must_match_regex
Section titled “must_match_regex”Write the pattern with delimiters and flags, PHP style: /pattern/flags. Because the pattern runs against the whole config at once:
- Without the
mflag,^and$mean the start and end of the whole config, not of a line. - Without the
sflag,.does not cross line breaks. - A JavaScript-style
gflag is accepted and has no effect on the result.
A pattern written without delimiters is wrapped in /.../ for you, with no flags. A pattern with an opening delimiter but no closing one never matches, so the rule fails rather than raising an error.
// Case-insensitive#[must_match_regex]/ip address/i
// Case-sensitive#[must_match_regex]/ip address/
// Start of a line#[must_match_regex]/^IP address/m
// Whole word#[must_match_regex]/\bTime\b/
// Partial word with boundaries#[must_match_regex]/\bTim\b/
// Alternation, any line#[must_match_regex]/^(?:IP|MAC) address: .+$/im
// Not present#[must_match_regex]/password: \w+/Against this text:
IP address: 192.0.2.1MAC address: 00:00:5E:00:53:01Time: 14:30:45Username: admin@example.com| Rule | Result |
|---|---|
/ip address/i | pass |
/ip address/ | fail |
/^IP address/m | pass |
/\bTime\b/ | pass |
/\bTim\b/ | fail |
/^(?:IP|MAC) address: .+$/im | pass |
/password: \w+/ | fail |
Source: PolicyMethodsTest::test_must_match_regex_with_various_patterns. Minimum version 8.0.0.
A network example: Junos set format
Section titled “A network example: Junos set format”// RSTP edge ports are configured#[must_match_regex]/^set protocols rstp interface (ge|xe|et)-\d+\/\d+\/\d+\.\d+ edge$/gm
// RSTP edge ports are disabled#[must_match_regex]/^set protocols rstp interface (ge|xe|et)-\d+\/\d+\/\d+\.\d+ disabled$/gmset protocols rstp interface ge-0/0/1.0 edgeset protocols rstp interface ge-0/0/2.0 edgeset protocols rstp interface ge-0/0/3.0 edgeset protocols rstp interface xe-0/0/3.0 edgeset protocols rstp interface xe-0/0/2.0 edgeset protocols rstp interface xe-0/0/1.0 edgeset protocols ospf area 0.0.0.0 interface ge-0/0/1.0set protocols rstp interface xe-0/0/2.0 edgesome other configuration lineset system services sshset protocols rstp interface et-0/0/3.0 edgeanother non-matching lineset protocols bgp group EXTERNAL-PEERS type externalset protocols rstp interface et-0/0/4.10 edgeset protocols rstp interface et-0/0/1.0 edgeset protocols rstp interface et-0/0/2.0 edgeset protocols rstp interface et-0/0/3.0 edge| Rule | Result |
|---|---|
| Edge ports configured | pass |
| Edge ports disabled | fail |
Source: PolicyMethodsTest::test_must_match_regex_with_gm_flags. The / characters inside the pattern are escaped as \/ because / is the delimiter.
must_not_match_regex
Section titled “must_not_match_regex”The inverse of must_match_regex: the rule passes when the pattern is not found. The same delimiter and flag rules apply.
// bridge1 does not have fast-forward enabled#[must_not_match_regex]/add name=bridge1 fast-forward=yes/m/interface bridgeadd name=bridge1 fast-forward=yesadd name=bridge2 fast-forward=no/interface ethernetset [find default-name=ether1] name=ether1-gatewayset [find default-name=ether2] name=ether2-local/ip dhcp-clientadd disabled=no interface=ether1-gatewayResult: fail, because the forbidden line is present. Source: PolicyMethodsTest::test_must_not_match_regex_pattern_found. Minimum version 8.0.2.
Allow-lists with lookaheads
Section titled “Allow-lists with lookaheads”Lookaheads let one pattern say “these must exist, and nothing else may”. The approved local accounts rule on the IOS-XE pages uses this technique, and its caution explains the one case it misses.
re: lines in code block methods
Section titled “re: lines in code block methods”In match_code_block_from_array, match_code_block_strict and match_code_block_flexible, a body line starting with re: is a regular expression tested against one config line at a time.
re:patternwithout delimiters is case-insensitive.re:/pattern/flagsuses exactly the flags you give. Leave outiand it is case-sensitive.
// Loopback0 description follows the naming standard#[match_code_block_from_array]re:^interface Loopback0$re:^\s*description LOOP:null:Loopback0:[a-z]{3}[0-9]{2}\.[a-z]{4}[0-9]{2}-[a-z]{2}:null:\[\]$interface Loopback0 description LOOP:null:Loopback0:lab01.site01-ar:null:[]interface GigabitEthernet1 description UplinkResult: pass. Source: PolicyMethodsTest::test_match_code_block_from_array_raw_regex_match and CustomerUseCases/MatchCodeBlockRawRegexCustomerTest.
With delimiters, case matters:
// Loopback0 description, case-sensitive#[match_code_block_from_array]re:/^interface Loopback0$/mre:/^\s*description LOOP:null:Loopback0:[a-z]{3}[0-9]{2}\.[a-z]{4}[0-9]{2}-[a-z]{2}:null:\[\]$/m
// Loopback0 description, case-insensitive#[match_code_block_from_array]re:/^interface Loopback0$/mire:/^\s*description LOOP:null:Loopback0:[a-z]{3}[0-9]{2}\.[a-z]{4}[0-9]{2}-[a-z]{2}:null:\[\]$/miinterface Loopback0 description LOOP:null:Loopback0:LAB01.SITE01-AR:null:[]| Rule | Result |
|---|---|
Case-sensitive (/m) | fail |
Case-insensitive (/mi) | pass |
Source: PolicyMethodsTest::test_match_code_block_from_array_raw_regex_case_sensitive_negative and test_match_code_block_from_array_delimited_regex_honors_flags. Minimum version 8.0.0.
regex: items in evaluate_block
Section titled “regex: items in evaluate_block”In an evaluate_block rule, a regex: item works like must_match_regex: it is tested against the whole config, or the whole section when the rule has a scope:. Quote the pattern in YAML.
// NTP configured, a known syslog host, and no telnet#[evaluate_block]all: - regex: "^ntp server " - any: - logging host 192.0.2.1 - logging host 192.0.2.2 - not: transport input telnetntp server 192.0.2.1logging host 192.0.2.2Result: pass. Source: Engine/PolicyExpressionEngineTest::test_whole_file_boolean_without_scope. Minimum version 8.3.0.