Extract data from a block of text to populate variables.

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

Shadow Wizard
Giant
Posts: 182
Joined: Mon Apr 11, 2011 8:11 pm

Extract data from a block of text to populate variables.

Post by Shadow Wizard »

I am trying to build a macro so I can paste the monsters stat block in, and it will extract the information and add it to the appropriate variable. But I don't know really where to start. One thing I was thinking of was something that could search for 2 specific strings, and return what is between them? Such as (see stat block snippet below for example references)
For example, find the the strings " Str " and ", Dex" and return "15".
And find the strings "Skills: " and "<br>" (Or whatever the "Next line" strings is) and return "Climb +3, Hide +4, Listen +4, Move Silently +6, Spot +4"

Or perhaps go line by line, and return specific parts of that line. Such as in the example below, select line 4, and return everything but the left 6 characters. This would return "Alertness, Weapon Focus (morningstar)" However that example will only work with line 4, as I need to strip specific information for each individual stat, for example, from line 2.

Of course if there is a better way I am open to suggestions. I just thought copy and paste stat block would be the best way to do it.


Stat block snippet (for examples):

Saves: Fort +2, Ref +4, Will +1
Abilities: Str 15, Dex 12, Con 13, Int 10, Wis 10, Cha 9
Skills: Climb +3, Hide +4, Listen +4, Move Silently +6, Spot +4
Feats: Alertness, Weapon Focus (morningstar)

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

There's no easy single answer, but typically you'll use regex in a Wiki: strfind() to return results. You'll have to decide where your input data will reside and go from there. input() is one method, but it doesn't save <CR><LF> characters. Putting data in to a macro then parsing that is another method. That's best for a lot of data. Just putting it directly in to the code in a string is another way.

Code: Select all

[H: input = "Saves: Fort +2, Ref +4, Will +1
Abilities: Str 15, Dex 12, Con 13, Int 10, Wis 10, Cha 9
Skills: Climb +3, Hide +4, Listen +4, Move Silently +6, Spot +4
Feats: Alertness, Weapon Focus (morningstar)"]
Once you have the data saved somewhere, then you can parse it by line, or by keywords.

Code: Select all

[H: id = strfind(input,"Saves: Fort ([+-]*[0-9]+), Ref ([+-]*[0-9]+), Will ([+-]*[0-9]+)")]
[H: fortSave = getGroup(id,1,1)]
[H: refSave = getGroup(id,1,2)]
[H: willSave = getGroup(id,1,3)]
There are other ways to do this (with list functions), but this way is pretty universal.

Shadow Wizard
Giant
Posts: 182
Joined: Mon Apr 11, 2011 8:11 pm

Re: Extract data from a block of text to populate variables.

Post by Shadow Wizard »

This is working wonderfully to extract the numbers! I have been able to modify it to do so (so far) without issue! Thank you.

Now, that about a string, when I don't know the length? For example, what would I use to get it to return the list of skills, with there mode, in one line? I want it to return this: "Climb +3, Hide +4, Listen +4, Move Silently +6, Spot +4" and store it in the Skills property.

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

Shadow Wizard wrote:
Mon Sep 26, 2022 11:58 am
This is working wonderfully to extract the numbers! I have been able to modify it to do so (so far) without issue! Thank you.

Now, that about a string, when I don't know the length? For example, what would I use to get it to return the list of skills, with there mode, in one line? I want it to return this: "Climb +3, Hide +4, Listen +4, Move Silently +6, Spot +4" and store it in the Skills property.
Other tricks can be used. With the above input you could do something like this:

Code: Select all

<!-- convert to json. change space to = and , to ; -->
[H: obj = replace(input," ([+-])","=\\$1")]
[H: obj = replace(obj,",",";")]
[H: obj = json.fromStrProp(obj)]
[H, foreach(skill,obj), code: {
   [H: setProperty(lower(replace(skill," ","")), number(json.get(obj,skill)))]
}]
This will set properties "climb,hide,listen,movesilently,spot" to the values.

Shadow Wizard
Giant
Posts: 182
Joined: Mon Apr 11, 2011 8:11 pm

Re: Extract data from a block of text to populate variables.

Post by Shadow Wizard »

Wow, some of this stuff gets hard to follow.. But I think I manage to get the basic idea of it.
The problem is 2 fold however. First and primarily, How do I get the single line "Climb +3, Hide +4, Listen +4, Move Silently +6, Spot +4" into the obj variable? I basically need a function that will search for the line that starts with "Skills:" and to place that entire line, minus the "Skills:" part into a variable (In this case, obj.) Once I know how to do that, I think I can write the rest (Or almost all of the rest anyway.)
The second problem really isn't that relevant, as solving the first problem will solve the second one, I don't have separate variables for Climb Hide Etc. I have a single variable called "Skills." Once I know how to get it to search for the line that starts with "Skills:" and put everything else in that line into a variable all is well.

p.s. Even if I did set a different variable for every skill, that would only solve the problems with that one line. I would still need to do the same with the Feats: line, and many other lines that are in the stat block (that I obviously didn't post here)

And thank you very much for the assistance.

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

Yeah, it will get complicated using regex. You should read up on "regex java" and there are some online testers (like regex101.com) to help you figure stuff out. Give it a shot and I'll help you out later.

Shadow Wizard
Giant
Posts: 182
Joined: Mon Apr 11, 2011 8:11 pm

Re: Extract data from a block of text to populate variables.

Post by Shadow Wizard »

I have looked at it a bit yesterday , and managed to do some edits to correctly parse other lines correctly such as:
Challenge Rating: 1/4
I have made a line that will correctly parse both single and double digits as well as fractions, and represent them as there fraction and not a decimal. So I am trying to learn. I have even managed to get it to correctly parse lines with words instead of numbers.
Treasure: Standard
The issue I have is when there are multiple "Words"
Treasure: Double standard
I don't know how to tell the system "There might be one word, or 2, or 3 or more. "
I just wanted to mention this so you know I am not just asking you to do everything (I know I hate that when I try and help people and they won't even try anything!)
I will take a look at it again, however am I a bit concerned due to learning disabilities.
I do have a couple of ideas how to accomplish this (I am very good at thinking outside the box) I would like your opinion on. I will be able to test one later today, but not the other
First off, and please correct me if I am wrong, strfind and getGroup seems to divide everything into "words" for a lack of a better term.
So, to my ideas:

1) So is there a way to find the strings "Skills: " and "Feats: " and just take everything in between them?
This is the one I don't know how to do.

2) is a bit of a work around (However I think I can do this one, and will try later)
Find and replace all the spaces " " with "QQ" As QQ will never appear, and can be removed later. Do that in the whole stat block.
This will change the Skills line line (as well as change every other line to something similar) to: "Skills:QQClimbQQ+3,QQHideQQ+4,QQListenQQ+4,QQMoveQQSilentlyQQ+6,QQSpotQQ+4"
Now find and replace ":QQ" with ": " in the whole stat block to making the new line (and other lines similar to) as follows: ""Skills: ClimbQQ+3,QQHideQQ+4,QQListenQQ+4,QQMoveQQSilentlyQQ+6,QQSpotQQ+4"
Now there are only 2 "words" on the "Skills:" line. So now I search for "Skills" extract the second "word" of the line which would return this: "ClimbQQ+3,QQHideQQ+4,QQListenQQ+4,QQMoveQQSilentlyQQ+6,QQSpotQQ+4"
Finally replace the "QQ" with " " again and store it in the appropriate property.

I would love some input before I get started trying to test out the second idea, but either way I am gonna get started trying it out in a few hours.

EDIT:

Well, I managed to get it to work with the QQ trick! It is parsing ALMOST all of the data, however I do need to pull specific lines for the rest of the parse.

The first line (as seen below) is always the creature name.
The second line always contains information I need to extract and out in 2 different places, namely Size, and Type.
So, could I get some help selecting specific line numbers? Unless you have a better way?

Stat block I am refernceing:
Orc, 1st-Level Warrior
Medium Humanoid (Orc)
Hit Dice: 1d8+1 (5 hp)
Initiative: +0
Speed: 30 ft. (6 squares)

Additional edit/note:
I have been working on and off for several hours, and I just cant figure out how to parse that second line. Nothing seems to work unless I prefix the line with something, and then I still can only parse the first word, or all of it. I can't put the first word (Meduim) into the property, and the rest of the line (Humanoid (Orc)) into another.
And since I can't parse that second line, I obviously can't parse the first.

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

There a lot of directions you can go here. First step is deciding how you get your data in to MapTool. One method I use is to create a big file with all my info with a specific format. Looks something like this.

Code: Select all

keyword:data
blockKeyword
data1
data2
keyword:data
blockKeyword
key1:data1
key2:data2
All your data is put in to macro directly and read from there. This way it saves your CR characters which makes it easier to parse the line. This function here is what I use to get the data in to a data structure. From there I can parse out the individual lines in another macro.
Spoiler

Code: Select all

<!-- loadData(dbName,keywordList,blockedList): records 
   dbName - name of macro that holds database
   keywordList - List of valid keywords, other keywords are blocked under the most recent valid keyword or blocked keyword
   blockedList - same as keyword but has a following list of other keywords and data that arent standardized
   records - An array of objects with the keywords and block lists
   
AM 9-24-21   
   Convert text from a database in to a more manageable json records. Simple Mode. I call it "log" format.
-->

[H: dbName = arg(0)]
[H: keywordList = arg(1)]
[H: blockedList = arg(2)]

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

<!-- initialize data structure -->
[H: records = "[]"]
[H: new.obj = "{}"]
[H: obj = "{}"]
[H, foreach(keyword,keywordList): new.obj = json.set(new.obj,keyword,"")]
[H, foreach(block,blockedList): new.obj = json.set(new.obj,block,"[]")]

[H: firstKeyword = json.get(keywordList,0)]
[H: blockName = ""]

<!-- loop through lines building structured data -->
[H, foreach(line,lines), code: {
   <!-- get keyword and keyword.data -->
   [H: id = strfind(line,"^([a-zA-Z][^:]*):(.*)")]
   [H, if(getFindCount(id)): keyword = trim(getGroup(id,1,1)); keyword = ""]
   [H, if(getFindCount(id)): value = trim(getGroup(id,1,2)); value = ""]
   [H: data = trim(line)]
   [H: isKey = json.contains(keywordList,keyword)]
   [H: isBlock = json.contains(blockedList,data)]

   <!-- check for new record -->
   [H, if(keyword == firstKeyword), code: {
      [H, if(! json.isEmpty(obj)): records = json.append(records,obj)]
      [H: obj = new.obj]
   };{}]
   
   <!-- set standard keyword -->
   [H, if(isKey), code: {
      [H: blockName = ""]
      [H: obj = json.set(obj,keyword,value)]
   };{}]
   
   <!-- set blocked keyword -->
   [H, if(isBlock): blockName = data]
   
   [H, if(! isBlock && ! isKey && ! json.isEmpty(blockName) && ! json.isEmpty(data)), code: {
      [H: obj = json.path.add(obj,strformat('\$.["%{blockName}"]'),json.set("{}","key",keyword,"value",value,"data",string(data)))]
   };{}]
}]

[H, if(! json.isEmpty(obj)): records = json.append(records,obj)]

[H: macro.return = records]
Example "log" file.
Spoiler

Code: Select all

Stat: Strength
Abilities
Increase the success to initiate a grapple during the encounter by 1 step and the affected target by 1 size category per creature. Note, does not apply to maintain grapple nor to re-grapple on the same target.
Succeed at any movement Athletics check (Climb,Jump,Swim) for the encounter or 10 minutes.
Increase strike damage dice by one for encounter for a single weapon.
Aligned
Increase the success to initiate a grapple during the encounter by 2 steps and the affected target by 2 size category per creature. Note, does not apply to maintain grapple nor to re-grapple on the same target.
Crit Succeed at any movement Athletics check (Climb,Jump,Swim) for the encounter or 10 minutes.
Increase strike damage dice by two for encounter for a single weapon.
Misaligned: Enfeebled 1

Stat: Dexterity
Abilities
Choose to start initiative in an encounter. Any opponent is considered flat-footed against you. 1 round.
Increase AC for one encounter. +2 AC status
Increased movement for one encounter. +10 Movement
Aligned
Choose to start initiative in an encounter. Any opponent is considered flat-footed against you. 2 rounds.
Increase AC for one encounter. +3 AC status
Increased movement for one encounter. +15 Movement
Misaligned: Clumsy 1

Stat: Constitution
Abilities
Increase the success of a Fortitude save by 1 step for a specific effect.
Gain physical damage reduction 5 for encounter.
Gain fast healing 5 for the encounter and you're immune to wounds for an encounter.
Aligned
Increase the success of a Fortitude save by 2 steps for a specific effect.
Gain physical damage reduction 10 for encounter.
Gain fast healing 10 for the encounter and you're immune to wounds for an encounter.
Misaligned: Drained 1
Example Data Structure Returned
Spoiler

Code: Select all

[
    {
    "Stat": "Strength",
    "Misaligned": "Enfeebled 1",
    "Abilities":     [
            {
        "key": "",
        "value": "",
        "data": "Increase the success to initiate a grapple during the encounter by 1 step and the affected target by 1 size category per creature. Note, does not apply to maintain grapple nor to re-grapple on the same target."
      },
            {
        "key": "",
        "value": "",
        "data": "Succeed at any movement Athletics check (Climb,Jump,Swim) for the encounter or 10 minutes."
      },
            {
        "key": "",
        "value": "",
        "data": "Increase strike damage dice by one for encounter for a single weapon."
      }
    ],
    "Aligned":     [
            {
        "key": "",
        "value": "",
        "data": "Increase the success to initiate a grapple during the encounter by 2 steps and the affected target by 2 size category per creature. Note, does not apply to maintain grapple nor to re-grapple on the same target."
      },
            {
        "key": "",
        "value": "",
        "data": "Crit Succeed at any movement Athletics check (Climb,Jump,Swim) for the encounter or 10 minutes."
      },
            {
        "key": "",
        "value": "",
        "data": "Increase strike damage dice by two for encounter for a single weapon."
      }
    ]
  },
    {
    "Stat": "Dexterity",
    "Misaligned": "Clumsy 1",
    "Abilities":     [
            {
        "key": "",
        "value": "",
        "data": "Choose to start initiative in an encounter. Any opponent is considered flat-footed against you. 1 round."
      },
            {
        "key": "",
        "value": "",
        "data": "Increase AC for one encounter. +2 AC status"
      },
            {
        "key": "",
        "value": "",
        "data": "Increased movement for one encounter. +10 Movement"
      }
    ],
    "Aligned":     [
            {
        "key": "",
        "value": "",
        "data": "Choose to start initiative in an encounter. Any opponent is considered flat-footed against you. 2 rounds."
      },
            {
        "key": "",
        "value": "",
        "data": "Increase AC for one encounter. +3 AC status"
      },
            {
        "key": "",
        "value": "",
        "data": "Increased movement for one encounter. +15 Movement"
      }
    ]
  },
    {
    "Stat": "Constitution",
    "Misaligned": "Drained 1",
    "Abilities":     [
            {
        "key": "",
        "value": "",
        "data": "Increase the success of a Fortitude save by 1 step for a specific effect."
      },
            {
        "key": "",
        "value": "",
        "data": "Gain physical damage reduction 5 for encounter."
      },
            {
        "key": "",
        "value": "",
        "data": "Gain fast healing 5 for the encounter and you're immune to wounds for an encounter."
      }
    ],
    "Aligned":     [
            {
        "key": "",
        "value": "",
        "data": "Increase the success of a Fortitude save by 2 steps for a specific effect."
      },
            {
        "key": "",
        "value": "",
        "data": "Gain physical damage reduction 10 for encounter."
      },
            {
        "key": "",
        "value": "",
        "data": "Gain fast healing 10 for the encounter and you're immune to wounds for an encounter."
      }
    ]
  },
  ...
  ]
Example Parser to convert
Spoiler

Code: Select all

<!-- parse_harrow() -->

[H: dbName = "harrow.log"]
[H: keywordList = json.append("","Stat","Misaligned")]
[H: blockedList = json.append("","Abilities","Aligned")]

[H: harrowData = pf2.db.loadData(dbName,keywordList,blockedList)]

<!-- convert import data to something more useful -->
[H: harrowObj = "{}"]
[H, foreach(record,harrowData), code: {
   [H: stat = json.get(record,"Stat")]
   [H: powers = "[]"]
   [H: aligned = "[]"]
   [H, foreach(data,json.get(record,"Abilities")): powers = json.append(powers,json.get(data,"data"))]
   [H, foreach(data,json.get(record,"Aligned")): aligned = json.append(aligned,json.get(data,"data"))]
   [H: obj = json.set("{}","stat",stat,"powers",powers,"aligned",aligned,"misaligned",json.get(record,"Misaligned"))]
   [H: harrowObj = json.set(harrowObj,stat,obj)]
}]
[dialog("D"):{<pre>[R: json.indent(replace(harrowObj,"<","&lt;"))]</pre>}]
<!-- save to main lib token -->
<!-- H: setLibProperty("harrowData",harrowObj,"lib:PF2")] -->
Example conversion
Spoiler

Code: Select all

{
  "Strength":   {
    "stat": "Strength",
    "powers":     [
      "Increase the success to initiate a grapple during the encounter by 1 step and the affected target by 1 size category per creature. Note, does not apply to maintain grapple nor to re-grapple on the same target.",
      "Succeed at any movement Athletics check (Climb,Jump,Swim) for the encounter or 10 minutes.",
      "Increase strike damage dice by one for encounter for a single weapon."
    ],
    "aligned":     [
      "Increase the success to initiate a grapple during the encounter by 2 steps and the affected target by 2 size category per creature. Note, does not apply to maintain grapple nor to re-grapple on the same target.",
      "Crit Succeed at any movement Athletics check (Climb,Jump,Swim) for the encounter or 10 minutes.",
      "Increase strike damage dice by two for encounter for a single weapon."
    ],
    "misaligned": "Enfeebled 1"
  },
  "Dexterity":   {
    "stat": "Dexterity",
    "powers":     [
      "Choose to start initiative in an encounter. Any opponent is considered flat-footed against you. 1 round.",
      "Increase AC for one encounter. +2 AC status",
      "Increased movement for one encounter. +10 Movement"
    ],
    "aligned":     [
      "Choose to start initiative in an encounter. Any opponent is considered flat-footed against you. 2 rounds.",
      "Increase AC for one encounter. +3 AC status",
      "Increased movement for one encounter. +15 Movement"
    ],
    "misaligned": "Clumsy 1"
  },
  "Constitution":   {
    "stat": "Constitution",
    "powers":     [
      "Increase the success of a Fortitude save by 1 step for a specific effect.",
      "Gain physical damage reduction 5 for encounter.",
      "Gain fast healing 5 for the encounter and you're immune to wounds for an encounter."
    ],
    "aligned":     [
      "Increase the success of a Fortitude save by 2 steps for a specific effect.",
      "Gain physical damage reduction 10 for encounter.",
      "Gain fast healing 10 for the encounter and you're immune to wounds for an encounter."
    ],
    "misaligned": "Drained 1"
  },
  ...
This method requires you to do a little editing to source data to get it in to the right format.

Another method is converting data from a CSV file. There is likely a monster CSV file somewhere out there.

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

The most difficult way is trying to parse the raw data and converting it directly to your data. I recently done this converting the html from a website in to my own spell data base. It took a lot of prep work to do, just to get the data in to MT, but once there after using a csv import, raw data import and 11 UDFs later I got the very basics.

Here's an example of just getting the Attributes

Code: Select all

<!-- getAttributes(content): attributes -->
[H: content = arg(0)]

[H: id = strfind(content,'<br[ /]*>(.*?)<hr[ /]*>')]
[H: body = getGroup(id,1,1)]
[H: id = strfind(body,'<b>(.*?)</b>(.+?)(?=<b>|\$)')]

[H: default = json.set("{}",
   "Source","",
   "PFS Note","",
   "Access","",
   "Bloodlines","",
   "Deities","",
   "Domain","",
   "Lesson","",
   "Mystery","",
   "Patron Themes","",
   "Spell List","",
   "Traditions","",
   "Cast","",
   "Cost","",
   "Trigger","",
   "Requirements","",
   "Range","",    "Area","",   "Targets","",
   "Saving Throw","",    "Duration",""
)] 

[H: replaceKeys = json.set("{}",
  "Deity","Deities",
  "Bloodline","Bloodlines",
  "Patron Theme","Patron Themes"
)]

[H: attributes = default]
[H, c(getFindCount(id)), code: {
   [H: index = roll.count + 1]
   [H: key = trim(getGroup(id,index,1))]
   [H: altKey = json.get(replaceKeys,key)]
   [H, if(! json.isEmpty(altKey)): key = altKey]
   [H: value = trim(getGroup(id,index,2))]
   [H: attributes = json.set(attributes,key,value)]
}]

[H: macro.return = attributes]
This is a nice a neat way of doing it. The PF2 Monster token import tool in the 3.5/Pathfinder Framework is an example of how I wouldn't do it. It works great and with added comments isn't terrible to read, but man, what a monster bit of code that is.

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

Here's a fairly simple way of handling the data.

Code: Select all

[H: rawData = "Orc, 1st-Level Warrior
Medium Humanoid (Orc)
Hit Dice: 1d8+1 (5 hp)
Initiative: +0
Speed: 30 ft. (6 squares)"]

[H: default = json.set("{}",
   "name","monster",
   "level","0",
   "className","",
   "size","",
   "race_type","",
   "race","",
   "hitDice","",
   "hp",0,
   "initiative",0,
   "speed",30
)]

[H: EOL = "%0A"]
[H: LF = "%0D"]

[H: rawData = replace(encode(rawData),LF,"")]
[H: lines = decode(json.fromList(rawData,EOL))]

[H: name = listGet(json.get(lines,0),0)]
[H: level = replace(json.get(lines,0),"[^0-9]","")]

[H: creature = json.set(default,"name",name,"level",level)]

[dialog("D"):{<pre>[R: json.indent(lines)]

[R: json.indent(creature)]</pre>}]

[H: regex = "^([^,]*?), ([a-zA-Z0-9/-]+) (.*)"]
[H: line = json.get(lines,0)]
[H: id = strfind(line,regex)]
[H: name = getGroup(id,1,1)]
[H: level = getGroup(id,1,2)]
[H: className = getGroup(id,1,3)]

[H: creature = json.set(default,"name",name,"level",level,"className",className)]
[dialog("D1"):{<pre>[R: json.indent(creature)]</pre>}]
How you parse out the data from here will likely require some tweaks because you have to account for all variations. I include 2 ways of doing this in D and D1 frame outputs.

Shadow Wizard
Giant
Posts: 182
Joined: Mon Apr 11, 2011 8:11 pm

Re: Extract data from a block of text to populate variables.

Post by Shadow Wizard »

So, I have looked at and tries to study this code both last night and this morning, and unfortunately it is beyond my ability to comprehend (My only programming knowledge is from back in the days with my TRS80) which means it is beyond my ability to modify.
Are you saying there really isn't a simply way to just say "Please take the entire first line, and put it in a specific variable (or property)" and "please take the entire second line and put in into a different variable."
I have fought endless with this line:
[H: id = strfind(input,"([Tiny|Small|Medium|Large](.*)+)")]
and just can't get it to work. It simply refuses to compare the first word. If I prefix the line with something "a: " for example, and add that prefix to the line above, I can get it to parse either the first word, or the whole line (After the "a: ") but just can't get it to parse the first word, and then the rest of the line. And besides, I don't want to have to prefix the line.

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

My last post does all the hard work for you. For the second line I would do this

Code: Select all

[H: line2 = json.get(lines,1)]
[H: regex = "^([a-zA-Z]+?) ([^(]+)[(]([^)]+)[)]"]
[H: id = strfind(line2,regex)]
[H: size = getGroup(id,1,1)]
[H: race_type = getGroup(id,1,2)]
[H: race = getGroup(id,1,3)]
I'll explain the regex part (again, I recommend reading up on this).

Code: Select all

part 1 - size
^ - start of a string
(...) - capture group. Goes in order, left to right, 1 to 3
[...] - character specific options. a-z means any character from a to z.
+ - select more than 1 character, but at least 1.
? - don't be greedy. If you find matching condition after the ? then stop match
So, "^([a-zA-Z]+?) " means, starting from start of string capture the next group of characters from A to Z. It'll stop capture at the space.
This will give you the size.

Code: Select all

part 2 - race type, ie humanoid
[^(]+ - capture the next group of characters that is not the (.
This kind of assumes that the ( will be in the string. If it's not always there, then you'll have to add an "or end of line" condition. That would look something like this: (([^(]+)|\$) wrapping capture group in another capture group.

Code: Select all

part 3 - race ie Orc
This looks a bit confusing, but I'm using ( as a capture and [(] as the character.
[(] ( [^)]+ ) [)] - character "(" followed by capture group of any character that's not a ")" and ends in character ")".
Now if this doesn't exist the whole match could fail, so doing as above we can wrap it with an "or end of line" condition. That way it will return blank if it doesn't exist.
Since we wrapped the previous condition, to set this value the match will be 4 and not 3.
new regex = ""^([a-zA-Z]+?) (([^(]+)|\$)([(]([^)]+)[)])|\$)"

Shadow Wizard
Giant
Posts: 182
Joined: Mon Apr 11, 2011 8:11 pm

Re: Extract data from a block of text to populate variables.

Post by Shadow Wizard »

I just wanted to touch base and thank you for the reply and help. I likely won't be able to look at it until next week some time, but I hope with your post I can try and iron things out to parse the last 5 bits of information.

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

Re: Extract data from a block of text to populate variables.

Post by aliasmask »

kk. Yeah, no easy solutions for parsing other peoples data.

Shadow Wizard
Giant
Posts: 182
Joined: Mon Apr 11, 2011 8:11 pm

Re: Extract data from a block of text to populate variables.

Post by Shadow Wizard »

I am sorry, I am really not getting this. So first off I will have to apologize, my learning disabilities can make showing me things that should be very simple be very frustrating for some people.
I have put this:

Code: Select all

[H: rawData = "Orc, 1st-Level Warrior
Medium Humanoid (Orc)
Hit Dice: 1d8+1 (5 hp)
Initiative: +0
Speed: 30 ft. (6 squares)"]

[H: default = json.set("{}",
   "name","monster",
   "level","0",
   "className","",
   "size","",
   "race_type","",
   "race","",
   "hitDice","",
   "hp",0,
   "initiative",0,
   "speed",30
)]

[H: EOL = "%0A"]
[H: LF = "%0D"]

[H: rawData = replace(encode(rawData),LF,"")]
[H: lines = decode(json.fromList(rawData,EOL))]

[H: name = listGet(json.get(lines,0),0)]
[H: level = replace(json.get(lines,0),"[^0-9]","")]

[H: creature = json.set(default,"name",name,"level",level)]

[dialog("D"):{<pre>[R: json.indent(lines)]

[R: json.indent(creature)]</pre>}]

[H: regex = "^([^,]*?), ([a-zA-Z0-9/-]+) (.*)"]
[H: line = json.get(lines,0)]
[H: id = strfind(line,regex)]
[H: name = getGroup(id,1,1)]
[H: level = getGroup(id,1,2)]
[H: className = getGroup(id,1,3)]

[H: creature = json.set(default,"name",name,"level",level,"className",className)]
[dialog("D1"):{<pre>[R: json.indent(creature)]</pre>}]
into a macro all by itself, and all it does it pop up boxes on my screen, and doesn't seem to populate any of the properties. (that's an exact cut and paste of the code in your post, just so you don't need to go though it and see that I didn't change anything)

Is there a way we can go one step at a time? (And, again I apologize, but I think its gonna be the only way I can learn)
Can you show me how to take the first line, namely "Orc, 1st-Level Warrior" and put into a variable called line1 ? I assume I can likely discover how to put line 2 into another variable by myself. Once I have those lines into variables I may be able to extract the data I need.

Another thing I am having issues with is how to do something with regex. I am looking for an "Everything up until" expression. So for example if I have the following line:
Attack: Claw +15 melee (1d6+9)
I want an expression that will return everything before the + (Minus the word "Attack: ") What i have so far is below. The ????? denote the area I am having issues with and don't represent the expression:
[H: id = strfind(input,"Attack: ([???????])]

And finally an "Anything including the spaces" I assumed the standard wildcard "*" would work, but it doesn't seem to... Something that would parse the following line:
Attack: Really Big Claw +15 melee (1d6+9)
in this kind of way:
[H: id = strfind(input,"Attack: ([*]*[+-]*[0-9]+")]
so getGroup(id,1,1) would equal "Really Big Claw" and getGroup(id,1,2) would equal 15

Post Reply

Return to “Macros”