Sunday, April 18, 2021

#1 2021-03-21 10:16:39 am

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Question about implementing a regex comparison in AppleScript?

Hi there,

with the very kind help of the members here I succeeded to build a script, that saves every incoming Mail message as .eml file.

In Apple Mail I built a rule to target the script to special mails.

But....

I'd like to be more specific than what's possible with Apple mail rules.
In the beginning of the script I'd like to check wether the subject of the mail matches a certain pattern. And for the pattern I have built a regex expression.

Question:
(how) is it possible to check at the beginning of the script if the subject matches the regex - if positive perform the script or otherwise quit the script?

The regex expression identifies mail subjects that look like:
ubfg-210312-gg-proposal for contract

The expression is: (x|(w-))?[^-]...-\d{6,6}-\w\w-.{0,}

The script is:

Applescript:



global theFile


using terms from application "Mail"
   on perform mail action with messages these_messages for rule this_rule
       tell application "Mail"
           repeat with eachMessage in these_messages
               
               set ptd to alias "Macintosh HD:Users:xy:Documents:mail_deposit:"
               set theText to source of eachMessage
               set theSubject to (subject of eachMessage) -- as string
               if theSubject is "" then set theSubject to "no subject"
               if theSubject contains ":" then ¬
                   set theSubject to my snr(theSubject, ":", "_")
               set theFile to ((ptd & theSubject) & ".eml") as string
               
               -- display dialog "File" & (theFile as string)
               
               
               my resolveConflict(ptd, theSubject)
               set theFileID to open for access file theFile with write permission
               write theText to theFileID
               close access theFileID
               
           end repeat
           -- display dialog "There were " & length of these_messages & " messages saved."
           
       end tell
       
   end perform mail action with messages
end using terms from

on resolveConflict(ptd, theSubject)
   tell application "Finder"
       set theCounter to 1
       set noConflict to false
       repeat until noConflict
           
           
           if exists file (theFile) then
               
               set theFile to (((ptd & theSubject) & " -" & theCounter as string) & ".eml")
               set theCounter to theCounter + 1
               
           else
               set noConflict to true
               
           end if
       end repeat
   end tell
end resolveConflict

on snr(theString, searchString, replaceString)
   tell (a reference to my text item delimiters)
       set {oldTID, contents} to {contents, searchString}
       set {theString, contents} to {theString's text items, replaceString}
       set {theString, contents} to {theString as Unicode text, oldTID}
   end tell
   return theString
end snr


Filed under: mail, regex

Offline

 

#2 2021-03-21 02:52:20 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 1752

Re: Question about implementing a regex comparison in AppleScript?

Hi,

Test yourself. I edited your resolveConflict handler as well. And, I removed your snr handler, because your subjects doesn't contain ":" symbol. Script:

Applescript:


use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"

using terms from application "Mail"
   on perform mail action with messages these_messages for rule this_rule
       tell application "Mail"
           repeat with eachMessage in these_messages
               tell eachMessage to set theSubject to its subject
               -- CHECK matchinng to Regex
               set theNSString to (NSString's stringWithString:theSubject)
               set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
               -- EXPORT as EML file if subject matches to regex
               if subject_MatchesToRegex then
                   tell eachMessage to set theText to its source
                   set theFile to my resolveConflict(ptd, theSubject)
                   set theFileID to open for access file theFile with write permission
                   write theText to theFileID
                   close access theFileID
               end if
           end repeat
       end tell
   end perform mail action with messages
end using terms from

on resolveConflict(ptd, theSubject)
   tell application "Finder"
       set theCounter to 1
       repeat
           set theFile to ptd & theSubject & " -" & theCounter & ".eml"
           if not (exists file theFile) then return theFile
           set theCounter to theCounter + 1
       end repeat
   end tell
end resolveConflict

Last edited by KniazidisR (2021-03-23 01:47:07 pm)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#3 2021-03-22 07:36:48 am

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Thank you KniazidisR, the code looks beautiful.
Strangely I didn't get it to work in my environment. Maybe I made some mistake while transferring it?
I added 2 dialogs for debugging but I couldn't identify the problem.

When the Script gets triggered I get the first dialog telling me "Start repeat loop." but then the script seems to stop and the second dialog "Begin check matching." does no appear at all.

Another thing: is there a way to display the result of the check for debugging issues. Just for the case if I made some mistake with my regex expression. I already tested it at https://regex101.com/ but maybe I made some mistake by transferring it to AppleScript.

Applescript:


use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"

using terms from application "Mail"
   on perform mail action with messages these_messages for rule this_rule
       tell application "Mail"
           repeat with eachMessage in these_messages
               display dialog "Start repeat loop."
               tell eachMessage to set theSubject to its subject
               display dialog "Begin check matching."            
               -- CHECK matchinng to Regex
               set theNSString to (NSString's stringWithString:theSubject)                
               set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
               -- EXPORT as EML file if subject matches to regex
               
               if subject_MatchesToRegex then
                   display dialog "Subject matches."
                   
                   tell eachMessage to set theText to its source
                   set theFile to my resolveConflict(ptd, theSubject)
                   set theFileID to open for access file theFile with write permission
                   write theText to theFileID
                   close access theFileID
               end if
           end repeat
       end tell
   end perform mail action with messages
end using terms from

on resolveConflict(ptd, theSubject)
   set theFile to ptd & theSubject & ".eml"
   set theCounter to 0
   repeat
       try
           alias theFile
           return theFile
       on error
           set theCounter to theCounter + 1
           set theFile to ptd & theSubject & " -" & theCounter & ".eml"
       end try
   end repeat
end resolveConflict

Offline

 

#4 2021-03-22 07:45:54 am

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 1752

Re: Question about implementing a regex comparison in AppleScript?

traegheitsmoment wrote:

When the Script gets triggered I get the first dialog telling me "Start repeat loop." but then the script seems to stop and the second dialog "Begin check matching." does no appear at all.


Display dialog is modal and waits response from you. And may be hidden on the background.  Try to put instead display notification for debugging. For example:

Applescript:


display notification "Start repeat loop." giving up after 2 -- seconds
delay 3

Or, put after tell application "Mail" following, to bring Mail's window and display dialogs to front:

activate

To debug result of check, you can use:

Applescript:


if subject_MatchesToRegex then display notification "Subject Matches To Regex" giving up after 2
delay 3

I add a delay of 3 seconds (which should be slightly longer than the notification's self-disappearance time), because if the script is too fast, the notifications may overlap. And we need clarity when debugging.

Now,
here, I check the subject provided by you in the post #1, and script returns true:

Applescript:


use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"

set theSubject to "ubfg-210312-gg-proposal for contract"
set theNSString to (NSString's stringWithString:theSubject)
set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
--> true

Last edited by KniazidisR (2021-03-22 08:31:13 am)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#5 2021-03-22 02:40:48 pm

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Thank you again for your input.

Unfortunately I'm completely lost and clueless.

First of all I tried to implement the notification alerts but it only get's me an error telling me something like 'end of line expected but identifier found'. Maybe it's because I have BigSur with AppleScript 2.7. If I replace the word 'notification' by 'dialog' there is no error, but then I have a dialog again.

Next I tried 'activate' but this doesn't reveal any hidden dialog boxes.

And then I tried all kinds of modifications to get the script working, but nothing worked.
So I tried again the script version with the two dialogs but still the same.
It shows the dialog "Start repeat loop." but then it seem's to stop.

The next dialog "Begin check matching." right after the line "tell eachMessage to set theSubject to its subject" does not appear and the small turning gear icon in the menue stops and then disappears.

Do you have any idea if maybe the other AppleScript version is causing this problem?

Sorry for bothering you.

Offline

 

#6 2021-03-23 01:43:16 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 1752

Re: Question about implementing a regex comparison in AppleScript?

First, my resolveConlict handler contained an error. I fixed it now.

Secondly, the script is easier to debug not as a mail rule, but as a regular script. To do this, just comment out the line on/end perform mail actions and use (get selection) instead of these_messages.

I tested the following script, edited as regular script and it works. It is easy for you to turn this script to mail rule. If it does not work in the form of a rule, then the reason will no longer be in the script, but in the Mail's bug with mail rules. So, debug version script:

Applescript:


use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"

using terms from application "Mail"
   -- on perform mail action with messages these_messages for rule this_rule (COMMENTED)
   tell application "Mail"
       repeat with eachMessage in (get selection) -- these_messages (EDITED)
           
           tell eachMessage to set theSubject to its subject
           -- CHECK matchinng to Regex
           set theNSString to (NSString's stringWithString:theSubject)
           set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
           -- EXPORT as EML file if subject matches to regex
           
           if subject_MatchesToRegex then
               tell eachMessage to set theText to (its source) as rich text
               set theFile to my resolveConflict(ptd, theSubject)
               set theFileID to open for access file theFile with write permission
               write theText to theFileID
               close access theFileID
           end if
           
       end repeat
   end tell
   -- end perform mail action with messages (COMMENTED)
end using terms from


on resolveConflict(ptd, theSubject)
   tell application "Finder"
       set theCounter to 1
       repeat
           set theFile to ptd & theSubject & " -" & theCounter & ".eml"
           if not (exists file theFile) then return theFile
           set theCounter to theCounter + 1
       end repeat
   end tell
end resolveConflict

Last edited by KniazidisR (2021-03-23 01:50:25 pm)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#7 2021-03-23 02:57:19 pm

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Thank you for everything, KniazidisR!

The script is now working perfectly. As a 'normal' script and as a script attached to a mail rule as well.

Very good hint to test it as a 'normal' script for debugging.
This will sure help me in the future although in this case no debugging was needed because it all worked well without any adjustments.

Cheers
Carl

Offline

 

#8 2021-03-24 02:19:46 pm

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Just curious....
Is there a way to extract the string, that is found by the regex search?

In this actual case it might not make sense. But if the subject only 'contains' a string that matches the regex expression it might make sense to be able to work with the string.

For example: if the subject of the mail was...

Re.: Re.: Re.: ubfg-210312-gg-proposal for contract

.. it might help to extract 'ubfg-210312-gg-proposal for contract'

I tried this by:

Applescript:


set extraktString to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)
           display dialog "extraktString " & (extraktString as rich text)

But this was obviously a fail...

Offline

 

#9 2021-03-26 01:05:37 pm

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Cool, thank you very much. I'm gonna try

KniazidisR wrote:

This ASOBJC expression returns   array of NSStrings. So, coerce it as list, then get item 1 of this list, and coerce it as string.

Offline

 

#10 2021-04-01 01:37:57 pm

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Sorry - I was a little bit too optimistic about my capabilities to figure this out.
I tried for quite a while but failed.

Do you have another hint for me?

Thanks
Carl

Offline

 

#11 2021-04-01 03:05:32 pm

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11746
Website

Re: Question about implementing a regex comparison in AppleScript?

traegheitsmoment wrote:


I tried this by:

Applescript:


set extraktString to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)
           display dialog "extraktString " & (extraktString as rich text)

But this was obviously a fail...



rangeOfString:options: returns an NSRange, a struct with a location and a length, you have to extract the string with subStringWithRange

Applescript:


set extraktRange to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)
tell current application to set extraktString to (theNSString's subStringWithRange:extraktRange) as text
display dialog "extraktString " & extraktString

The tell current application expression avoids the terminology clash text <--> rich text


regards

Stefan

Offline

 

#12 2021-04-05 01:35:23 pm

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Hi Stefan,

thank you very much for your help.
When I try to implement it, I get the following message:

error "-[__NSCFString subStringWithRange:]: unrecognized selector sent to instance 0x600000227c00" number -10000

Can't figure out what the problem is... do you have an idea maybe?

Cheers
Carl

Offline

 

#13 2021-04-05 11:41:23 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 1752

Re: Question about implementing a regex comparison in AppleScript?

traegheitsmoment wrote:

error "-[__NSCFString subStringWithRange:]: unrecognized selector sent to instance 0x600000227c00" number -10000


subStringWithRange should be substringWithRange:

Applescript:


use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"

set theNSString to (NSString's stringWithString:"ubfg-210312-gg-proposal for contract")

set extraktRange to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)
set extraktString to (theNSString's substringWithRange:extraktRange) as string -- EDITED
display dialog "extraktString: \"" & extraktString & "\""

Last edited by KniazidisR (2021-04-06 12:05:02 am)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#14 2021-04-08 12:14:49 pm

traegheitsmoment
Member
Registered: 2021-01-13
Posts: 33

Re: Question about implementing a regex comparison in AppleScript?

Great. Once again... many thanks to you and Stefan
I would have never figured out the problem by myself.

Cheers
Carl

Offline

 

#15 2021-04-10 03:25:12 am

technomorph
Member
Registered: 2017-12-14
Posts: 180

Re: Question about implementing a regex comparison in AppleScript?

You could also use NSPredicate Matches comparison which can take a Reg-Ex string.

At the very start of your script You then could filter your whole array of messages and end up
With an array of messages that pass your filter.

https://nshipster.com/nspredicate/

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)