Skip to content

Commit 054389b

Browse files
committed
⚡ Efficient command parsing
Use ReadOnlySpan<char> for zero-copy string slicing.
1 parent 3041f99 commit 054389b

File tree

1 file changed

+39
-21
lines changed

1 file changed

+39
-21
lines changed

CubicBot.Telegram/Utils/ChatHelper.cs

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -318,52 +318,70 @@ public static string EscapeMarkdownV2CodeBlock(string code)
318318
/// Command is null if the text message is not a command to the bot.
319319
/// Argument can be null.
320320
/// </returns>
321-
public static (string? command, string? argument) ParseMessageIntoCommandAndArgument(string? text, string botUsername)
321+
public static (string? command, string? argument) ParseMessageIntoCommandAndArgument(ReadOnlySpan<char> text, string botUsername)
322322
{
323323
// Empty message
324-
if (string.IsNullOrWhiteSpace(text))
324+
if (text.IsEmpty)
325325
return (null, null);
326326

327327
// Not a command
328-
if (!text.StartsWith('/') || text.Length < 2)
328+
if (text[0] != '/' || text.Length < 2)
329329
return (null, null);
330330

331331
// Remove the leading '/'
332332
text = text[1..];
333333

334334
// Split command and argument
335-
var parsedText = text.Split(' ', 2);
336-
string command;
337-
string? argument = null;
338-
switch (parsedText.Length)
335+
ReadOnlySpan<char> command, argument;
336+
var spacePos = text.IndexOf(' ');
337+
if (spacePos == -1)
339338
{
340-
case <= 0:
341-
return (null, null);
342-
case 2:
343-
argument = parsedText[1];
344-
goto default;
345-
default:
346-
command = parsedText[0];
347-
break;
339+
command = text;
340+
argument = ReadOnlySpan<char>.Empty;
341+
}
342+
else if (spacePos == text.Length - 1)
343+
{
344+
command = text[..spacePos];
345+
argument = ReadOnlySpan<char>.Empty;
346+
}
347+
else
348+
{
349+
command = text[..spacePos];
350+
argument = text[(spacePos + 1)..];
348351
}
349352

350353
// Verify and remove trailing '@bot' from command
351354
var atSignIndex = command.IndexOf('@');
352355
if (atSignIndex != -1)
353356
{
354-
var atUsername = command[atSignIndex..];
355-
if (atUsername != $"@{botUsername}")
356-
return (null, null);
357+
if (atSignIndex != command.Length - 1)
358+
{
359+
var atUsername = command[(atSignIndex + 1)..];
360+
if (!atUsername.SequenceEqual(botUsername))
361+
{
362+
return (null, null);
363+
}
364+
}
357365

358366
command = command[..atSignIndex];
359367
}
360368

361369
// Trim leading and trailing spaces from argument
362-
if (argument is not null)
370+
argument = argument.Trim();
371+
372+
// Convert back to string
373+
string? commandString = null;
374+
string? argumentString = null;
375+
if (!command.IsEmpty)
363376
{
364-
argument = argument.Trim();
377+
commandString = command.ToString();
378+
379+
if (!argument.IsEmpty)
380+
{
381+
argumentString = argument.ToString();
382+
}
365383
}
366384

367-
return (command, argument);
385+
return (commandString, argumentString);
368386
}
369387
}

0 commit comments

Comments
 (0)