We use cookies to enhance your experience on the site
CodeWorlds

Regular Expressions

At the Jurassic Park control center, Dennis Nedry has just received a task: search thousands of system logs for anomalies. "I'm not going to browse through this manually," he mutters. "I'll use regular expressions — the most powerful tool for finding patterns in text!"

What Are Regular Expressions?

Regular expressions (RegEx or RegExp) are patterns used to match character strings in text. They're like "search DNA" — they define exactly what we're looking for.

1// Simplest regular expression — searching for exact text
2const dinoIdPattern = /RAPTOR-d+/;
3console.log(dinoIdPattern.test("RAPTOR-001")); // true
4console.log(dinoIdPattern.test("TREX-001"));   // false
5
6// Creating with the RegExp constructor
7const speciesPattern = new RegExp("Velociraptor", "i"); // i = case insensitive
8console.log(speciesPattern.test("velociraptor")); // true

Creating Regular Expressions

1// Literal notation
2const literal = /pattern/flags;
3
4// Constructor notation
5const constructor = new RegExp("pattern", "flags");
6
7// Examples
8const emailPattern = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}/;
9const dinoIdPattern = /^[A-Z]{2,6}-d{3}$/;

Regular Expression Methods

1const log = "2024-01-15 10:30:45 [RAPTOR-001] STATUS: escaped, SECTOR: B-4";
2
3// test() — returns true/false
4const hasEscaped = /STATUS: escaped/.test(log);
5console.log(hasEscaped); // true
6
7// match() — returns array of matches
8const dateMatch = log.match(/d{4}-d{2}-d{2}/);
9console.log(dateMatch[0]); // "2024-01-15"
10
11// matchAll() — returns all matches (with flag g)
12const allNumbers = [...log.matchAll(/d+/g)];
13console.log(allNumbers.map(m => m[0])); // ["2024", "01", "15", "10", "30", "45", "001", "4"]
14
15// replace() — replace matches
16const sanitized = log.replace(/RAPTOR-d+/g, "[REDACTED]");
17console.log(sanitized); // "... [REDACTED] STATUS: ..."
18
19// split() — split by pattern
20const parts = log.split(/[s,]+/);

Special Characters and Metacharacters

Character Classes

1// \d - any digit (0-9)
2const sectorLog = "Sector 7 - status OK";
3console.log(sectorLog.match(/\d/g)); // ["7"]
4
5// \w - word character (letter, digit, underscore)
6const code = "DINO_001_REX";
7console.log(code.match(/\w+/g)); // ["DINO_001_REX"]
8
9// \s - whitespace (space, tab, newline)
10const text = "Park\tJurassic\nStatus";
11console.log(text.split(/\s+/)); // ["Park", "Jurassic", "Status"]
12
13// . (dot) - any character (except newline)
14const pattern = /T.Rex/;
15console.log(pattern.test("T-Rex")); // true
16console.log(pattern.test("T Rex")); // true
17console.log(pattern.test("TXRex")); // true

Negated Character Classes

1// \D - everything except digits
2// \W - everything except word characters
3// \S - everything except whitespace
4
5const mixed = "Dino123!@#";
6console.log(mixed.match(/\D/g)); // ["D", "i", "n", "o", "!", "@", "#"]

Ranges and Character Sets

1// [abc] - one of the listed characters
2const vowels = /[aeiou]/gi;
3console.log("Tyrannosaurus".match(vowels)); // ["a", "o", "a", "u"]
4
5// [a-z] - character range
6const lowercase = /[a-z]+/g;
7console.log("T-Rex123".match(lowercase)); // ["ex"]
8
9// [^abc] - negation - everything except listed
10const notDigit = /[^0-9]+/g;
11console.log("Sector7A".match(notDigit)); // ["Sector", "A"]
12
13// Combining ranges
14const alphanumeric = /[a-zA-Z0-9]+/g;
15console.log("ID: DINO-001".match(alphanumeric)); // ["ID", "DINO", "001"]

Quantifiers — How Many Times?

1// * - zero or more
2const pattern1 = /ro*ar/;
3console.log(pattern1.test("rar"));    // true (0 times 'o')
4console.log(pattern1.test("roar"));   // true (1 time 'o')
5console.log(pattern1.test("roooar")); // true (many times 'o')
6
7// + - one or more
8const pattern2 = /ro+ar/;
9console.log(pattern2.test("rar"));    // false (need at least 1 'o')
10console.log(pattern2.test("roar"));   // true
11
12// ? - zero or one
13const pattern3 = /colou?r/;
14console.log(pattern3.test("color"));  // true (American)
15console.log(pattern3.test("colour")); // true (British)
16
17// {n} - exactly n times
18const idPattern = /DINO-\d{3}/;
19console.log(idPattern.test("DINO-001")); // true
20console.log(idPattern.test("DINO-01"));  // false
21
22// {n,m} - from n to m times
23const codePattern = /[A-Z]{2,4}-\d{3,5}/;
24console.log(codePattern.test("REX-001"));    // true
25console.log(codePattern.test("TREX-12345")); // true
26console.log(codePattern.test("A-1"));        // false

Anchors — Position in Text

1// ^ - start of text/line
2const startPattern = /^ALERT/;
3console.log(startPattern.test("ALERT: Dinosaur escaped")); // true
4console.log(startPattern.test("Status: ALERT"));           // false
5
6// $ - end of text/line
7const endPattern = /OK$/;
8console.log(endPattern.test("Status: OK")); // true
9console.log(endPattern.test("OK - done"));  // false
10
11// \b - word boundary
12const wordBoundary = /\bRex\b/;
13console.log(wordBoundary.test("T-Rex"));     // true
14console.log(wordBoundary.test("Rexona"));    // false (Rex is not a separate word)

Groups and Alternatives

1// () - capturing group
2const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
3const date = "2024-06-15";
4const match = date.match(datePattern);
5console.log(match[0]); // "2024-06-15" (full match)
6console.log(match[1]); // "2024" (first group)
7console.log(match[2]); // "06" (second group)
8console.log(match[3]); // "15" (third group)
9
10// | - alternative (or)
11const dinoPattern = /T-Rex|Velociraptor|Triceratops/;
12console.log(dinoPattern.test("T-Rex spotted"));      // true
13console.log(dinoPattern.test("Velociraptor alert")); // true
14console.log(dinoPattern.test("Brachiosaurus"));      // false
15
16// (?:) - non-capturing group
17const efficientPattern = /(?:Mr|Mrs|Dr)\.?\s+(\w+)/;
18const title = "Dr. Grant";
19const nameMatch = title.match(efficientPattern);
20console.log(nameMatch[1]); // "Grant" (only name, not title)

Flags

1// g - global (find all matches)
2console.log("Rex Rex Rex".match(/Rex/));  // ["Rex"] (only first)
3console.log("Rex Rex Rex".match(/Rex/g)); // ["Rex", "Rex", "Rex"]
4
5// i - ignore case
6console.log(/trex/i.test("T-REX"));  // true
7console.log(/trex/.test("T-REX"));   // false
8
9// m - multiline (^ and $ apply to each line)
10const multiline = `Sector 1: OK
11Sector 2: ALERT
12Sector 3: OK`;
13
14console.log(multiline.match(/^Sector/gm));
15// ["Sector", "Sector", "Sector"] (start of each line)
16
17// s - dotAll (. also matches newline)
18const withNewline = "Start\nEnd";
19console.log(/Start.End/.test(withNewline));  // false
20console.log(/Start.End/s.test(withNewline)); // true

Practical Examples in Jurassic Park

1// 1. Validate dinosaur IDs
2function validateDinoId(id) {
3  const pattern = /^[A-Z]{2,6}-d{3}$/;
4  return pattern.test(id);
5}
6
7console.log(validateDinoId("RAPTOR-001")); // true
8console.log(validateDinoId("TREX-15"));    // false (need 3 digits)
9console.log(validateDinoId("BRACHI-042")); // true
10
11// 2. Parse security log entries
12function parseSecurityLog(logEntry) {
13  const pattern = /(?<date>d{4}-d{2}-d{2}) (?<time>d{2}:d{2}:d{2}) [(?<dinoId>[A-Z]+-d+)] STATUS: (?<status>w+)/;
14  const match = logEntry.match(pattern);
15
16  if (!match) return null;
17
18  const { date, time, dinoId, status } = match.groups;
19  return { date, time, dinoId, status };
20}
21
22const log = "2024-01-15 10:30:45 [RAPTOR-001] STATUS: escaped";
23const parsed = parseSecurityLog(log);
24console.log(parsed);
25// { date: "2024-01-15", time: "10:30:45", dinoId: "RAPTOR-001", status: "escaped" }
26
27// 3. Validate email
28function validateEmail(email) {
29  const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/;
30  return pattern.test(email);
31}
32
33// 4. Extract GPS coordinates
34function extractCoordinates(text) {
35  const pattern = /LAT: (?<lat>-?d+.d+), LON: (?<lon>-?d+.d+)/g;
36  const matches = [...text.matchAll(pattern)];
37
38  return matches.map(m => ({
39    lat: parseFloat(m.groups.lat),
40    lon: parseFloat(m.groups.lon)
41  }));
42}
43
44// 5. Sanitize input
45function sanitizeInput(input) {
46  // Remove potentially dangerous characters
47  return input
48    .replace(/<script[^>]*>.*?</script>/gi, '')
49    .replace(/<[^>]*>/g, '')
50    .trim();
51}

Performance and Best Practices

1// ✅ Compile pattern once, use many times
2const dinoIdPattern = /^[A-Z]{3}-\d{3}$/;
3
4function validateManyIds(ids) {
5  return ids.filter(id => dinoIdPattern.test(id));
6}
7
8// ❌ Don't create patterns in loops
9function badValidation(ids) {
10  return ids.filter(id => /^[A-Z]{3}-\d{3}$/.test(id)); // New RegExp on each iteration!
11}
12
13// ✅ Use non-capturing groups when you don't need groups
14const efficient = /(?:Mr|Mrs|Dr)\.\s+\w+/;  // (?:...) doesn't create a capturing group
15
16// ✅ Avoid excessive backtracking
17// ❌ Bad: /.*foo/ (can be very slow)
18// ✅ Good: /[^f]*foo/ or use lazy quantifier /.*?foo/

Summary

Regular expressions are a powerful but complex tool. Their main advantages in a Jurassic Park context:

  1. Pattern matching — find text that matches complex patterns (e.g.
    /RAPTOR-d{3}/
    )
  2. Validation — check if input matches the expected format (
    /^[A-Z]{2,6}-d{3}$/
    )
  3. Extraction — pull specific parts from text (
    match
    ,
    matchAll
    with groups)
  4. Transformation — replace patterns with other text (
    replace
    )
  5. Splitting — split text by complex delimiters (
    split
    )

Key tips: use

test()
for simple checks,
match()
/
matchAll()
for extraction,
replace()
for transformations, and always test your patterns on real data before deploying them to production!

Go to CodeWorlds