From 054389b3d0eccd6767c8de2c6c848dd7798ab6d2 Mon Sep 17 00:00:00 2001 From: database64128 Date: Thu, 9 Dec 2021 21:53:56 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Efficient=20command=20parsing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ReadOnlySpan for zero-copy string slicing. --- CubicBot.Telegram/Utils/ChatHelper.cs | 60 +++++++++++++++++---------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/CubicBot.Telegram/Utils/ChatHelper.cs b/CubicBot.Telegram/Utils/ChatHelper.cs index 9b2f5e0..7a8b381 100644 --- a/CubicBot.Telegram/Utils/ChatHelper.cs +++ b/CubicBot.Telegram/Utils/ChatHelper.cs @@ -318,52 +318,70 @@ public static string EscapeMarkdownV2CodeBlock(string code) /// Command is null if the text message is not a command to the bot. /// Argument can be null. /// - public static (string? command, string? argument) ParseMessageIntoCommandAndArgument(string? text, string botUsername) + public static (string? command, string? argument) ParseMessageIntoCommandAndArgument(ReadOnlySpan text, string botUsername) { // Empty message - if (string.IsNullOrWhiteSpace(text)) + if (text.IsEmpty) return (null, null); // Not a command - if (!text.StartsWith('/') || text.Length < 2) + if (text[0] != '/' || text.Length < 2) return (null, null); // Remove the leading '/' text = text[1..]; // Split command and argument - var parsedText = text.Split(' ', 2); - string command; - string? argument = null; - switch (parsedText.Length) + ReadOnlySpan command, argument; + var spacePos = text.IndexOf(' '); + if (spacePos == -1) { - case <= 0: - return (null, null); - case 2: - argument = parsedText[1]; - goto default; - default: - command = parsedText[0]; - break; + command = text; + argument = ReadOnlySpan.Empty; + } + else if (spacePos == text.Length - 1) + { + command = text[..spacePos]; + argument = ReadOnlySpan.Empty; + } + else + { + command = text[..spacePos]; + argument = text[(spacePos + 1)..]; } // Verify and remove trailing '@bot' from command var atSignIndex = command.IndexOf('@'); if (atSignIndex != -1) { - var atUsername = command[atSignIndex..]; - if (atUsername != $"@{botUsername}") - return (null, null); + if (atSignIndex != command.Length - 1) + { + var atUsername = command[(atSignIndex + 1)..]; + if (!atUsername.SequenceEqual(botUsername)) + { + return (null, null); + } + } command = command[..atSignIndex]; } // Trim leading and trailing spaces from argument - if (argument is not null) + argument = argument.Trim(); + + // Convert back to string + string? commandString = null; + string? argumentString = null; + if (!command.IsEmpty) { - argument = argument.Trim(); + commandString = command.ToString(); + + if (!argument.IsEmpty) + { + argumentString = argument.ToString(); + } } - return (command, argument); + return (commandString, argumentString); } }