IRC parsing, tokenization, and state handling in C#
at main 63 lines 1.9 kB view raw
1using System.Globalization; 2using System.Text; 3 4namespace IRCTokens; 5 6public static class TagEscape 7{ 8 private static readonly string[] TagUnescaped = ["\\", " ", ";", "\r", "\n"]; 9 private static readonly string[] TagEscaped = [@"\\", "\\s", "\\:", "\\r", "\\n"]; 10 11 /// <summary>Unescape ircv3 tag</summary> 12 /// <param name="val">escaped string</param> 13 /// <returns>unescaped string</returns> 14 public static string Unescape(string val) 15 { 16 StringBuilder unescaped = new(); 17 18 var graphemeIterator = StringInfo.GetTextElementEnumerator(val); 19 graphemeIterator.Reset(); 20 21 while (graphemeIterator.MoveNext()) 22 { 23 var current = graphemeIterator.GetTextElement(); 24 25 if (current == @"\") 26 { 27 try 28 { 29 graphemeIterator.MoveNext(); 30 var next = graphemeIterator.GetTextElement(); 31 var pair = current + next; 32 unescaped.Append(TagEscaped.Contains(pair) 33 ? TagUnescaped[Array.IndexOf(TagEscaped, pair)] 34 : next); 35 } 36 catch (InvalidOperationException) 37 { 38 // ignored 39 } 40 } 41 else 42 { 43 unescaped.Append(current); 44 } 45 } 46 47 return unescaped.ToString(); 48 } 49 50 /// <summary>Escape strings for use in ircv3 tags</summary> 51 /// <param name="val">string to escape</param> 52 /// <returns>escaped string</returns> 53 public static string Escape(string val) 54 { 55 StringBuilder sb = new(val); 56 for (var i = 0; i < TagUnescaped.Length; ++i) 57 { 58 sb.Replace(TagUnescaped[i], TagEscaped[i]); 59 } 60 61 return sb.ToString(); 62 } 63}