How do pattern matching and regex work in switch?

← Control Flow · Ref: Q71

EK9 switch cases support pattern matching with the 'matches' and 'contains' operators. These work with String values.

REGEX MATCHING

Use 'case matches' with a regex literal:

  switch userInput
    case matches /^[A-Z]{2}[0-9]{4}$/
      category: "product code"
    case matches /^[0-9]+$/
      category: "numeric"
    default
      category: "text"

The regex literal uses /pattern/ syntax. The switch value is tested against the pattern.

SUBSTRING MATCHING

Use 'case contains' to check for substrings:

  switch logLine
    case contains "ERROR"
      severity: "high"
    case contains "WARN"
      severity: "medium"
    default
      severity: "low"

MIXING PATTERN TYPES

You can mix regex, contains, comparison operators, and literal values in the same switch:

  switch conditionVariable
    case 'D'
      label: "exact match"
    case matches /[nN]ame/
      label: "regex match"
    case > "Gandalf"
      label: "comparison match"
    default
      label: "default"

This is a powerful combination unique to EK9.

EXPRESSION FORM

Pattern matching works in switch expressions too:

  result <- switch text
    <- rtn as String?
    case matches /pattern/
      rtn: "matched"
    default
      rtn: "no match"

ORDER MATTERS

As with all switch cases, order matters. Place more specific patterns before general ones to avoid shadowing.

See Q33 for regex type details. See Q37 for String type details. See Q63 for basic switch. See Q70 for comparison operators in cases.

Example

defines module qa.flow.switch.pattern

  defines program

    SwitchPatternDemo()
      stdout <- Stdout()

      // === REGEX MATCHING ===

      inputs <- ["AB1234", "hello", "42", "XY9999"]
      for userInput in inputs
        category <- switch userInput
          <- rtn as String?
          case matches /^[A-Z]{2}[0-9]{4}$/
            rtn: "product code"
          case matches /^[0-9]+$/
            rtn: "numeric"
          default
            rtn: "text"
        stdout.println(`"${userInput}" -> ${category}`)

      // === CONTAINS MATCHING ===

      logLines <- ["2024 ERROR disk full", "2024 WARN low memory", "2024 INFO started"]
      for logLine in logLines
        severity <- switch logLine
          <- rtn as String?
          case contains "ERROR"
            rtn: "HIGH"
          case contains "WARN"
            rtn: "MEDIUM"
          default
            rtn: "LOW"
        stdout.println(`${severity}: ${logLine}`)

      // === MIXED PATTERNS ===

      names <- ["Dave", "Name", "Zara", "Alice"]
      for nameEntry in names
        assessment <- switch nameEntry
          <- rtn as String?
          case matches /[nN]ame/
            rtn: "contains 'name'"
          case > "M"
            rtn: "second half of alphabet"
          case < "D"
            rtn: "early alphabet"
          default
            rtn: "mid alphabet"
        stdout.println(`${nameEntry} -> ${assessment}`)

Common mistakes

E01070 — EK9 has no break statement. Switch cases with pattern matching are self-contained like all other cases. No fallthrough exists in the language. See ek9 -h E01070 for details.

Incorrect:

case matches /^[A-Z]{2}[0-9]{4}$/
            rtn: "product code"
            break

Correct:

case matches /^[A-Z]{2}[0-9]{4}$/
            rtn: "product code"

E01072 — EK9 has no return statement. Switch expressions use a declared return variable that is assigned in each case branch. See ek9 -h E01072 for details.

Incorrect:

case contains "ERROR"
            return "HIGH"

Correct:

case contains "ERROR"
            rtn: "HIGH"
          case contains "WARN"
            rtn: "MEDIUM"
Other ways to ask this
  • Can I use regex in a switch case in EK9?
  • How do I match patterns in a switch statement?
  • How does case matches work in EK9?

Coming from another language?

Rust: match with pattern matching and destructuring, no inline regex, separate regex crate. Python: match/case since 3.10 with structural patterns, no regex in case clauses. Kotlin: when with arbitrary expressions, regex via matches() in guards. Java: no pattern matching in switch cases (instanceof patterns only since Java 21). Go: no pattern matching in switch. C/C++: no pattern matching in switch. JavaScript: no pattern matching in switch. Swift: pattern matching with case let and where clauses, no inline regex. Ruby: case/when with regex via === operator. EK9: case matches /regex/ and case contains "text" directly in case clauses, mixed with comparison operators and literals.

Keywords: pattern, contains, case, condition, matches, switch, flow, regular, regex, string, control, substring, branch