English [Tip] Stop using string.sub() for commands

13 replies
Goto Page
To the start Previous 1 Next To the start
Up
VaiN
User
Offline Off
Something I see a lot with scripts here is the usage of string.sub() to check for a specific command. This is slow and ugly and not very efficient use of Lua in general.

There's a easier way to work with strings in Lua (once you get the hang of it). Lua pattern matching can be very powerful.

I'm not going to try to teach you pattern matching, that's something you really have to play with to fully grasp, but I'll give you some examples of how it can help with scripting for CS2D.

Checking for commands:
Code:
1
2
3
4
5
6
-- get the the first word if it starts with "!" or "@"
-- with an optional space after it (not included in the result)
local cmd = txt:match("^([!|@][%w]+)[%s]?")

-- get everything after the first space
local aftercmd = txt:match("[%s](.*)")


This makes it much easier to check for, and work with, commands.

Here's another useful function to add to that:
Code:
1
2
3
4
5
6
function string:split(sep)
  local sep,words = sep or " ", {}
  local pattern = string.format("([^%s]+)",sep)
  self:gsub(pattern, function(c) words[#words+1] = c end)
  return words
end

This will split any string into a table. It splits at whatever character you specify, if none then it splits words. This allows you to easily get the arguments of a command.

so for a command like:
@setrank <ID> <Rank>
you can easily capture each argument into a table:
Code:
1
2
3
local args = aftercmd:split()
local id = tonumber(args[1])
local rank = args[2]


This is far easier to work with than string.sub() in my opinion, as you can automate this with a command processing function.

Hope that helps someone.

If you are interested in more tips like this, let me know.
27.10.15 10:17:36 am
Up
tontonEd
User
Offline Off
good tip, it does look a lot better with patern matching.
but why string.sub method should be slower ?
yes more tips
27.10.15 10:24:29 am
Up
DaisukeOno
User
Offline Off
Looks good, but i not really sure people will use this.
I have a potato internet
27.10.15 11:16:34 am
Up
VaiN
User
Offline Off
user tontonEd has written:
good tip, it does look a lot better with patern matching.
but why string.sub method should be slower ?
yes more tips


It's actually slower in two ways.

1. It's literally slower to script with string.sub() as it's more to type. The string:split() example show this with the in-line function, as you would instead have to loop through each character looking for a space, or check for an exact match, or find where a space is and get another subset of the string, ect. By plugging the pattern in to gsub it does the iterating for you.

2. Lua pattern matching is optimised for searching strings for specific sub-sets of string and for conforming to a set format.

Not sure if I'm explaining it very clearly, but here's another example:
Code:
1
2
3
function valid_email(email)
     return email:match("[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?")
end

a single line to check if a string is a valid email format. imagine trying to validate an unknown string as an email any other way lol

I can expand upon this and show an example of how a command processor can make things much more efficient for CS2D if you'd like.
27.10.15 12:52:45 pm
Up
XoOt
Super User
Offline Off
Seems helpful, thanks for sharing
27.10.15 01:06:46 pm
Up
DannyDeth
User
Offline Off
Pattern matching is computationally more expensive than a substring operation. I think the claim that substrings are "not very efficient" and "slow" in comparison to pattern matching is nonsense except in very few scenarios where Lua's overhead will be enough to make your script surpass the cost of pattern matching. The ugliness point is indisputable. Though regexp strings aren't exactly eye candy either IMO.
27.10.15 01:38:37 pm
Up
Rainoth
Moderator
Offline Off
@user DaisukeOno: A lot of people are already using it.

It's really simple. If a person on forum asks for two commands, I'll use txt:sub(a,b)
If I'm making a script with 5-80 commands, it's obvious that txt:split() is more convenient.
27.10.15 02:10:25 pm
Up
VaiN
User
Offline Off
@user DannyDeth: What I was meaning is that it's slower not in the sense of computation, but in the sense of time and effort. And having dozens of conditionals with sub-strings is far uglier than a single pattern match. It's easier to script, organize, and read if the commands are defined separately and simply run through a generic handler. And this is why it's more efficient. (I'll show a complete example below)

regarding computational expense:
More >

There's not going to be any noticeable difference in just getting a single word, but the following example shows how using this can be so beneficial.

As @user Rainoth: mentioned, this is for those who are using lots of commands and trying to put hundreds of lines in a single function (which is part of why the LuaJIT update had issues I believe).

Here's a full example of a basic command processor (tested and heavily commented):
More >


With this you could easily have hundreds of commands defined in separate scripts, and keep the command checking generic to handle all of them. Also easily expandable, returning error codes from commands for common checks and drastically reducing the amount of error-prone conditionals. Also showing the correct way to use the command if they did it wrong, without repeating lots of code for each command. It's basically just refactoring.

This also helps to demonstrate how you can modularize a large script system, breaking it down into separate systems that have specific tasks to keep it easier to maintain.

(Edit: Fixed tab spacing in example)
edited 1×, last 27.10.15 02:21:31 pm
27.10.15 02:47:07 pm
Up
Gaios
Security Supporter
Offline Off
Better to post it here thread cs2d Tricks in CS2D Scripting that you might not know. than making a new thread .
27.10.15 03:16:58 pm
Up
DannyDeth
User
Offline Off
@user VaiN: The example you gave falls into the "Lua's overhead surpasses the pattern matching" case I was talking about, so no need to convince me on that front. Also, I understand your arguments about modularity and such, and agree with you. I misunderstood what you were talking about initially.
27.10.15 03:25:25 pm
Up
Nekomata
User
Offline Off
Lua's (and global) Regex is extremely useful and definitely better than the other sub commands however learning it is a bit tricky when it comes to being a newbie. Even tho the regex for lua is simpler than in other languages. o.x
27.10.15 03:43:13 pm
Up
Fraizeraust
Moderator
Offline Off
This is kinda useful, never heard about that. Thanks user VaiN for sharing this tip with us.
27.10.15 04:51:59 pm
Up
omg
User
Offline Off
...yea this is unreadable lol, all my commands use substring and its way easier to change in my opinion. the speed difference is negligible. if its not broken, dont fix it. its not like people are gonna be flooding with say commands
will code for food
27.10.15 06:12:49 pm
Up
tontonEd
User
Offline Off
@user VaiN: ok.
good exemple, I was looking for what you wrote a month ago:
Quote:
[a-z]+
lua doc is so confused.. I thought repetition wasn't possible in lua..

@user omg: I think it is a lot related with the coder sensibility with bash script, this method is the usual way on linux.
To the start Previous 1 Next To the start