Skip to content

Instantly share code, notes, and snippets.

@quackbarc
Last active September 4, 2024 19:14
Show Gist options
  • Save quackbarc/a24d5f7473cee2e44a4fef83288d0f45 to your computer and use it in GitHub Desktop.
Save quackbarc/a24d5f7473cee2e44a4fef83288d0f45 to your computer and use it in GitHub Desktop.
a fizzbuzz pattern made with pure regex
\b(?:(?<fizzbuzz>(?:(?:[369]|[258][0369]*[147]|(?:[147]|[258][0369]*[258])(?:[0369]|[147][0369]*[258])*(?:[28]|[147][0369]*[147]))*(?:0|(?:[147]|[258][0369]*[258])(?:[0369]|[147][0369]*[258])*5))+)|(?<buzz>\d*[05])|(?<fizz>(?:[0369]|[258][0369]*[147]|(?:[147]|[258][0369]*[258])(?:[0369]|[147][0369]*[258])*(?:[258]|[147][0369]*[147]))+))\b

insanity, as i'd like to call it. although it isn't fizzbuzz per se, it's the best you can get with regex. here's a regexr link to it with sample text.

this matches a number (within word boundaries) if it falls under any of the three groups:

  • fizzbuzz, which picks up numbers divisible by both 3 and 5, i.e. 15;
  • buzz, which picks up numbers divisible by 5; and
  • fizz, which picks up numbers divisible by 3.

the pattern for buzz is simply \d*[05], where it checks if a number ends with a 0 or a 5, like how one would normally check divisibility by 5. fizz's pattern however is more complex as it checks the total sum of the digits, modulo 3. fizzbuzz is similar to fizz, except it also checks divisibility by 5 -- more specifically, it checks for (<fizz>)*(0|<A>5), where A is a pattern that sums up to a remainder of 1.

the patterns for fizz and fizzbuzz were generated from hand-drawn DFA machines and compiled to regex via state removal. their formal definitions being:

Mfizz = (Q, Σ, δ, q0, F), where:

  • Q = {S0, S1, S2} (each representing a remainder of the accumulating sum)
  • Σ = {0, 1, 2, ..., 9}
  • q0 = S0
  • F = S0 and
  • δ as the following table:
0, 3, 6, 9 1, 4, 7 2, 5, 8
S0 S0 S1 S2
S1 S1 S2 S0
S2 S2 S0 S1

Mfizzbuzz = (Q, Σ, δ, q0, F), where:

  • Q = {S0, S1, S2, S3} (same thing but with an extra state S3 for 0 remainders that don't end in 0 or 5)
  • Σ = {0, 1, 2, ..., 9}
  • q0 = F = S0
  • F = S0 and
  • δ as the following table:
0 1, 4, 7 2, 8 3, 6, 9 5
S0 S0 S1 S2 S3 S2
S1 S1 S2 S3 S1 S0
S2 S2 S3 S1 S2 S1
S3 S0 S1 S2 S3 S2

or, if you prefer eye candy, here's some graph versions from my notes:

image image

nameless version:

\b(?:((?:(?:[369]|[258][0369]*[147]|(?:[147]|[258][0369]*[258])(?:[0369]|[147][0369]*[258])*(?:[28]|[147][0369]*[147]))*(?:0|(?:[147]|[258][0369]*[258])(?:[0369]|[147][0369]*[258])*5))+)|(\d*[05])|((?:[0369]|[258][0369]*[147]|(?:[147]|[258][0369]*[258])(?:[0369]|[147][0369]*[258])*(?:[258]|[147][0369]*[147]))+))\b

expanded version:

styled under python highlighting because it looks nice.

import re
pattern = re.compile(r"""
\b
(?:
  (?P<fizzbuzz>
    (?:
      (?:
        [369]
        |
        [258][0369]*[147]
        |
        (?:[147]|[258][0369]*[258])
        (?:[0369]|[147][0369]*[258])*
        (?:[28]|[147][0369]*[147])
      )*
      (?:
        0
        |
        (?:[147]|[258][0369]*[258])
        (?:[0369]|[147][0369]*[258])*
        5
      )
    )+
  )
  |
  (?<buzz>
    \d*[05]
  )
  |
  (?<fizz>
    (?:
      [0369]
      |
      [258][0369]*[147]
      | 
      (?:[147]|[258][0369]*[258])
      (?:[0369]|[147][0369]*[258])*
      (?:[258]|[147][0369]*[147])
    )+
  )
)
\b
""", re.VERBOSE)

...why?

i just thought it would be funny

references

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment