macro regex issue, end of line in multiline

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice

User avatar
celestian
Dragon
Posts: 276
Joined: Mon May 17, 2010 3:29 pm

macro regex issue, end of line in multiline

Post by celestian »

I'm having an issue trying to figure out what gets me "end of line" on a multiline text from form textbox.

Code: Select all

[h: text = encode(importText)]
[foreach(encodedLine,text, "", "%0A"), code: {
	[h: line = decode(encodedLine)]

	[h: id = strfind(line, "(?i)Size:\\s+(.*)\\b")]
	[h, if( !foundMatch && getFindCount(id)>0), code :{
		[npcFields = json.set(npcFields,"size",getGroup(id, 1, 1))]
		[foundMatch = 1]
	};{}]

}]
I used encoded line to flip through each line and then decode the line, then I test the decoded line of text for strings. I've trimmed it down to just the one search for "Size: L (9 ' foot)" matching.

The above works EXCEPT it chops off the ")" right after "foot". It does that for any match with a ) on the end. I tried what I thought
was a valid regex (\\$) for end of line but it caused the macro to generate "Error in roll".

Any thoughts/suggestions?

User avatar
aliasmask
RPTools Team
Posts: 9024
Joined: Tue Nov 10, 2009 6:11 pm
Location: Bay Area

Re: macro regex issue, end of line in multiline

Post by aliasmask »

Depending on the source of the text, either text entered manually or cut/paste from another source you should replace the Line Feed + Carriage Return with just the Line Feed.

Code: Select all

[H: LF = encode("%0A")]
[H: CR = encode("%0D")]
[H: regex = strformat("%{LF}%{CR}?")]
[H: newText = replace(textAreaText,regex,LF)]
Then I split the textarea in to a json.

Code: Select all

[H: lines = json.fromList(newText,LF)]
[H, foreach(line,lines), code: {
   ...
}]
You may want to also remove or replace characters outside the normal alpha numeric character set.

Code: Select all

[H: newText = replace(newText,strformat("[ -~%{LF}]"),"")]

User avatar
celestian
Dragon
Posts: 276
Joined: Mon May 17, 2010 3:29 pm

Re: macro regex issue, end of line in multiline

Post by celestian »

Thanks for the tips, I tried those but didn't seem to help my issue ;(

I guess my problem is I need to know what regular expression to use to detect a LF or a "end of string" in a decoded() text. \\b isn't working right. As I said it's truncating just ")" off. I am not sure why it's just ) and not the last character on every line...

The encoded string is:

Code: Select all

Size%3A%09L+%289'+long%29
Text is

Code: Select all

Size:	L (9’ long)
So while I was typing this up I was trying to figure out why $ wouldn't work and...

Code: Select all

[h: id = strfind(line, "(?i)Size:\\s+(.*)\$")]
Works. I guess I was trying a bare $ and a \\$ and never tried a single \$

That captures to end of line as needed ;) Again thanks for the tips in the other areas. I'll make use of them.

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: macro regex issue, end of line in multiline

Post by wolph42 »

good that you found it!
\\b isn't working right
I guess you don't mean it that way, but just in case: \b IS working right! Its a word boundary and ")" is never part of a 'word'.

User avatar
celestian
Dragon
Posts: 276
Joined: Mon May 17, 2010 3:29 pm

Re: macro regex issue, end of line in multiline

Post by celestian »

wolph42 wrote:good that you found it!
\\b isn't working right
I guess you don't mean it that way, but just in case: \b IS working right! Its a word boundary and ")" is never part of a 'word'.
You are correct ;) I had tried various regex trying to get it to work and that was a close as I could at the time. I got a bit confused on the double versus single "\" and $.

User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

Re: macro regex issue, end of line in multiline

Post by Sereptus »

I'm having a similar issue regarding end of line "capture" if you will. I'm simply looking for the correct regex to find the carriage return in any given line of input. I'm working on a 5E D&D statblock importer and it works well but I'm adding some flavor by putting some macros on the token as well as the properties. I just basically just copied AliasMask's PF/3.5 importer but made it so it works with 5E D&D. Anyhoo, I'm trying to extract just this line in two parts.

"Multiattack. The dragon can use its Frightful Presence. It then makes three attacks: one with its bite and two with its claws."

It comes between other text which is variable like...

"Actions

Multiattack. The dragon can use its Frightful Presence. It then makes three attacks: one with its bite and two with its claws.

Bite. Melee Weapon Attack: +17 to hit, reach 15 ft., one target. Hit: 21 (2d10 + 10) piercing damage."


First I need "Multiattack" and then the rest of the text on that line only. This is the code I use to try and get both groups that I need.

Code: Select all

[H: MA = strfind(statblock, "(?i)(Multiattack.)(.+?) \Melee")]
[H, IF(0< getFindCount(MA)), CODE: {
   [MAD=getGroup(MA, 1, 1)]
      [MADesc=getGroup(MA, 1, 2)]
      [h:createMacro(MAD, MADesc, ButtonProps2)]
};{   
	[MAD=""]
      [MADesc=""]
      }]
This returns;
Multiattack. The dragon can use its Frightful Presence. It then makes three attacks: one with its bite and two with its claws. Bite.

In as much as getting Multiattack works, I can't get it to stop at the carriage return which comes after claws. It would be easy if I knew Bite always came after the line I'm looking for but it doesn't.

I have of course tried several iterations of this but to no avail. I use "\Melee" to stop it but obviously this isn't efficient or effective. For now this is the closest I can get without it spitting out the rest of the statblock or just getting the word The.

Is there no way to find the carriage return? Since "\r" or "\r\n" doesn't work? I've looked at encode and decode as well but my knowledge with regex and programming is limited to what I've learned with Maptool thus far.

EDIT: I think I found my answer here http://forums.rptools.net/viewtopic.php ... age+return so I'll look further into it there.

EDIT: Nope, if anyone can help me on this it would be greatly appreciated!
OOOHH RegEx....YOU BITTER-SWEET BEAST!!!

User avatar
aliasmask
RPTools Team
Posts: 9024
Joined: Tue Nov 10, 2009 6:11 pm
Location: Bay Area

Re: macro regex issue, end of line in multiline

Post by aliasmask »

The way the data is entered matters. With the statblock importer, there are no CRLF because the info is entered via input() text field which filters out those characters.

If you post the statblock then I can give suggestions.

User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

Re: macro regex issue, end of line in multiline

Post by Sereptus »

Thanks AM, but at the beginning of the statblock importer you wrote there is this line of code:

Code: Select all

[H: CRLF = decode("%0D%0A")] 
which I just left there. So for a long time I had no idea what that was, and even after looking into this I figured this would decode them so they would still exist after inputting the text (input). Anyway, I gleen my statblocks from here http://chisaipete.github.io/bestiary/cr ... old-dragon

Then put them into the GM notes (I don't have to do this but it's a good habit) and I plan to do that via the importer like yours at some point, so anyhoo here is the copied text from the site;
Spoiler
Ancient Gold Dragon
Tags: gargantuan dragon cr24 monster-manual
Gargantuan dragon, lawful good

Armor Class 22 (natural armor)

Hit Points 546 (28d20+252)

Speed 40 ft., fly 80 ft., swim 40 ft.

STR DEX CON INT WIS CHA
30 (+10) 14 (+2) 29 (+9) 18 (+4) 17 (+3) 28 (+9)
Saving Throws Dex +9, Con +16, Wis +10, Cha +16

Skills Insight +10, Perception +17, Persuasion +16, Stealth +9

Damage Immunities fire

Senses blindsight 60 ft., darkvision 120 ft.

Languages Common, Draconic

Challenge 24 (62,000 XP)

Amphibious. The dragon can breathe air and water.

Legendary Resistance (3/Day). If the dragon fails a saving throw, it can choose to succeed instead.

Actions

Multiattack. The dragon can use its Frightful Presence. It then makes three attacks: one with its bite and two with its claws.

Bite. Melee Weapon Attack: +17 to hit, reach 15 ft., one target. Hit: 21 (2d10 + 10) piercing damage.

Claw. Melee Weapon Attack: +17 to hit, reach 10 ft., one target. Hit: 17 (2d6 + 10) slashing damage.

Tail. Melee Weapon Attack: +17 to hit, reach 20 ft., one target. Hit: 19 (2d8 + 10) bludgeoning damage.

Frightful Presence. Each creature of the dragon’s choice that is within 120 feet of the dragon and aware of it must succeed on a DC 24 Wisdom saving throw or become frightened for 1 minute. A creature can repeat the saving throw at the end of each of its turns, ending the effect on itself on a success. If a creature’s saving throw is successful or the effect ends for it, the creature is immune to the dragon’s Frightful Presence for the next 24 hours.

Breath Weapons (Recharge 5-6). The dragon uses one of the following breath weapons.

Fire Breath. The dragon exhales fire in a 90-foot cone. Each creature in that area must make a DC 24 Dexterity saving throw, taking 71 (13d10) fire damage on a failed save, or half as much damage on a successful one.

Weakening Breath. The dragon exhales gas in a 90-foot cone. Each creature in that area must succeed on a DC 24 Strength saving throw or have disadvantage on Strength-based attack rolls, Strength checks, and Strength saving throws for 1 minute. A creature can repeat the saving throw at the end of each of its turns, ending the effect on itself on a success.

Change Shape. The dragon magically polymorphs into a humanoid or beast that has a challenge rating no higher than its own, or back into its true form. It reverts to its true form if it dies. Any equipment it is wearing or carrying is absorbed or borne by the new form (the dragon’s choice).

In a new form, the dragon retains its alignment, hit points, Hit Dice, ability to speak, proficiencies, Legendary Resistance, lair actions, and Intelligence, Wisdom, and Charisma scores, as well as this action. Its statistics and capabilities are otherwise replaced by those of the new form, except any class features or legendary actions of that form.

Legendary Actions

The ancient gold dragon can take 3 legendary actions, choosing from the options below. Only one legendary action option can be used at a time, and only at the end of another creature’s turn. The ancient gold dragon regains spent legendary actions at the start of its turn.

Detect. The dragon makes a Wisdom (Perception) check.

Tail Attack. The dragon makes a tail attack.

Wing Attack (Costs 2 Actions). The dragon beats its wings. Each creature within 15 ft. of the dragon must succeed on a DC 25 Dexterity saving throw or take 17 (2d6 + 10) bludgeoning damage and be knocked prone. The dragon can then fly up to half its flying speed.
And from the GM notes (which I use)
Spoiler
Ancient Gold Dragon

Gargantuan dragon, lawful good

Armor Class 22 (natural armor)

Hit Points 546 (28d20+252)

Speed 40 ft., fly 80 ft., swim 40 ft.

STR DEX CON INT WIS CHA
30 (+10) 14 (+2) 29 (+9) 18 (+4) 17 (+3) 28 (+9)

Saving Throws Dex +9, Con +16, Wis +10, Cha +16

Skills Insight +10, Perception +17, Persuasion +16, Stealth +9

Damage Immunities fire

Senses blindsight 60 ft., darkvision 120 ft.

Languages Common, Draconic

Challenge 24 (62,000 XP)

Amphibious. The dragon can breathe air and water.

Legendary Resistance (3/Day). If the dragon fails a saving throw, it can choose to succeed instead.

Actions

Multiattack. The dragon can use its Frightful Presence. It then makes three attacks: one with its bite and two with its claws.

Bite. Melee Weapon Attack: +17 to hit, reach 15 ft., one target. Hit: 21 (2d10 + 10) piercing damage.

Claw. Melee Weapon Attack: +17 to hit, reach 10 ft., one target. Hit: 17 (2d6 + 10) slashing damage.

Tail. Melee Weapon Attack: +17 to hit, reach 20 ft., one target. Hit: 19 (2d8 + 10) bludgeoning damage.

Frightful Presence. Each creature of the dragon’s choice that is within 120 feet of the dragon and aware of it must succeed on a DC 24 Wisdom saving throw or become frightened for 1 minute. A creature can repeat the saving throw at the end of each of its turns, ending the effect on itself on a success. If a creature’s saving throw is successful or the effect ends for it, the creature is immune to the dragon’s Frightful Presence for the next 24 hours.

Breath Weapons (Recharge 5-6). The dragon uses one of the following breath weapons.

Fire Breath. The dragon exhales fire in a 90-foot cone. Each creature in that area must make a DC 24 Dexterity saving throw, taking 71 (13d10) fire damage on a failed save, or half as much damage on a successful one.

Weakening Breath. The dragon exhales gas in a 90-foot cone. Each creature in that area must succeed on a DC 24 Strength saving throw or have disadvantage on Strength-based attack rolls, Strength checks, and Strength saving throws for 1 minute. A creature can repeat the saving throw at the end of each of its turns, ending the effect on itself on a success.

Change Shape. The dragon magically polymorphs into a humanoid or beast that has a challenge rating no higher than its own, or back into its true form. It reverts to its true form if it dies. Any equipment it is wearing or carrying is absorbed or borne by the new form (the dragon’s choice).

In a new form, the dragon retains its alignment, hit points, Hit Dice, ability to speak, proficiencies, Legendary Resistance, lair actions, and Intelligence, Wisdom, and Charisma scores, as well as this action. Its statistics and capabilities are otherwise replaced by those of the new form, except any class features or legendary actions of that form.

Legendary Actions

The ancient gold dragon can take 3 legendary actions, choosing from the options below. Only one legendary action option can be used at a time, and only at the end of another creature’s turn. The ancient gold dragon regains spent legendary actions at the start of its turn.

Detect. The dragon makes a Wisdom (Perception) check.

Tail Attack. The dragon makes a tail attack.

Wing Attack (Costs 2 Actions). The dragon beats its wings. Each creature within 15 ft. of the dragon must succeed on a DC 25 Dexterity saving throw or take 17 (2d6 + 10) bludgeoning damage and be knocked prone. The dragon can then fly up to half its flying speed.
Eventually I'm going to try and parse the Legendary Actions, Breath Weapons, and special stuff like Amphibious in the example above. Knowing how to tell when the line ends or where carriage return is would be a big help. Like I mentioned in the previous post the attributes will always change (not every NPC will have multiattack etc.) so knowing this would be great. Thanks for your help once again! :mrgreen:
OOOHH RegEx....YOU BITTER-SWEET BEAST!!!

User avatar
aliasmask
RPTools Team
Posts: 9024
Joined: Tue Nov 10, 2009 6:11 pm
Location: Bay Area

Re: macro regex issue, end of line in multiline

Post by aliasmask »

I'm working on another parser with a similar situation. I'm not positive about the GM notes, but I think it only puts a LF instead of a CRLF. Despite how the data is separated, without the html formatting it's not super obvious where the actions are. So,

Code: Select all

Actions

Ability Name 1. Ability Description 1

Ability Name 2. Ability Description 2

Ability Description 2 second paragraph
Will be a problem. For my data I have to reformat it putting the description all on one line. If there is a second paragraph I use <br><br> to break it, but still no CRLF. I also use : instead of . for the "action" key word postfix.

So, for my example:

Code: Select all

Race: Lashunta
Summary: Charismatic and telepathic race of scholars with two subspecies: one tall and lean, the other short and muscular.
Ability Adjustments
   Korasha: +2 Chr, +2 Str, -2 Wis
   Damaya: +2 Chr, +2 Int, -2 Con
Hit Points: 4
Size: Medium
Type: humanoid
Subtype: lashunta
Subraces: korasha, damaya
Vision: normal
Move: 30
Source: Core
RACIAL TRAITS
Dimorphic: Korasha lashuntas are muscular but often brash and unobservant. Damaya lashuntas are typically clever and well-spoken but somewhat delicate.
Lashunta Magic: Lashuntas gain the following Spell-Like abilities 
   At will: daze, psychokinetic hand 
   1/day: detect thoughts
Limited Telepathy: Lashuntas can mentally communicate with any creatures within 30 feet with whom they share a language. Conversing telepathically with multiple creatures simultaneously is just as difficult as listening to multiple people speaking.
Student: Lashuntas love to learn, and they receive a +2 racial bonus to any two skills of their choice.

I have this:

Code: Select all

@@ @parser_Races
[H: keywords = json.append("","Race","Summary","Ability Adjustments","Hit Points","Size","Type","Subtype","Subraces","Vision","Move","Source")]
[H: keywords.init = json.append("","","","",0,"","","","","",0,"")]
[H: datablocks = json.append("","RACIAL TRAITS")]

<!-- initialize race data structure -->
[H: raceObj = "{}"]
[H, foreach(keyword,keywords): raceObj = json.set(raceObj,keyword,json.get(keywords.init,roll.count))]
[H, foreach(block,datablocks): raceObj = json.set(raceObj,block,"{}")]

<!-- put each line of raw data in to a json array. -->
[H: EOL = decode("%0A")]
[H: buttonIndex = getMacroIndexes("Races")]
[H: lines = json.fromList(getMacroCommand(buttonIndex),EOL)]

<!-- loop through lines building structured data -->

<!-- initialize variables for data parsing -->
[H: keyword.main = ""]
[H: keyword.block = ""]
[H: thisRace = ""]
[H: thisBlock = ""]

<!-- about formatting text and different types:

keyword.main: keyword.data

keyword.main
   keyword.indent: keyword.data
   
keyword.block
keyword.sub: keyword.data
   keyword.indent: keyword.data
   
-->

[H, foreach(line,lines), code: {
   <!-- get line data -->
   [H, if(json.isEmpty(line)), code: {
      [H: nextLine = 1]
   };{
      <!-- get keyword and keyword.data -->
      [H: id = strfind(line,"^([^:]+):*")]
      [H, if(getFindCount(id)): keyword = trim(getGroup(id,1,1)); keyword = ""]
      [H, if(! json.isEmpty(keyword) && listCount(line,":") >= 2): keyword.data = trim(listGet(line,1,":")); keyword.data = trim(line)]
      
      [H: keyword.isValid = json.contains(keywords,keyword)]
      [H: keyword.isBlock = json.contains(datablocks,keyword)]
      [H: keyword.hasIndent = startsWith(line,"   ")]
   }]
   
   <!-- keyword.main closes any block data -->
   [H, if( ! nextLine && keyword.isValid && ! json.isEmpty(keyword.block)), code: {
      [H, if(! json.isEmpty(thisBlock)): thisRace = json.set(thisRace,keyword.block,thisBlock)]
      [H: keyword.main = keyword]
      [H: keyword.block = ""]
      [H: thisBlock = ""]
   };{}]
   
   <!-- keyword.block closes any opened main data blocks -->
   [H, if( ! nextLine && keyword.isBlock && ! json.isEmpty(keyword.main)), code: {
      [H: keyword.main = ""]
      [H: keyword.block = keyword]
   };{}]
   
   
   <!-- check for new race -->
   [H, if(! nextLine && keyword == "Race"), code: {
      [H, if(! json.isEmpty(thisRace)): allRaces = json.set(allRaces,json.get(thisRace,"Race"),thisRace)]
      [H: thisRace = raceObj]
      [H: thisRace = json.set(thisRace,"Race",keyword.data)]
      [H: nextLine = 1]
   };{}]
   
   <!-- Enter simple keyword.data --> 
   [H, if(! nextLine && keyword.isValid && ! json.isEmpty(keyword.data)), code: {
      [H: thisRace = json.set(thisRace,keyword,keyword.data)]
      [H: nextLine = 1]
   };{}]
   
   <!-- keyword.main with indent -->
   [H, if(! nextLine &&
}]
 

!!
 
As you can see it's still a WIP, but the gist of it is I have certain keywords I separate by data with and block keywords to tell me the next "keys" (key:info) are blocked even though not on my main keyword list. I will also be using an indent as another form of blocked data to build my data.

I haven't figured it all out for myself, but I'll post an update when I do. I think GMNotes and putting the data in a macro will process the same way.

TL;DR - You'll have to reformat you input to get rid of 2nd paragraph, use <br><br> instead of CRLF and then you could use the EOL to get your different lines of abilities.

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: macro regex issue, end of line in multiline

Post by wolph42 »

many ways to rome and it appears we've all been there.

My method is similar to that of AM, difference is is that I first clean up everything (e.g. double spaces, punctuation, etc) then I search and replace the LF with an unambiguous string of characters e.g. "@#@" then I apply the regex in a similar manner as AM does.

SnR the LF can be done at least by using encode decode (like am does in his example)

User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

Re: macro regex issue, end of line in multiline

Post by Sereptus »

:shock: Wow!! I was hoping you'd reply with something like . . ." You numbskull, just use '\\EOL'!"

I'm going to be a couple weeks figuring all that out but I see now the value in what you're doing by formatting the text.

I was wondering something else though :oops: , when I copy/paste the statblock into the RegExr site clearly there is two carriage returns between each line, wouldn't the encode/decode options work in separating these?
Spoiler
regex_capture.jpg
regex_capture.jpg (78.47 KiB) Viewed 1253 times
Sorry about the huge image but it makes it a little clearer. Anyway, wouldn't "something" like replacing the input text "<CR>" "\\r" or "%0D" with "XYZ" at the beginning of the importer code work? Then I could find the carriage returns with \XYZ \xyz or some other iteration of that? Ugh! I have the feeling that won't work either without changing the way Maptool handles input()! :roll:



EDIT: I'll have to assume that won't work it's because of what you said earlier, "there are no CRLF because the info is entered via input() text field which filters out those characters."
OOOHH RegEx....YOU BITTER-SWEET BEAST!!!

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: macro regex issue, end of line in multiline

Post by wolph42 »

im wondering though if thre is no CR and only LF then "\\r" should work, did you try that? (note the \\ as that is required for the maptool parser to parse it (it will eat one \ leaving: \r of the initial \\r. Note that you need to escape ALL escapes, so if you're looking for e.g. \ you need: "\\\\"). Try it and let me know.

User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

Re: macro regex issue, end of line in multiline

Post by Sereptus »

wolph42 wrote:im wondering though if thre is no CR and only LF then "\\r" should work, did you try that? (note the \\ as that is required for the maptool parser to parse it (it will eat one \ leaving: \r of the initial \\r. Note that you need to escape ALL escapes, so if you're looking for e.g. \ you need: "\\\\"). Try it and let me know.
Tried it and didn't work. :cry:

Thanks though, sure appreciating all the input! :mrgreen:
OOOHH RegEx....YOU BITTER-SWEET BEAST!!!


User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

Re: macro regex issue, end of line in multiline

Post by Sereptus »

wolph42 wrote:bummer...and while were experimenting: \\r\\n ?
Nope. :| and I tried several different iterations of that. I realized afterwards that I was pulling the weapon names off flawlessly and since Multiattack came directly before the first weapon (which there always is a weapon) I even tried putting \\WeaponName and \WeaponName as the end of the capture group, but alas I was thwarted once again! I've tried decode and encode combinations until I was dizzy and still a 0 where the getFindCount is. :oops:

In your opinion, what combination of decode/encode might work? I mean, the input() HAS to recognize something in the form of carriage return, indent, tab, or start of new line doesn't it? or does it just strip all that away?

EDIT: Yeah, after several test runs on a new input macro the input is stripped of all of that. Maybe we could petition Az to put it back in? :P
OOOHH RegEx....YOU BITTER-SWEET BEAST!!!

Post Reply

Return to “Macros”