Create a semicolon separated list into a set

Hey there Tinderbox community. I could use some help.

I have a list of emails, e.g.

<AAA@gmail.com>
<BBB@gmail.com>
<CCC@yahoo.com>

Using the training I got form @PaulWalters and the Marks (@mwra @eastgate) I was able to run a grep command in a Stamp to get the emails into a list:

$MyList=runCommand(“grep -o ‘[[:alnum:]+._-]@[[:alnum:]+._-]’”,$Text);

The above returns this:
AAA@gmail.com
BBB@gmail.com
CCC@gmail.com

Now what I’d like to do is take the above is and convert it into a semicolon-separated list for a set:

AAA@gmail.com;BBB@gmail.com;CCC@gmail.com

Which would result in $Attendees=AAA@gmail.com;BBB@gmail.com;CCC@gmail.com

I’m being playing with sed - e commands and just can’t seem to get it to work. Anyone of any idea how to make this work?

So you have a string:

AAA@gmail.com
BBB@gmail.com
CCC@gmail.com

which in a Tinderbox string terms is "AAA@gmail.com\nBBB@gmail.com\nCCC@gmail.com" as \n indicates a line break. So now we can use the String .split() using the line break `\n’ as the spit delimiter:

$MyList = "AAA@gmail.com\nBBB@gmail.com\nCCC@gmail.com".split("\n");

See this demo: string split demo.tbx (82.5 KB)

Select note ‘Test note’ then use stamp ‘Text .split’ and look at the value of $MyList in the notes Displayed Attributes.

1 Like

There are, of course, many ways to do this. I often turn to awk [1] for this type of thing. The attached TB file shows how to do this using $Rule to assign the values to $MySet. I first build the command in $MyCommand (for clarity) and then passing that as the argument to runCommand:

$MyCommand="awk 'FNR==1 " + "{printf(" + '"%s",' + "$1);next}" + "{printf(" + '";%s",' + "$1)}'";$MySet=runCommand($MyCommand,$Text)

The command executed in $Rule is equivalent to the following used zsh shell command line (which assumes the list of values is contained in the clipboard):

$ pbpaste | awk 'FNR==1 {printf("%s",$1);next}{printf(";%s",$1)}' AAA@gmail.com;BBB@gmail.com;CCC@gmail.com

The command pbpaste writes the contents of the clipboard stdout, which is the piped (using '|') into the awk command. The argument to awk is a program that prints out the first list item (the FNR==1 part) and then continues by reading the next item (next1). For all other items in the list, each is printed out with a preceding semicolon (print ";" $1).

This should do the trick for you — let me know if you have any problems (rtalexander@mac.com).

awk-test.tbx (76.6 KB)

  1. Gawk: Effective Awk Programming
1 Like

Obviously Mark Anderson’s suggestion is the way to go!

Are you doing this for one list? An occasional list? Or are people sending you these lists every five minutes.

If I were doing this myself (and, in point of fact, I do exactly this every month or two), I’d open the email list in BBEdit. It’s got plenty of nice tools for doing this, and you don’t need to fuss with runCommand.

1 Like

A rule would be overkill for a one-time event, no?

I would like to do it repeatedly. My use case is this. When you drag an ICS file on to Tnderbox, Tinderbox copies the $Name, $StartDate, $EndDate. It ignores everything else.

What I’ve been doing is hand-copying the names and emails of all the invitees for all my meetings. What I figured out is that I can use

$Attended=runCommand("grep -o '[[:alnum:]+\.\_\-]*@[[:alnum:]+\.\_\-]*'",$Text);

to copy the email address after paying them from the Calendar to the meeting. I can then use Roger’s code to build the list. My complete script looks like this (last names and domain blurred out), I’m to complete the operation on all one attribute in a Stamp.

image

$Attended=runCommand("grep -o '[[:alnum:]+\.\_\-]*@[[:alnum:]+\.\_\-]*'",$Text);$MyCommand="awk 'FNR==1 " + "{printf(" + '"%s",' + "$1);next}" + "{printf(" + '";%s",' + "$1)}'";$Attended=runCommand($MyCommand,$Attended);

I tried Mark’s method. It worked great when the emails were in $Text, but did not work when they were in a field, like with Roger’s script.

There are a couple of things I can’t figure it. I’m not sure why Roger’s code needs the MyCommand attribute. In an attempt to skip this step I tried putting the command in the Stamp and got an error.

image

/bin/sh: line 1: unexpected EOF while looking for matching `‘’
/bin/sh: line 7: syntax error: unexpected end of file

Also, I’d love to part the first names. In Expressions, this RegEx .*(?=<) seems to pull the right info, but when applying within the Stamp, does not seem to work.

Thanks for the effort. This will save a lot of time.

My objective was not to suggest the use of a rule—that was merely a convince to get the code to execute (I could have achieved that differently). My intent was to illustrate how Awk could be used to convert a sequence of strings into a single string of delimited items. There are other ways to do it using runCommand, and of course the approach that Mark suggested.

The MyCommand attribute is in fact not needed. I was having a bit of trouble getting the Awk command properly formatted as an argument of runCommand. So I just separated the concerns by assigning the command to be executed to $MyCommand so as to make it easier for me to spot the error.

1 Like

Michael, I believe the problem you are having is due to embedded double quotes used in the Awk program. I was having this problem too until I realized that the embedded double quotes were likely the issue. I then tried escaping them (e.g., ‘\”’), but couldn’t get that to work. Then it occurred to me (which MarkB later confirmed) that the way to go was to break the command up so that I could enclose the double quotes as a single quoted string. And concatenate the pieces back together (you can see this being done where I assigned the value to $MyCommand).

Now that I think about it, I probably could have avoided the problem entirely had I just enclosed the whole Awk command with single quotes (I’ll have to give that a try).

1 Like

Passing anything complex to runCommand() is easy to avoid. Do the hard part in a script. For example, instead of

$MyAttended=runCommand(" grep -o ‘[[:alnum:]+._-]@[[:alnum:]+._-]’",$Text);

you could then just have

$MyAttended=runCommand(“/usr/bin/fixupAttendeeFile”,$Text)

This solves problems with wrangling quotations and such, and also makes your intent clearer.

Thanks. Sorry for my coding ignorance, but is “/usr/bin/fixupAttendeeFile” a code note or is it a system folder?

It’s an example. The script doesn’t exist, but if someone wrote a script to fix problem in this script, and named the script fixupAttendeeFile and stored it in /usr/bin/ at the root of Macintosh HD – then that example is how one would invoke that script and apply it to the $Text of the note.

I understand. Thanks.