diff --git a/QuickFIXn/Message/Message.cs b/QuickFIXn/Message/Message.cs index e6435db8e..6a373eaef 100644 --- a/QuickFIXn/Message/Message.cs +++ b/QuickFIXn/Message/Message.cs @@ -1,7 +1,6 @@ using System; using System.Text; using QuickFix.Fields; -using System.Text.RegularExpressions; using System.Text.Json; using System.Collections.Generic; using QuickFix.DataDictionary; @@ -256,11 +255,31 @@ public static SessionID GetReverseSessionId(string msg) /// if 35 tag is missing or malformed public static string GetMsgType(string fixstring) { - Match match = Regex.Match(fixstring, SOH + "35=([^" + SOH + "]*)" + SOH); - if (match.Success) - return match.Groups[1].Value; + // Note: This is faster than regex. See stats from https://github.com/connamara/quickfixn/pull/910 + ReadOnlySpan chars = fixstring.AsSpan(); + int l = 0; + int r = 1; - throw new MessageParseError("missing or malformed tag 35 in msg: " + fixstring); + if (chars.Length > 0 && chars[0] == SOH) l = 1; + while (r < chars.Length) + { + if (chars[r] == SOH) + { + if (r - l >= 4 && + chars[l] == '3' && + chars[l + 1] == '5' && + chars[l + 2] == '=') + { + return new string(chars[(l + 3)..r]); + } + + l = r + 1; + } + + r++; + } + + throw new MessageParseError("Missing or malformed tag 35 in msg: " + fixstring); } public static ApplVerID GetApplVerID(string beginString) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 05ddc4eb3..d2f4b9eaf 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -46,6 +46,7 @@ What's New * #891 - make NonSessionLog implement IDisposable and fix the IOException (VAllens) * #893 - Upgrade the unit testing framework to the latest version and remove obsolete Assert methods (VAllens) * #907 - A fix to make body-less messages work, specifically 35=n aka XMLnonFIX (gbirchmeier) +* #910 - faster Message.GetMsgType that doesn't use Regex (jkulubya) ### v1.12.0 diff --git a/UnitTests/MessageTests.cs b/UnitTests/MessageTests.cs index b2eefc15b..b9b20029a 100644 --- a/UnitTests/MessageTests.cs +++ b/UnitTests/MessageTests.cs @@ -580,16 +580,23 @@ public void TestGetSetSessionId() Assert.That(getSessionId.TargetLocationID, Is.EqualTo("")); } - [Test] - public void GetMsgTypeTest() { - string msgStr = ("8=FIX.4.4|9=104|35=W|34=3|49=sender|52=20110909-09:09:09.999|56=target" - + "55=sym|268=1|269=0|272=20111012|273=22:15:30.444|10=19|").Replace('|', Message.SOH); - Assert.That(Message.GetMsgType(msgStr), Is.EqualTo("W")); - - // invalid 35 value, let it ride - string msgStr2 = ("8=FIX.4.4|9=68|35=*|34=3|49=sender|52=20110909-09:09:09.999|56=target" - + "55=sym|268=0|10=9|").Replace('|', Message.SOH); - Assert.That(Message.GetMsgType(msgStr2), Is.EqualTo("*")); + [TestCase("8=FIX.4.4|9=104|35=W|34=3|49=sender|52=20110909-09:09:09.999|56=target|55=sym|268=1|269=0|272=20111012|273=22:15:30.444|10=19|", "W")] + [TestCase("8=FIX.4.4|9=104|35=AW|34=3|49=sender|52=20110909-09:09:09.999|56=target|55=sym|268=1|269=0|272=20111012|273=22:15:30.444|10=19|", "AW")] + [TestCase("8=FIX.4.4|9=68|35=*|34=3|49=sender|52=20110909-09:09:09.999|56=target|55=sym|268=0|10=9|", "*")] + public void GetMsgTypeTest(string message, string expectedMessageType) + { + var msgStr = message.Replace('|', Message.SOH); + Assert.That(Message.GetMsgType(msgStr), Is.EqualTo(expectedMessageType)); + } + + [TestCase("")] + [TestCase("8=FIX.4.4|9=68|34=3|49=sender|52=20110909-09:09:09.999|56=target|55=sym|268=0|10=9|")] + [TestCase("8=FIX.4.4|9=68|35=|34=3|49=sender|52=20110909-09:09:09.999|56=target|55=sym|268=0|10=9|")] + [TestCase("8=FIX.4.4|9=68|35=")] + public void GetInvalidMsgTypeTest(string message) + { + var msgStr = message.Replace('|', Message.SOH); + Assert.Throws(() => Message.GetMsgType(msgStr)); } [Test]