RegEx Range: answer key
Every question with its answer and the reasoning. Work the drill first, or the key only tells you what, not how.
-
Find any mention of PowerShell in a log line. Plain characters in a regex match themselves, so no special syntax is needed yet.
Answer: powershell
powershell (or any pattern containing it) matches every should-match case because plain characters match themselves literally. This is the baseline every other regex feature builds on top of.
-
Match a drive-letter reference to C:, D:, or E:, but not other drive letters. [ABC] matches any ONE of the characters inside the brackets.
Answer: [CDE]:
[CDE]: matches a single C, D, or E immediately followed by a colon. A bracket character class is an OR across individual characters, distinct from alternation (|) which ORs whole sub-patterns (you'll meet that in a later challenge).
-
Match a process-ID-looking reference of 4 or more digits in a row (real Windows PIDs are rarely shorter).
Answer: \d{4,}
\d{4,} (equally [0-9]{4,}) matches four or more consecutive digits. {min,} with nothing after the comma means "at least min, unlimited max". {min,max} would cap it, and {exact} would require exactly that many.
-
Match lines that START with the word ERROR, not lines where ERROR merely appears somewhere inside.
Answer: ^ERROR
^ERROR only matches when ERROR is the very first thing in the string. Without the anchor, plain ERROR would also match 'Got ERROR from server', which is exactly what the should-NOT-match cases are testing for.
-
Match a mention of one of three commonly-abused script extensions: vbs, ps1, or bat.
Answer: vbs|ps1|bat
vbs|ps1|bat matches any one of three literal alternatives. Alternation is how a single pattern accepts several genuinely different substrings, not just different single characters.
-
Match the literal text '4624' followed by a period, but not '4624' followed by any OTHER single character. A bare . normally matches ANY character.
Answer: 4624\.
4624\. escapes the dot so it matches a literal period only. Without the backslash, . would match ANY character right after 4624, including the '9' in '46249' and the 'X' in '4624X', which is exactly what those should-NOT-match cases are built to catch.
-
Match the standalone word 'admin' as a username, not as part of a longer word like 'administrator' or 'badmin'.
Answer: \badmin\b
\badmin\b only matches 'admin' as a complete word. The boundaries on each side stop it from also matching inside 'administrator' or 'badmin_tool'. Without them, plain admin would match all five test cases, not just the first two.
-
Match a bracketed severity tag that is NOT [INFO], e.g. [WARN], [ERROR], [CRIT]. A caret right after the opening bracket of a character class negates it.
Answer: \[[^I]
\[[^I] matches an opening bracket followed by any character that isn't 'I'. Since INFO is the only tag here starting with I, that's enough to separate it from WARN/ERROR/CRIT. It is a classic minimal-pattern move: exploit whatever detail actually distinguishes YOUR data, rather than exhaustively spelling out every valid tag. A more bulletproof real-world version would use a negative lookahead, \[(?!INFO\]), which you'll meet in a later challenge.
-
Detect a word typed twice in a row with a space between (a common paste-duplication artifact). Match only when the SAME word repeats.
Answer: \b(\w+) \1\b
(\w+) captures a run of word characters, and \1 requires that SAME captured text to appear again right after a space. A backreference is the only way to require two parts of a match to be identical without knowing the word in advance: you cannot express "whatever this matched, again" with a character class or quantifier alone.
-
Match a credential-looking token containing BOTH a digit and an uppercase letter, in any order.
Answer: (?=.*[0-9])(?=.*[A-Z])
(?=.*[0-9]) asserts a digit exists somewhere ahead; (?=.*[A-Z]) asserts an uppercase letter exists somewhere ahead. Together they require both, in either order: an order-independent AND. A sequential pattern like [0-9].*[A-Z]|[A-Z].*[0-9] could do the same for two conditions, but a lookahead chain stays simple as more conditions stack up, where the alternation approach grows combinatorially worse.
-
Final challenge: match a genuine IPv4 address (four dot-separated numbers, each in the real 0-255 range) while correctly REJECTING an out-of-range octet like 300 or 999. Counting digits alone will not be enough here.
Answer: \b(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}\b
This is a simplified form of the exact pattern this site's own Regex Tester ships with for IPv4 detection (see the Pattern library above, or the live tool linked below). Counting digits alone (\d{1,3} four times) is not enough. It would also accept '300' or '999' as a valid octet, which is exactly what the should-NOT-match cases test for. Range-checking each octet with alternation (25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d) is what correctly rejects an out-of-range value while still accepting every real 0-255 octet.
Read more: See the full pattern in the Regex Tester