DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
What's in store for DevOps in 2023? Hear from the experts in our "DZone 2023 Preview: DevOps Edition" on Fri, Jan 27!
Save your seat
  1. DZone
  2. Software Design and Architecture
  3. Microservices
  4. Binary Pattern Matching in Elixir

Binary Pattern Matching in Elixir

A dev tells how, when using TCP streams to create an old-timey feeling game, he ran into some issues that Elixir helped him to solve.

Eric Oestrich user avatar by
Eric Oestrich
·
Mar. 04, 19 · Tutorial
Like (2)
Save
Tweet
Share
8.84K Views

Join the DZone community and get the full member experience.

Join For Free

Binary Pattern Matching

I've been working on a web client for my side project Grapevine, and part of that includes parsing a telnet stream. Before you ask, "A telnet stream!?", the web client connects to text-based games called MUDs that primarily used telnet as that's how they started in the late 1980s.

Telnet is mostly a TCP stream that contains only text that should be output to the screen. Hidden inside the otherwise plain TCP stream is a series of bytes called IAC (Interpret as Command). This is the byte 255 followed by at least one other byte that describes what the command is.

An example stream might be:

"Welcome! What is your name? " <> <<255, 249>> 

This is the command to Go Ahead (GA), signaling to the remote client that the server is done sending and should display the text it sent. In order to act on this, the Grapevine web client needs to be able to parse this binary stream to find the commands.

Luckily, Elixir has a wonderful thing called binary pattern matching that saves the day.

Pattern Matching on Binaries

In order to find these telnet commands, I have a function that takes the full binary as it pops off bytes at a time until it finds a known byte series such as the go ahead.

def options(binary, current \\ <<>>, processed \\ [])

def options(<<>>, current, processed) do  
  processed ++ [current]
end

def options(<<@iac, @ga, data::binary>>, current, processed) do  
  options(data, <<>>, processed ++ [current, <<@iac, @ga>>])
end

def options(<<byte::size(8), data::binary>>, current, processed) do  
  options(data, current <> <<byte>>, processed)
end  

With this, you can now call options/3 with the above binary and get ["Welcome! What is your name? ", <<255, 249>>]

This works by expecting the last option function definition to be the main call; it takes the top byte of the binary, ::size(8), and adds it to the current working binary. It then calls itself again with the rest of the binary, minus the first byte.

If a known byte sequence is encountered at the beginning of the binary, that function definition is called instead. The current working binary and the known pattern is added to the processed data.

The function continues to recurse by calling itself with the unprocessed binary and continues until it runs out of binary data. The top function then matches and the processed data is returned with the final current working binary.

Transforming Binary Into Actionable Data

With this list of broken up binary data, I then loop over the list transforming it into something useful for the application.

def transform(<<@iac, @ga>>), do: {:ga}

def transform(string), do: {:string, string}  

This results in the following list, continuing with the example: [{:string, "Welcome! What is your name? "}, {:ga}]. The application can then easily act on each of these pieces of data, processing as needed.

Conclusion

Binary pattern matching is incredibly powerful and I suggest seeing what else is available in the Elixir Special Forms documentation.

The full code for the example above is also available on GitHub, both the options function and the transform function. The real examples are much more complicated as some telnet options don't have a determined length, and the real options function parses those out — with more pattern matching!

Elixir (programming language)

Published at DZone with permission of Eric Oestrich, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How Observability Is Redefining Developer Roles
  • Handling Virtual Threads
  • Explainer: Building High Performing Data Product Platform
  • Comparing Flutter vs. React Native

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: