Every line has a prefix character before the vertical bar |, and text after. The P prefix means that the text after the pipe consists of patterns.

The text within the metacharacters { and } are JSON Pattern expressions, which generally do named capture. The things outside are regular expressions that must be matched. They're processed by the underlying regex engine.

With the P prefix, the whitespace between {} expressions and text is stripped.

Here we capture the hour and minute from a time string:

Pattern time1 AST
  P|   Time:[ ] { \d+ hour } : { \d+ minute }
MatchRegex 'Time:[ ]'
MatchValue    (name: hour, scalar)
    MatchRegex '\\d+'
MatchLiteral ':'
MatchValue    (name: minute, scalar)
    MatchRegex '\\d+'
Input String Captured JSON
Time: 3:45
{
  "minute": "45", 
  "hour": "3"
}

Suppose we want the integer 45 instead of the string "45". You can apply filters inside JSON Pattern expressions to do this conversion.

Pattern time2 AST
  P|   Time:[ ] { \d+ hour | int } : { \d+ minute | int }
MatchRegex 'Time:[ ]'
MatchValue    (name: hour, filter: int, scalar)
    MatchRegex '\\d+'
MatchLiteral ':'
MatchValue    (name: minute, filter: int, scalar)
    MatchRegex '\\d+'
Input String Captured JSON
Time: 3:45
{
  "minute": 45, 
  "hour": 3
}

We're reusing the same pattern twice, so let's define this subpattern. If we omit the name, then the capture is anonymous.

Pattern int AST
  P|   { \d+ | int }
MatchValue    (anonymous, filter: int, scalar)
    MatchRegex '\\d+'
Input String Captured JSON
45
45

This is how we refer to subpatterns. We can build up complex patterns using this mechanism.

Pattern time AST
  P|   {:int hour} : {:int minute}
MatchSubpattern int
MatchLiteral ':'
MatchSubpattern int
Input String Captured JSON
3:45
{
  "minute": 45, 
  "hour": 3
}

The real power of JSON Pattern is that we can build up hierarchical structures. Here we match a bus schedule with two columns of numbers.

Lines with no prefix have JSON Pattern keywords on them. The repeated keyword starts a block that repeats until its body cannot be matched. On each iteration, the captured JSON is appended to an array.

The S prefix is like P, but indicates that whitespace is significant, which makes certain patterns more readable. (This doesn't apply the beginning and end of the line, so you can use indentation to structure your programs).

Pattern train AST
  
    #     Skip the heading lines
    P|    .*\n
    P|    .*\n
  
    #     The structured data
     |    repeated routes
   SP|        \s*{:time depart}  {:time arrive} { \w+ name }\n
     |    end
  
MatchRegex '.*\\n'
MatchRegex '.*\\n'
MatchRepeated    (name: routes)
    MatchRegex '\\s*'
    MatchSubpattern time
    MatchLiteral '  '
    MatchSubpattern time
    MatchLiteral ' '
    MatchValue    (name: name, scalar)
        MatchRegex '\\w+'
    MatchRegex '\\n'
Input String Captured JSON
Depart Arrive Name
------ ------ -----
 10:02  10:13 Dinky
 10:14  10:25 Binky
 11:02  11:13 Dinky
 11:14  11:25 Binky
{
  "routes": [
    {
      "arrive": {
        "minute": 13, 
        "hour": 10
      }, 
      "depart": {
        "minute": 2, 
        "hour": 10
      }, 
      "name": "Dinky"
    }, 
    {
      "arrive": {
        "minute": 25, 
        "hour": 10
      }, 
      "depart": {
        "minute": 14, 
        "hour": 10
      }, 
      "name": "Binky"
    }, 
    {
      "arrive": {
        "minute": 13, 
        "hour": 11
      }, 
      "depart": {
        "minute": 2, 
        "hour": 11
      }, 
      "name": "Dinky"
    }, 
    {
      "arrive": {
        "minute": 25, 
        "hour": 11
      }, 
      "depart": {
        "minute": 14, 
        "hour": 11
      }, 
      "name": "Binky"
    }
  ]
}

This HTML fragment was automatically generated from the test cases for JSON Pattern.