An IRC parser in LPEG, with a pure-Lua fallback. Supports IRCv3 message tags.
local parser = require('irc-parser').new()
local line = '@message-id=12345;some-content=hello\\sthere;empty-str=;empty :nick!user@example.com PRIVMSG #a-room ::-) Hi there!'
local parsed, pos = parser(line)
--[[
parsed is a table:
{
tags = {
empty = false,
["empty-str"] = false,
["message-id"] = "12345",
["some-content"] = "hello there"
},
source = {
host = "example.com",
nick = "nick",
user = "user"
},
command = "PRIVMSG",
params = { "#a-room", ":-) Hi there!" },
}
pos is the length of the string + 1, so in this case 115
]]
Available on luarocks:
luarocks install irc-parser
Available on OPM
opm install jprjr/irc-parser
By default, you can require('irc-parser')
, and it will automatically
choose an appropriate backend.
It will first try to load the LPEG-based backend, and fall back to the pure-Lua backend if LPEG is not available.
You can force a specific backend by requiring it: require('irc-parser.fallback')
for the Lua fallback, and require('irc-parser.lpeg')
for the LPEG version.
You can then instantiate a parser with .new([mode],[opts])
(or just call the returned
module directly like parser = require('irc-parser')([mode],[opts])
.
The mode
argument is optional. If not specified, the parser will be in
LOOSE
mode.
There's three different modes available:
LOOSE
- aims to be broadly-compatible.STRICT
- follows the IRC RFCs as closely as possible.TWITCH
- essentiallySTRICT
with a few modifications for Twitch's IRC interface.
The default LOOSE
mode should work on most IRC servers, including Twitch. In
my testing, it's also the fastest (since it performs less validations than
any other mode).
You can specify which mode you'd like in a few ways:
-- these are all equivalent:
-- use a string name
local strict_parser = require('irc-parser')('strict')
local strict_parser = require('irc-parser')('STRICT')
-- use an enum
local mod = require('irc-parser')
local strict_parser = mod.new(mod.STRICT)
The opts
argument is a table of options to fine-tune handling of empty and
missing tag values. By default, empty and missing tags are converted to
the boolean false
.
If you'd prefer a different value for either empty or missing tags (example, say you want empty tags to remain empty strings), you can:
local parser = require('irc-parser')('loose', {
empty_tag_replacement = '',
})
And now empty tags will be returned as empty strings, missing tags
will remain as false
.
You can also specify that you'd like empty and missing strings to be removed entirely:
local parser = require('irc-parser')('loose', {
remove_empty_tags = true,
remove_missing_tags = true,
})
The parser exposes a single method, parser:parse(str, [pos])
. The parser itself
can also be called as a function, parser(str, [pos])
.
It accepts a string argument, the string argument can be terminated with a newline character, or a carriage return and newline, or nothing. It also accepts an optional position argument, this should be a number indicating where to start parsing.
If successful, it will return a parsed table, and the position for the next parse (essentially the length of the line + 1). This position argument is so you can have a string with multiple lines.
If not successful, it returns nil
.
Here's an example of looping through a block of data using the position argument and return value.
The returned table will have the following keys:
tags
- a table of tag values, ornil
if no tags were attached to the message.source
- a table representing the message source with the keyshost
,nick
, and/oruser
.source
will benil
if there was no source on the message.command
- an IRC command (ie,PRIVMSG
,001
, etc).params
- an array-like table of parameters, ornil
if there were no parameters.
local parser = require('irc-parser').new()
-- we'll say that "raw.txt" is a raw IRC log file with multiple lines
local rawfile = io.open('raw.txt','rb')
local rawdata = rawfile:read('*a')
rawfile:close()
local parsed
local pos = 1
while pos < #rawdata do
parsed, pos = parser:parse(rawdata,pos)
if not parsed then
break
end
-- do something with parsed
print(parsed.command)
end
MIT (see file LICENSE
).