#Regex Challenge using strfind()

1 messages · Page 1 of 1 (latest)

lunar hornet
#

Take this string "1d6 + 2, -10, 2D8" and have strfind() return 3 results (getFindCount()) while at the same time capturing the numDice (1 of 1d6+2), dieSides (6 of 1d6+2) and bonus (2 of 1d6+2). For example, this will capture just the 1d6 + 2 [H: str = "1d6 + 2, -10, 2D8"] [H: regex = "([0-9]+)d([0-9]+)([0-9 +-]+)"] [H: id = strfind(str,regex)] [H: output = "[]"] [H,for(match,1,getFindCount(id)+1): output = json.append(output,"Match "+match+" = [" +getGroup(id,match,0)+"]")] [R: json.toList(output,"<br>")]
I'll post my solution later.

sinful spruce
#

The example allows multiple +'s and -'s in a row when evaluating the first expression, so something like 1d6 ++-++ 2 would be parsed as success and would return ++-++ 2 as the third value. That expression is also not anchored to the beginning of the string, which means it could match any portion of the original string. I would recommend this:

[H: regex = "^\s*(\d+)?[Dd](\d+)(\s*[-+]\s*(\d+))?"]

That expression will match the original, but enforces only a single +/- (not both and not multiple). It also allows the expression following the die roll to be optional. Since your original string used d in one place and D in another, I allowed either to be used. (I would probably extend the requirements to include one or more die rolls to be allowed in front of the first comma, so that 1d6+2d6+1d10-2 would work. If the expression allowed the die roll to be optional, it could be repeated and a comma added so that the same expression would match all three portions of the input.)

lunar hornet
#

The challege is allow all 3 entries. I'm not too worried about invalid entries, just weird valid entries. Your example didn't give any valid returns if you plug your regex line in with the above example. By putting the ^ at the beginning it will only make 1 match at most because there is only one beginning of line and I want to get 3 matches.

sinful spruce
#

Did I get the number of backslashes wrong or something? Hm, I’ll take a look.

Yeah, the BOL marker would be combined with a repeat count to match all three. I’ll type an example shortly (on my phone atm).

lunar hornet
#
[H: str =  "1d6 + 2, -10, 2D8"]
[H: regex = "(?i)((([0-9]+)d([0-9]+) *([+-] *[0-9]+)*)|((?= *)([+-] *[0-9]+)))(?=[ ,]*)"]
[H: id = strfind(str,regex)]
[H: output = "[]"]
[H,for(match,1,getFindCount(id)+1), code: {
   [H: output = json.append(output,"Match "+match+" = [" +getGroup(id,match,0)+"]")]
}]
[R: json.toList(output,"<br>")]

Output Player: Match 1 = [1d6 + 2] Match 2 = [-10] Match 3 = [2D8]

Explanation:

(?i) - ignore case
Groups are counted left to right using the ( to start new group, but ignoring (?..) look aheads
Group 1 - Contains the full expression
((([0-9]+)d([0-9]+) *([+-] *[0-9]+)*)|((?= *)([+-] *[0-9]+)))

Group 2 - Contains only the xdy+z part of expression
(([0-9]+)d([0-9]+) *([+-] *[0-9]+)*)

Group 3 - Contains the numDice part
([0-9]+)

Group 4 - Contains the numSides part
([0-9]+)

Group 5 - Contains the Bonus part which is optional
([+-] *[0-9]+)*

Group 6 - Contains a number only expression ignore preceding spaces in capture
((?= *)([+-] *[0-9]+))

Group 7 - Contains the number only value
([+-] *[0-9]+)

The ending (?=[ ,]*) is there separate the expression capture groups, but not include it in capture.

I use the | (or) to say capture a xdy+z expression or just a value.

Finally, to determine what I have I get the "number only" value and if not valid or 0 use the expression. Here is the actual code I use in my macro.

#
<!-- extract expressions -->
[H: regex.expression = "(?i)((([0-9]+)d([0-9]+) *([+-] *[0-9]+)*)|((?= *)([+-] *[0-9]+)))(?=[ ,]*)"]
[H: id = strfind(trim(string(eval("damage.expression"))),regex.expression)]
[H: expression = "[]"]
[H: prop = "damage"]
[H, for(match,1,getFindCount(id)+1), code: {
   [H: numOnly = number(getGroup(id,i,7))]
   [H, if(! numOnly): 
      obj = json.set("{}",
         prop+".expression",getGroup(id,match,1),
         prop+".diceNum",number(getGroup(id,match,3)),
         prop+".diceSides",number(getGroup(id,match,4)),
         prop+".diceBonus",number(getGroup(id,match,5));
      obj = json.set("{}",
         prop+".expression",getGroup(id,match,1),
         prop+".diceNum",0,
         prop+".diceSides",0,
         prop+".diceBonus",numOnly
   )]
   [H: expression = json.append(expression,obj)]
}]
#

The goal for me was to allow players to put in multiple damages under the same damage type. In PF2, basic weapon damage can also have multiple types like for one-handed and two-handed grips. Not to mention silly stuff like the Fatal trait where the based weapon damage die changes. I needed to parse out the dice and sides from the expression for these reasons.

flat kraken
#

Not good enough, it should cover other dice expressions, what if I want to subtract Z keep low with an upper bound of W?

#

Call me when you can parse all extant dice expressions

lunar hornet
#

lol

#

I actually have a solution for that too though. If you wrap the expression in {} then it will run as is. I just haven't done that yet. Wanted to get this part working first.

#

One of the players in my game has a weapon that increases damage the more doomed levels he has on him.

#

Currently in death coma being at Doomed 4. In my game, people don't die until Dying 5.

lunar hornet
#

Not that anyone will use this, but I updated the regex to include formulas with dice expressions. Just need to wrap them in {}'s```
[H: regex = "(?i)((([0-9]+)d([0-9]+) *([+-] [0-9]+))|((?= )([+-] *[0-9]+))|((?= )([{][^}]+[}])))(?=[ ,])"]