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]