Using AppleScript to find and set an AS variable collects TMI (too much information)

67 views
Skip to first unread message

e2o

unread,
Aug 13, 2023, 5:33:41 PM8/13/23
to BBEdit Talk
Using AppleScript to find and set an AS variable collects TMI (too much information)

Hello!

I create many text documents in BBEdit every day, and I have to extract and send these variables over to Keyboard Maestro to paste in a web form. These documents start like this:

+ - - - - + - - - - + - - - - +
08:30-11:30 UWA

:: Item one
- the associated notes

:: Item two
- etc
+ - - - - + - - - - + - - - - +

I need to pull out variables:

StartTime: 08:30
EndTime: 11:30
ClientCode: UWA

I've been working with the following script:

+ - - - - + - - - - + - - - - +
set StartTime to "00:00"
set EndTime to "00:00"
set ClientCode to "AAA"

tell application "BBEdit"
set StartTime to find "(\\A)([0-9]{2})(\\:)([0-9]{2})" searching in text document 1 options {search mode:grep, wrap around:true} with selecting match
set EndTime to find "([0-9]{2})(\\:)([0-9]{2})" searching in text document 1 options {search mode:grep, wrap around:false} with selecting match
set ClientCode to find "[A-Z]{3}" searching in text document 1 options {search mode:grep, wrap around:false} with selecting match
end tell

tell application "Keyboard Maestro Engine"
setvariable TicketTimeEntryBegin to StartTime
end tell
+ - - - - + - - - - + - - - - +

Running it, I keep getting the error:
"Can’t make characters 1 thru 5 of text document id 220 of application "BBEdit" into the expected type."

Script Debugger tells me that variable StartTime has these three properties:
found: true
found object: characters 1 thru 5 of text document id 220
found text: "08:30"

So I'm getting the right found text "08:30" (and I'm getting the correct EndTime and Client Code), but there is a type mismatch when trying to get 08:30 over to a variable TicketTimeEntryBegin in Keyboard Maestro.

Now, when I use the following Execute AppleScript step in Keyboard Maestro to try to see what's going on:

+ - - - - + - - - - + - - - - +
tell application "BBEdit"
find "(\\A)([0-9]{2})(\\:)([0-9]{2})" searching in text document 1 options {search mode:grep, wrap around:true} with selecting match
end tell

And Keybard Maestro action: Save to variable: TicketTimeEntryBegin
+ - - - - + - - - - + - - - - +

the variable TicketTimeEntryBegin in Keyboard Maestro now contains:

found:true, found object:characters 1 thru 5 of text document id 220, found text:08:30

So it is getting the three properties of the variable mashed together.

How do I just get the found text 08:30, and not the rest?

Thanks!

- eric

Rick Gordon

unread,
Aug 14, 2023, 2:23:11 AM8/14/23
to bbe...@googlegroups.com
I haven't worked with Keyboard Maestro, but what about *found text of
TicketTimeEntryBegin*?

On August 13, 2023 at 11:20:24 PM [-0700], E2o wrote in an email
entitled "Using AppleScript to find and set an AS variable collects TMI (too
much information)":
> found text:08:30

___________________________________________
RICK GORDON
EMERALD VALLEY GRAPHICS AND CONSULTING
___________________________________________
WWW: http://www.shelterpub.com

jj

unread,
Aug 14, 2023, 10:59:45 AM8/14/23
to BBEdit Talk
Hi Eric,

Here is an example of how to get the values captured by a regex.

tell application "BBEdit"

set vDocument to first text document of first window

set vTimeRegex to "(?:[01][0-9]|2[0-3]):[0-5][0-9]"

set vRegex to "^(" & vTimeRegex & ")-(" & vTimeRegex & ")\\h+([A-Z]{3})"

set vOptions to {search mode:grep, starting at top:true, wrap around:false, returning results:true}

set vResult to find vRegex searching in vDocument options vOptions

if vResult's found then

repeat with vMatch in found matches of vResult

log vMatch

set vOptions to {search mode:grep, starting at top:true, wrap around:false, returning results:false}

set vTag to characters (vMatch's start_offset) thru (vMatch's end_offset) of vDocument

set vTagMatch to find vRegex searching in vTag options vOptions

if vTagMatch's found then

set vStartTime to grep substitution of "\\1"

set vEndTime to grep substitution of "\\2"

set vClientCode to grep substitution of "\\3"

log {vStartTime:vStartTime, vEndTime:vEndTime, vClientCode:vClientCode}

end if

end repeat

end if

end tell


HTH,

Jean Jourdain

e2o

unread,
Aug 14, 2023, 12:19:57 PM8/14/23
to BBEdit Talk
<jaw drops> Wow, this helps SO much! I'm redoing a bunch of scripts for my daily workflow, and pulling text out of BBEdit is the core of everything. I've been relying on moving the cursor around and copying using Keyboard Maestro, but I'm just starting to overhaul these with faster and more predictable AppleScript actions. I've got one simple one done, and it is mind-blowingly better. Now I have to work on the harder ones. This will help a ton.

I might pick your brain when I get to doing some time arithmetic with varying number of time entry lines!

THANK YOU!

e2o

unread,
Aug 17, 2023, 11:04:20 PM8/17/23
to BBEdit Talk
JJ,

I've been going over this script you sent trying to wrap my head around it. I haven't been able to get through it completely "plain-english" in my head yet. Could you briefly elaborate? I love the way the variables are set to build the find. But I'm not clear on the need for repeat statement and the overall strategy. All I know is that if I could grok this script - which does things I find myself needing a LOT - then it could open up a whole new world.
Could you shed a bit of light for an old dog learning new tricks?

Thanks!

- eric

On Monday, August 14, 2023 at 7:59:45 AM UTC-7 jj wrote:

e2o

unread,
Aug 17, 2023, 11:23:17 PM8/17/23
to BBEdit Talk
I'm also struggling with the expression:

(?:[01][0-9]|2[0-3]):[0-5][0-9]

e2o

unread,
Aug 17, 2023, 11:54:58 PM8/17/23
to BBEdit Talk
phew! work my way bit-by-bit through the expression (?:[01][0-9]|2[0-3]):[0-5][0-9]
and got that sorted.

jj

unread,
Aug 19, 2023, 6:20:30 AM8/19/23
to BBEdit Talk
Hi Eric,

As requested, some additional comments.

1. The time regular expression commented

    (?x)                                        (?# Allow comments and ignore whitespace in regex.)
    (?:                                         (?# Non-capturing OR opening parenthesis.)
        [01][0-9]                               (?# Double digit from 00 to 19.)
    |                                           (?# or)
        2[0-3]                                  (?# Double digit from 20 to 23.)
    )                                           (?# Non-capturing OR closing parenthesis.)
    :                                           (?# A colon.)
    [0-5][0-9]                                  (?# Double digit from 00 to 59.)
   
This expression should match any hh:mm time from 00:00 to 23:59.

2. Commented Applescript


tell application "BBEdit"

set vDocument to first text document of first window

set vTimeRegex to "(?:[01][0-9]|2[0-3]):[0-5][0-9]" -- Regex to match any time from 00:00 to 23:59.

set vRegex to "^(" & vTimeRegex & ")-(" & vTimeRegex & ")\\h+([A-Z]{3})" -- Regex to captures 3 informations:

-- at beginning of a line 

-- a start time to be captured

-- a colon 

-- a end time to be captured    

-- one or more horizontal spaces

-- 3 letters to be captured

set vOptions to {search mode:grep, starting at top:true, wrap around:false, returning results:true} -- We want `find` to return a list of the found matches with offsets in the document.

set vResult to find vRegex searching in vDocument options vOptions

log vResult

if vResult's found then -- The find command succeeded. vResult has a `found matches` property that lists the matches.

repeat with vMatch in found matches of vResult -- Lets loop over each match and extract the captured strings.

log vMatch

set vOptions to {search mode:grep, starting at top:true, wrap around:false, returning results:false} -- This time, we don't want find to return results because we want to extract the captured strings.

set vTag to characters (vMatch's start_offset) thru (vMatch's end_offset) of vDocument -- Create a reference to the substring we want to decompose by using grep substitutions.

set vTagMatch to find vRegex searching in vTag options vOptions -- Use `find` again against each substring (e.g. '08:30-11:30 UWA') to capture the matching parts.

if vTagMatch's found then -- This should always succeed.

set vStartTime to grep substitution of "\\1" -- matched by the first capturing parentheses: '08:30'   

set vEndTime to grep substitution of "\\2" -- matched by the second capturing parentheses: '11:30'

set vClientCode to grep substitution of "\\3" -- matched by the third capturing parentheses: 'UWA'

log {vStartTime:vStartTime, vEndTime:vEndTime, vClientCode:vClientCode}

end if

end repeat

end if

end tell


Best regards

Jean Jourdain

e2o

unread,
Aug 20, 2023, 11:24:02 PM8/20/23
to BBEdit Talk
Thank you so much! I'm getting there!

A couple things I'm confused about:
- vMatch - I don't see where it gets defined.
- vMatch - also, how would you describe what vMatch contains that we want/need from it? I don't see how we get the number of repeats from it.
- Couldn't I simplify things by *assuming* I have a match and not have to check? If so, it seems I could just start with the repeat loop. Just a thought. If this is best practice, I'm all for it.

The repeat is great because I often have multiple time entries per daily ticket:


+ - - - - + - - - - + - - - - +
09:30-14:00 HGA
12:30-13:15
14:00-15:30


: Item one
- the associated notes

:: Item two
- the associated notes

- etc
+ - - - - + - - - - + - - - - +

I didn't see your script picking up multiple matches, but I realized I need to have the client code on each line to match. Then it finds each one. This makes me think I should reformat as the following to simplify things:


+ - - - - + - - - - + - - - - +
HGA
09:30-14:00
12:30-13:15
14:00-15:30


: Item one
- the associated notes

:: Item two
- the associated notes

- etc
+ - - - - + - - - - + - - - - +

The final goal is to transform the document to have a single summary line at the top, and move the individual time entries with time totals to the bottom. This let's me transfer a single time entry per day into our billing system for each client, even though I might have multiple interactions. I still want to preserve the individual times for the record:


+ - - - - + - - - - + - - - - +
HGA
09:30-16:15 6.75


: Item one
- the associated notes

:: Item two
- the associated notes
- etc

09:30-14:00 4.50
12:30-13:15 0.75
14:00-15:30 1.50 6.75

+ - - - - + - - - - + - - - - +

I'm using a lot of Keyboard Maestro looping, time math etc. to do all this. It seems a bit sluggish, and it seems a good chance to learn some AppleScript.

I think I'm slowly becoming more able to start tackling this. As always, I really appreciate your help!

- eric
Reply all
Reply to author
Forward
0 new messages