Skip to content

Instantly share code, notes, and snippets.

@jcotton42
Created January 6, 2018 23:25
Show Gist options
  • Save jcotton42/5f0f6e832265d48b74bf11097be71175 to your computer and use it in GitHub Desktop.
Save jcotton42/5f0f6e832265d48b74bf11097be71175 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ReactiveIRC {
public struct IRCMessage {
private const int MaxParams = 15;
private static readonly Regex MessageRegex =
new Regex(@"(@(?<tags>[^ ]*) +)?(:(?<prefix>[^ ]*) +)?(?<command>[^ ]+)( +(?<params>.*))?");
public ImmutableDictionary<string, string> Tags { get; }
public string Source { get; }
public string Command { get; }
public ImmutableArray<string> Parameters { get; }
public IRCMessage(ImmutableDictionary<string, string> tags, string source, string command,
ImmutableArray<string> parameters) {
Tags = tags ?? throw new ArgumentNullException(nameof(tags));
Source = source ?? throw new ArgumentNullException(nameof(source));
Command = command ?? throw new ArgumentNullException(nameof(command));
Parameters = parameters;
}
public static IRCMessage Parse(string message) {
if(message is null) {
throw new ArgumentNullException(nameof(message));
}
var matches = MessageRegex.Match(message);
if(!matches.Success) {
throw new FormatException(nameof(message) + " is not a valid IRC message.");
}
return new IRCMessage(
ParseTags(matches.Groups["tags"].Value),
matches.Groups["prefix"].Value,
matches.Groups["command"].Value,
ParseParams(matches.Groups["params"].Value)
);
ImmutableDictionary<string, string> ParseTags(string tags) {
if(string.IsNullOrWhiteSpace(tags)) {
return ImmutableDictionary<string, string>.Empty;
}
return tags.Split(';').Select(ExtractKeyValuePair)
.ToImmutableDictionary(kvp => kvp.key, kvp => UnescapeValue(kvp.value));
(string key, string value) ExtractKeyValuePair(string tag) {
var parts = tag.Split(new[] { '=' }, 2);
return (parts[0], parts.Length > 1 ? parts[1] : "");
}
string UnescapeValue(string value) {
var sb = new StringBuilder();
for(var i = 0; i < value.Length; i++) {
if(value[i] == '\\') {
i++;
if(i >= value.Length) {
break;
}
switch(value[i]) {
case ':':
sb.Append(';');
break;
case 's':
sb.Append(' ');
break;
case '\\':
sb.Append('\\');
break;
case 'r':
sb.Append('\r');
break;
case 'n':
sb.Append('\n');
break;
default:
sb.Append("\\" + value[i]);
break;
}
} else {
sb.Append(value[i]);
}
}
return sb.ToString();
}
}
ImmutableArray<string> ParseParams(string parameters) {
// max params: 15
// TODO: there is definitely a more efficient way to do this
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment