This is my lame attempt to convert the BNF-style grammar from RFC 1459 into useable ruby regexes. The hope here is that one can effectively match an incoming message with high accuracy. Usage:

line = ':Nerdmaster! PRIVMSG Nerdminion :Do my bidding!!'
message =
# hash now has all kinds of useful pieces of the incoming message:
puts line.nick        # "Nerdmaster"
puts line.user        # "jeremy"
puts        # ""
puts line.prefix      # "Nerdmaster!"
puts line.command     # "PRIVMSG"
puts line.params      # ["Nerdminion", "Do my bidding!!"]
USER = /\S+?/

Note that all regexes are non-greedy. I’m scared of greedy regexes, sirs.

NICK = /[\w\d\\|`'^{}\]\[-]+?/

RFC suggested that a nick had to start with a letter, but that seems to not be the case.

HOST = /\S+?/
PREFIX = /((#{NICK})!(#{USER})@(#{HOST})|#{SERVERNAME})/

This is automatically grouped for ease of use in the parsing. Group 1 is the full prefix; 2, 3, and 4 are nick/user/host; 1 is also servername if there was no match to populate 2, 3, and 4.

COMMAND = /(\w+|\d{3})/
TRAILING = /\:\S*?/
MIDDLE = /(?: +([^ :]\S*))/
MESSAGE = /^(?::#{PREFIX} +)?#{COMMAND}(.*)$/
[R] command
[R] host
[R] nick
[R] params
[R] prefix
[R] servername
[R] user
Class Public methods
# File lib/net/yail/message_parser.rb, line 41
def initialize(line)
  @params = []

  if line =~ MESSAGE
    matches = Regexp.last_match

    @prefix = matches[1]
    if (matches[2])
      @nick = matches[2]
      @user = matches[3]
      @host = matches[4]
      @servername = matches[1]

    @command = matches[5]

    # Args are a bit tricky.  First off, we know there must be a single
    # space before the arglist, so we need to strip that.  Then we have to
    # separate the trailing arg as it can contain nearly any character. And
    # finally, we split the "middle" args on space.
    arglist = matches[6].sub(%r^ +/, '')
    arglist.sub!(%r^:/, ' :')
    (middle_args, trailing_arg) = arglist.split(%r +:/, 2)
    @params.push(middle_args.split(%r +/), trailing_arg)