|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Mar 27, 2008 5:14 pm
Some more regex trigger issues |
Pattern: .* tells you (.*\(.*\)) '.*'
Isn't firing for tells like these:
Kadence tells you 'oh?' |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Thu Mar 27, 2008 5:33 pm |
Because of the brackets and spaces that aren't optional. The minimum your pattern will match is " tells you () ''", which doesn't match that tell. Use one of the more complex patterns we suggested.
|
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Mar 27, 2008 5:49 pm |
So something like:
Code: |
^(?:(\w+) tells you(?: \(\w+\))?$ |
|
|
|
|
Dharkael Enchanter
Joined: 05 Mar 2003 Posts: 593 Location: Canada
|
Posted: Thu Mar 27, 2008 8:07 pm |
If its just a regular trigger something like
Code: |
^(%w) tells you '(*)'$ |
or
Code: |
^(*) tells you '(*)'$ |
or if its a REGEX trigger
Code: |
^(.*) tells you '(.*)'$ |
If its a regex and you dont want to capture a subgroup
change the opening ( to (?: on that subgroup |
|
_________________ -Dharkael-
"No matter how subtle the wizard, a knife between the shoulder blades will seriously cramp his style." |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Thu Mar 27, 2008 8:17 pm |
Couple of problems with that:
You haven't closed all the brackets (or parens if you like :P) that you've opened. Your pattern doesn't include the speech part of the pattern, between the quotes, but does include the end of the line, so it's going to fail there too.
I suggested a pattern in another thread (don't remember which one, you've started a few :P) that worked for tells to you in languages and your tells to people and your group. I know that one works fine for all your different kinds of tells because I tested it with the text you gave.
EDIT: Ninja'd by Dhark. Just for clarification, I was talking to the OP. |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Mar 27, 2008 8:52 pm |
Alright, the one I took was from a larger one that you posted, probably explaining the unclosed brackets. At this point, there have been so many versions posted that I'm not sure which you refer to. But I may uninstall and reinstall CMUD anyways.
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Thu Mar 27, 2008 8:56 pm |
Post the one you're using, and I'll tell you if it'll work or not, but the one you took that part from is the one I'm talking about, IIRC.
|
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Mar 27, 2008 8:58 pm |
The one I'm using isn't working
|
|
|
|
Dharkael Enchanter
Joined: 05 Mar 2003 Posts: 593 Location: Canada
|
Posted: Thu Mar 27, 2008 9:10 pm |
Post it anyways then we'll have a starting point.
|
|
_________________ -Dharkael-
"No matter how subtle the wizard, a knife between the shoulder blades will seriously cramp his style." |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Mar 27, 2008 9:20 pm |
I'm going to revert back to something simple
* tells you (*) '*'|* tells you '*' |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Thu Mar 27, 2008 9:26 pm |
That may be simple but it's about the worst thing you can do. Everyone showed you how to match the pattern.
First of all though, you should clarify a couple things.
1. At the beginning of the pattern the name of the person telling you, is it always one word like Bob tells you or do they have titles attached or multiple words like Bob, the warrior?
2. Where you have (*) for the type of language, is the language always one word like Elvish or can it be more than one word like Northern Elvish? |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Mar 27, 2008 9:36 pm |
Language is always one word so far as I know. Name is always one word.
I don't want to use something I don't understand. |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Fri Mar 28, 2008 1:16 am |
The reason that oldguy2 calls that pattern 'the worst' is simply that it will be VERY slow, both to match or to reject a match, because of all the greedy '*' quantifiers. If you know that, say, the name at the beginning of the line is always a single word, you can replace that '*' with a regex that will match only letters ('%w' in zScript patterns, or \w in a regex), and the whole thing will be a lot faster.
So, let's tackle this step-by-step. You want to match:
- The beginning of the line
- Followed by a name, consisting of a single word
- Followed by the literal string 'tells you'
- Optionally followed by a language name, consisting of one word surrounded by parens
- Followed by an arbitrary string surrounded by single-quotes
- Followed by the end of the line
right?
I'm going to do this in a regex, rather than a zScript pattern, simply because I'm more familiar with them. I will also explain my thinking in extreme detail.
Step #1 - Match the beginning of the line. That's easy, it's just the special character '^'. So far, so good.
Step #2 - Match a name, consisting of a single word. Well, we could use '.*', which will match any string of characters. However, that will also match a lot of other things, and it's horribly inefficient as well. So let's use something more specific.
Wait, wait, you say....why is it inefficient? Because '*' is a greedy quantifier - it tries to match as long a string as possible, and only gives up a character at a time if it fails. So, using '.*' will cause the regex engine to absorb the entire rest of the subject string, then try to match the rest of the regex. If that doesn't work, it will put back the LAST character that the '.*' absorbed, then try to match the rest of the regex again. If that also fails, it will put back one more character, and try to match the rest of the regex. And so on, and so on. As you can see, it could do a LOT of work to decide that something doesn't match. Or even to figure out what DOES match.
So...what would be better? Well, we know that the name is a single word, consisting of letters, and no spaces. To do so, first we figure out a regex that will match ONE letter. That's easy: '[a-zA-Z]' will do the trick. Or we can use the shorthand '\w', which will actually match any letter, digit, or the underscore ('_') character. We want to match one or more of those characters in a row, so we put the '+' quantifier after the letter. Put it all together, and we have '\w+', which will match a single word.
So, our whole pattern now is
Step #3 - The literal string 'tells you'. Literals are easy - just type 'em in. Actually, we also want to match the spaces at the beginning and end of that literal, so let's be sure they are in, too. So now, the whole pattern is
Step #4 - An optional single word in parens. Hrm...need to break that down. We already know how to match a single word, with '\w+'. To match a word with parens around it, we just type the parens - '(\w+)' - right? Unfortunately, no. Parens are 'special characters' in a regex (more on this later), so we have to put a backslash before each one to tell the regex engine that we mean a real, literal paren, and not the special meaning of the parens. That gives us '\(\w+\)'.
So far, so good. But how do we make it 'optional'? We use another quantifier - '?' - which tells the engine to match zero-or-one instances of the regex it follows. So we have '\(\w+\)?', which will match either (a) nothing, or (b) a word inside parens...right?
Not exactly. The '?' quantifier only modifies the thing RIGHT before it...in this case, the close paren. So that pattern would match an open paren, a word, and an optional close paren. We want the WHOLE THING to be optional. How do we group the whole thing, so that the '?' will apply to it all together?
Remember that I said the parens were special characters? Well, their special meaning is to create groups for just this sort of thing. So, if we put our pattern inside parens, and put the '?' after it, then the whole expression inside the parens becomes optional together. Thus, what we need is '(\(\w+\))?'.
So our pattern is now
Code: |
^\w+ tells you (\(\w+\))? |
Step #5 - An arbitrary string in single quotes. The initial single quote is easy - it's another literal.
Next...an arbitrary string. Hrm. First, we need another special character - '.' - which will match any character whatsoever. And we want to match any number of them. Well, there's no help for it, we'll HAVE to use the greedy * this time. The efficiency won't really be a problem, though, since there's very little left in the pattern after this, so the greedy star SHOULD consume most of the string (if we've really got a match), and won't have to give much back. Also, since we've gotten this far into the pattern, it's fairly likely that we will have a match, so the efficiency at rejecting matches won't matter much either. So that part of the pattern is '.*'.
And we wrap up with a final literal single-quote. So our whole pattern now is
Code: |
^\w+ tells you (\(\w+\))? '.*' |
Step 6 - Match the end of the string. Again, easy. The '$' special character matches the end of the string. So, we've got:
Code: |
^\w+ tells you (\(\w+\))? '.*'$ |
Great! We're done!
But...um...well, not quite. If you try that, you'll find that it matches correctly when there is a language present, but WON'T match if there isn't. Can you see why?
The problem is that we have an extra space in there if no language is present. If the 'optional' part of the regex matches NOTHING, our pattern still shows a space before AND after the 'nothing'....or two spaces. We only want to match ONE space in that case.
So, we have to fix it by moving one of the spaces inside the 'optional' part, so that that space will only be part of the pattern if the language is also there. So our final expression is:
Code: |
^\w+ tells you (\(\w+\) )?'.*'$ |
Easy enough, right?
Final finesse: The other special meaning of parens is to create a 'backreference', which you can access afterward using the %pat() function or the %<number> predefined variables. In our current pattern, we only have one backreference (remember that the other set of parens - the ones with the backslashes - are just literals, with no special meaning). So, we could actually get the language name, if one were present, using %pat(1) or %1 inside this trigger.
But what if we want to access the name of the person doing the telling? Or the message he told? Or, for that matter, the name of the language WITHOUT the parens around it?
We just add more parens! This will allow access to all three of the interesting strings:
Code: |
^(\w+) tells you (\((\w+)\) )?'(.*)'$ |
The name will be in %1, the language in %3 (%2 will have the language name AND the surrounding parens and the trailing space), and the message in %4.
To make it even better, we could tell the engine not to bother storing the pattern matched by the second set of parens, since we don't want it (we want the third one instead, for the language name). That uses the syntax '(?:regex)' in place of the '(regex)' we've used so far. Thus, the whole pattern now is
Code: |
^(\w+) tells you (?:\((\w+\) )?'(.*)'$ |
and now %1 is the name, %2 is the language (if any), and %3 is the message.
See...simple!
Code: |
#REGEX {^(\w+) tells you (?:\((\w+)\) )?'(.*)'$} {#say name: %1;#say language: %2;#say message: %3} |
|
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Fri Mar 28, 2008 2:39 am |
This looks helpful, I'll read it when I get more time :)
|
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Apr 01, 2008 2:20 am |
Wow, it is simple. I feel a it stupid. I'll still make many errors I'm sure. But I have a better grip on it now. Thanks.
|
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Apr 01, 2008 2:29 am |
odd...
#REGEX Ding on Tell {^(\w+) tells you (?:\((\w+)\) )?'(.*)'$} {#play C:\WINDOWS\Media\ding.wav} {General Triggers}
doesn't put it in the General Triggers class, it makes a new one with the command as the name?? |
|
|
|
Dharkael Enchanter
Joined: 05 Mar 2003 Posts: 593 Location: Canada
|
Posted: Tue Apr 01, 2008 2:34 am |
Try
Code: |
#REGEX Ding_on_Tell {^(\w+) tells you (?:\((\w+)\) )?'(.*)'$} {#play C:\WINDOWS\Media\ding.wav} {General Triggers} |
|
|
_________________ -Dharkael-
"No matter how subtle the wizard, a knife between the shoulder blades will seriously cramp his style." |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Apr 01, 2008 2:46 am |
Hmm, I figured CMUD was fine with white space. I'll try it.
|
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Apr 01, 2008 2:47 am |
oh wait, that was the one that worked!
It's this one...
#REGEX Tell Capture {^(\w+) tells you (?:\((\w+)\) )?'(.*)'$} {#CAP Tells} {General Captures}
Oh no, it was the one. But this one didn't work either, same problem I suppose. |
|
|
|
Dharkael Enchanter
Joined: 05 Mar 2003 Posts: 593 Location: Canada
|
Posted: Tue Apr 01, 2008 2:48 am |
Code: |
#REGEX "Tell Capture" {^(\w+) tells you (?:\((\w+)\) )?'(.*)'$} {#CAP Tells} {General Captures} |
|
|
_________________ -Dharkael-
"No matter how subtle the wizard, a knife between the shoulder blades will seriously cramp his style." |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Apr 01, 2008 3:02 am |
Hmm... so I tried to make my own with this info:
#REGEX You_Tell {^You tell \w+ (\(\w+\) )? '.*'$} {#CAP Tells} {General Captures}
But it doesn't work...
You tell Kadence (Elvish) 'blah'
doesn't work. |
|
|
|
Dharkael Enchanter
Joined: 05 Mar 2003 Posts: 593 Location: Canada
|
Posted: Tue Apr 01, 2008 3:13 am |
Use a regex similar to your "Tell Capture" trigger
Code: |
^You tell \w+ (?:\((\w+)\) )?'(.*)'$ |
|
|
_________________ -Dharkael-
"No matter how subtle the wizard, a knife between the shoulder blades will seriously cramp his style."
Last edited by Dharkael on Tue Apr 01, 2008 3:14 am; edited 1 time in total |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Apr 01, 2008 3:14 am |
all I say see that's different is the ?: what makes it so crucial?
|
|
|
|
Dharkael Enchanter
Joined: 05 Mar 2003 Posts: 593 Location: Canada
|
Posted: Tue Apr 01, 2008 3:25 am |
You're correct you just had an extra space in your pattern
the \) )? instead of \))?
or you could look at it like you had an extra space after the \) )? |
|
_________________ -Dharkael-
"No matter how subtle the wizard, a knife between the shoulder blades will seriously cramp his style." |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Apr 01, 2008 3:28 am |
I put the space in because of the earlier mentioned thing about spaces being optional... why was it wrong?
|
|
|
|
|
|