Your regular expressions on parsing your MV plugin commands?

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,645
Reaction score
717
First Language
Chinese
Primarily Uses
N/A
While I don't find much value in the MV plugin commands personally, I'm told that it's more friendly for non coders, and I'd assume so for now.
However, if a MV plugin command looks like a script call and is written in the way similar to writing a script call, then it seems to me that it's just defeating the purpose of MV plugin commands.
So I've thought about what might have a MV plugin command more friendly to non coders, and the following are what I've got so far:
1. A well-written MV plugin command should have a very forgiving syntax(i.e., very low syntax sensitivity)
2. A well-written MV plugin command should look like plain English(i.e., without syntax being foreign to non coders)

For instance, the following is a very well-written script call:
JavaScript:
setSATBActTimes(actorId, actTimes)
Whereas the following is a MV plugin command counterpart:
Code:
setSATBActTimes actorId actTimes
While they're virtually the same to me, they might have the following differences to non coders:
1. Script calls are always case-sensitive, while MV plugin commands can be implemented in ways that aren't
2. Script calls have syntax like "(", "," and ")" being foreign to non coders

In my experience, in order for MV plugin commands to be really more friendly to non coders, the regular expressions parsing them must be very well-written.
While it's an easy, simple and small task for easy, simple and small MV plugin commands, the regular expressions can become complicated and convoluted with complicated and convoluted MV plugin commands.

For instance, the following is 1 such plugin command:
JavaScript:
pluginCommand argument1  argument2Element1,"argument2, Element 2", "argument2,ElementN' 'argument 3'"argument4'
With the expected result being something like this:
Plugin command name: pluginCommand
Argument 1: argument1
Argument 2: [argument2Element1, "argument2, Element 2", "argument2,ElementN"]
Argument 3: "argument 3"
Argument 4: "argument4"
(Note the difference between single and double quotes)

As you want it to have very forgiving syntax, you'd have to forgive at least the following:
1. While command names and arguments are supposed to be separated by exactly 1 space, the command should treat multiple consecutive spaces as 1 space
2. While elements in array arguments are supposed to be separated by a comma and nothing more, the command should treat consecutive spaces immediately following a comma as just a comma
3. While string argument values are supposed to be enclosed in single or double quotes(i.e., "String" or 'string'), the command should tolerate errors like "string' or 'string"
4. As it's possible for strings to include commas and/or spaces, those inside single or double quotes shouldn't be treated as separators
5. Consecutive arguments as strings without separators(like 'argument 3'"argument4') should still be separated as 2 arguments
So how long does it take for you to come up with regular expressions that work very well? It took about an hour in my case, and here's my answer(verified in https://regex101.com/):
Separating command names and arguments -
JavaScript:
match(/(?:[^'", ]+|['"][^'"]*['"])(?:, *(?:[^'", ]+|['"][^'"]*['"]))*/gim)
Separating array argument elements -
JavaScript:
match(/[^'", ]+|['"][^'"]*['"]/gim)
Eliminating strings like "string' or 'string" -
JavaScript:
replace("'", "\"")
On a side note: The command name will be converted to be all capital letters to be case-insensitive, and in order for these regular expressions to work, command356 instead of pluginCommand should be extended.

Of course, the command might need to have an even more forgiving syntax, like not limiting the command name and argument separator to be a space, and not limiting the array argument element separator to be a comma. Maybe something like "-", "|", ":" or ";"(with attached consecutive spaces tolerated) should be considered as well.
But the point remains that, it takes a solid understanding on how regular expressions work in details to be able to write such regular expressions, at least quickly(which isn't my case as I took an hour), as the essence of parsing friendly MV plugin commands is to turn plain English with very forgiving grammars into JavaScript data, which involves advanced concepts and techniques that can never be taken lightly.
While I'll want to try even if it's hard, I don't think it's a must, so I think an alternative would be just writing plugin command for easy, simple and small tasks, and reserve the complicated and convoluted ones to be script calls only.

So these are my 2 cents on writing regular expressions to parse MV plugin commands that are supposed to be very friendly to non coders.
I'd like to know yours as well, so maybe we can collect some wisdom here, even though it's going to be a thing in the past in MZ :)
 
Last edited:

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
503
Reaction score
220
First Language
English
Primarily Uses
RMMV
While regular expressions are great, I'd suggest that they aren't necessarily your only option for parsing things. Take a simple example... let's suppose we have a plugin command that opens a small message window above an on-map character, with a name box (or at least, with the name formatted separately from the message). The basic desired syntax is something like:

Code:
Talk <charId> <name> <message>
But you want to allow name and message to have spaces in them! So the built-in parsing is woefully insufficient. A simple solution would be to allow quotes around the name, and for the message, since it's the last argument, you can just collect all the leftovers.

This gives you something like this:

Code:
var id = args.shift();
var name, message;
if(name.startsWith('"')) {
    name = '';
    do {
        name += args.shift();
    } while(!name.endsWith('"'));
    name = name.slice(1,-1);
} else if(name.startsWith("'")) {
    // Basically the same as the above branch, only ending on ' instead of "
} else {
    name = args.shift();
}
message = args.join(' ');
No regular expressions, much more user-friendliness. Though it does make use of quotes to collect text, that should be more familiar to users than most programming notations.
(Of course, you'd also check the command name case-insensitively.)

But it really depends on what you need, of course. Regular expressions are great for things that don't rely on balanced delimiters (such as quotes or brackets).

I think your example can also be done by some combination of joins and splits. Whether or not that's better than the regular expression you came up with though, I can't say.
 

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,645
Reaction score
717
First Language
Chinese
Primarily Uses
N/A
Code:
Talk <charId> <name> <message>
For me, it's a very well-written plugin command and your way's much, much better than mine if most plugin commands are written this way, but if there are some users having problems with using a script call like this:
JavaScript:
setSATBActTimes(actorId, actTimes)
while not having problems with using a plugin command like this:
JavaScript:
setSATBActTimes actorId actTimes
I wonder if they'll be ok with having to enclose arguments with <>, as these symbols, while being a second nature to us, might be alien to them.
Even though this argument sounds even strange to myself, I'm told that the even such an easy, simple and small script call, involving just "()" and ",", can already be too intimidating to some non coders.

I'm thinking this way because most plugin commands I've seen are so similar to script calls to me that I failed to even find any meaningful value to use plugin commands over script calls(other than giving another way to do the same thing), so I feel that a well-written plugin command designed for non coders has to be like plain English with very forgiving grammars in order to be friendly enough for them.
Maybe I'm just getting something very wrong though :)

P.S.: I'd like to know, in your example, how you'd handle errors like the following:
1. "[]", "{}", "()" instead of "<>"
2. "<]", "[>" instead of "<>"
3. "<<>", "<>>" instead of "<>"
4. "<", ">" instead of "<>"
Will you try to forgive these syntax errors(of course forgiving everything's impossible but one can always try his/her best), or will you just ignore these invalid commands(perhaps with a console warning informing users about those)?
 
Last edited:

Eliaquim

Hakuen Studio
Veteran
Joined
May 22, 2018
Messages
1,425
Reaction score
679
First Language
Portuguese - Br
Primarily Uses
RMMV
Nice observations!
I personally don't like to use regular expressions in plugin commands(because of possible performance issues) There are many things happening under the hood of regular expressions and I not mastered it yet, so I avoid.

I think the most valuable use for plugin command, besides being more familiar with noncoders, is that does not use eval() as script call does.
But I think you can have other things in mind. Rpg Maker users are friendly with the escape codes messages:
\v[x], \c[x] etc...
Maybe you(we) can follow the logic for this to make nice plugin commands for the users as I did with one of my plugins that you can use variables in plugin commands.

But I like to keep the format, more like this, when it is possible:
Command arg1 arg2
SetWeather rain 60

And instead of use a regex or switch statements, I try to make an array or object lookup table.
 

ImaginaryVillain

Now A YouTube Cool Kid! =D
Veteran
Joined
Jun 22, 2019
Messages
636
Reaction score
2,807
First Language
Absurdism
Primarily Uses
RMMV
Wow... I never noticed that MV uses Eval to handle script calls.... That explains so much why it's performance is so terrible if a script call is called repeatedly versus adding it to MV's update cycle.
 

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,645
Reaction score
717
First Language
Chinese
Primarily Uses
N/A
But I think you can have other things in mind. Rpg Maker users are friendly with the escape codes messages:
\v[x], \c[x] etc...
Maybe you(we) can follow the logic for this to make nice plugin commands for the users as I did with one of my plugins that you can use variables in plugin commands.
So I guess most non coders will be okay with this then?
JavaScript:
pluginCommand[argument1][argument2Element1, "argument2, Element 2", "argument2,ElementN']['argument 3']["argument4']
Wow... I never noticed that MV uses Eval to handle script calls.... That explains so much why it's performance is so terrible if a script call is called repeatedly versus adding it to MV's update cycle.
I wonder if you're thinking about something like this instead:
JavaScript:
// Script
Game_Interpreter.prototype.command355 = function() {
    var script = this.currentCommand().parameters[0] + '\n';
    while (this.nextEventCode() === 655) {
        this._index++;
        script += this.currentCommand().parameters[0] + '\n';
    }
    // eval(script);
    var cachedFunction = Game_Interpreter._scriptFunctions[script];
    if (cachedFunction) {
        cachedFunction();
    } else {
        var newFunction = new Function(script);
        Game_Interpreter._scriptFunctions[script] = newFunction;
    }
    return true;
};
 
Last edited:

ImaginaryVillain

Now A YouTube Cool Kid! =D
Veteran
Joined
Jun 22, 2019
Messages
636
Reaction score
2,807
First Language
Absurdism
Primarily Uses
RMMV
@DoubleX You're pretty much my favorite person right now. I'm so going to toss that into a plugin and see if it makes a difference. Thanks! :LZSexcite:
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
503
Reaction score
220
First Language
English
Primarily Uses
RMMV
For me, it's a very well-written plugin command and your way's much, much better than mine if most plugin commands are written this way, but if there are some users having problems with using a script call like this:
JavaScript:
setSATBActTimes(actorId, actTimes)
while not having problems with using a plugin command like this:
JavaScript:
setSATBActTimes actorId actTimes
I wonder if they'll be ok with having to enclose arguments with <>, as these symbols, while being a second nature to us, might be alien to them.
Even though this argument sounds even strange to myself, I'm told that the even such an easy, simple and small script call, involving just "()" and ",", can already be too intimidating to some non coders.

I'm thinking this way because most plugin commands I've seen are so similar to script calls to me that I failed to even find any meaningful value to use plugin commands over script calls(other than giving another way to do the same thing), so I feel that a well-written plugin command designed for non coders has to be like plain English with very forgiving grammars in order to be friendly enough for them.
Maybe I'm just getting something very wrong though :)
It looks like you've misunderstood something. The line you quoted was supposed to be merely illustrative of the basic structure of the command, and I was using <> as a syntax to indicate a placeholder. An actual use of the command would look like this:

Code:
Talk 5 "Master Harold" How are you?
That said, if you modified my sample code to test for brackets instead of quotes, then there exists an answer to your questions. Keep in mind that it was a simple example without any error handling, so actually handling unusual cases would need some additional code.

Code:
var id = args.shift();
var name, message;
if(name.startsWith('<')) {
    name = '';
    do {
        name += args.shift();
    } while(!name.endsWith('>'));
    name = name.slice(1,-1);
} else if(name.startsWith("[")) {
    // Basically the same as the first branch, only ending on ] instead of >
} else if(name.startsWith("(")) {
    // Basically the same as the first branch, only ending on ) instead of >
} else if(name.startsWith("{")) {
    // Basically the same as the first branch, only ending on } instead of >
} else {
    name = args.shift();
}
message = args.join(' ');
P.S.: I'd like to know, in your example, how you'd handle errors like the following:
1. "[]", "{}", "()" instead of "<>"
2. "<]", "[>" instead of "<>"
3. "<<>", "<>>" instead of "<>"
4. "<", ">" instead of "<>"
Will you try to forgive these syntax errors(of course forgiving everything's impossible but one can always try his/her best), or will you just ignore these invalid commands(perhaps with a console warning informing users about those)?
  1. Easily handled by just having multiple branches. Since the code in each branch is basically the same, it could be split to a plugin.
  2. As written, this would be an infinite loop. That's easily solved by adding an && args.length check to the loop, though. Unfortunately, that means that the name consumes the rest of the parameters, and there is no message. I don't think there's any good way to recover from this. How is the code supposed to guess that they'd use two completely different bracket types? The best you could do is probably a console warning that the message is empty.
  3. This would just work. The resulting name would contain either a < or > character.
  4. I'm not sure what you mean by this.
 

Trihan

Speedy Scripter
Veteran
Joined
Apr 12, 2012
Messages
2,382
Reaction score
1,567
First Language
English
Primarily Uses
RMMV
In cases where I do use regular expressions to check plugin command syntax, I do make sure it's as robust as possible with as much leeway for user error (case insensitive, eliminating multiple spaces etc. as you said).
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
503
Reaction score
220
First Language
English
Primarily Uses
RMMV
Yes, agreed; I don't generally use regex for plugin commands, but I do sometimes use it for note tags. To be clear, that means parsing the value of the meta property, not extracting the note tag from the raw note field. I try to allow for spaces to appear nearly anywhere, and use a case-insensitive regex.

My SwitchCommand plugin is a good example of my regex usage. I believe it does satisfy the above properties. It's probably not as user-friendly as it could be, mind you; it does introduce weird syntax.
 

Kino

EIS Game Dev
Veteran
Joined
Nov 27, 2015
Messages
527
Reaction score
744
First Language
English
Primarily Uses
RMMV
If I'm using regular expressions, I give the user space for error.
 

Trihan

Speedy Scripter
Veteran
Joined
Apr 12, 2012
Messages
2,382
Reaction score
1,567
First Language
English
Primarily Uses
RMMV
Also for anyone who uses regex for programming, I cannot recommend enough a little program called The Regex Coach. It's free and allows you to specify your pattern and sample text to parse with it (plus you can step through your match pattern step by step if it's not working to figure out why)
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

How do you cure sleep problem? It has been 7 months and it's 3 AM now..
Darn you, Seals! Why do you gotta be so cute when on land?:kaoluv:
So dragonbones getting laggy xD
I even removed the fingers armatures.

Have to remake this guy after crashing ( corrupted file).
:rtear:

Although limited to only this shop for room decorations, I like this aspect for previewing items.
So yesterday I got a follower (follow my NSFW art account) who dmed me and said to me :
if you continue to be friends with [name of the artists] which make me uncomfortable I will have to unfollow and I am like :
... do it?

Forum statistics

Threads
100,837
Messages
980,125
Members
132,487
Latest member
AnthonyDewitt
Top