Extraction usernames from email addresses in order top down

Hi again marvellous community, this time, if possible, i need help to create a simple script that extract names in order from first up descending, in a txt file that has delimiter “return” or “enter” the file is like this:

hajydhtn@mail.xxx
aohauaho@mail.xxx
iiksjjiwow@mail.xxx
pjaiowjondon@mail.xxx

I am interested in the extraction of the part before the “@” and of the entire address but in 2 different codes.

I hope i was clear, if not here i do a drawing :wink:

first code result:

hajydhtn@mail.xxx

second code result:

hajydhtn

Hello: I have made a do shell script line for you that takes the quoted form of a posix filename as a parameter, which should returns lines consisting of email adresses, and the the names of the receipients in two columns.


set pxMailList to quoted form of (POSIX path of (choose file))
set results to (do shell script "cat " & pxMailList & " |sed 's/\\r/\\'$'\\n''/g' |sed  -n 's/^\\([^@]*\\)\\([@][m][a][i][l]\\)\\(.*\\)$/\\1\\2\\3  \\1/p' |tr \" \" \"\\t\"")
log results

hajydhtn@mail.xxx hajydhtn aohauaho@mail.xxx aohauaho iiksjjiwow@mail.xxx iiksjjiwow pjaiowjondon@mail.xxx pjaiowjondon

thank you for your help but maybe i was not clear, i dont need to do a list i need it to extract one name at a time and strip it of the @ and the domain plus it has to do something in the text file so that the next time it access it will know where to go take a different name.

This isn’t still totally clear to me, but it starts to take form. Is it so that you only need the username, and not the rest of the mail address?

See if you can use this:


property parnum : 0
set mailList to (choose file)

set {mAddr, mName} to getReceipStuff for mailList

on getReceipStuff for mailList
	try
		set fref to open for access mailList
		set parnum to parnum + 1
		set thePars to every paragraph of (read fref as «class utf8»)
		set parCount to length of thePars
		if parnum > (parCount - 1) then
			error "The file is consumed, no more adresses to be had,
 open the script to start over" number 3000
		else
			set thePar to item parnum of thePars
			
			set results to (do shell script "echo " & thePar & "|sed -n 's/^\\([^@]*\\)\\([@][m][a][i][l]\\)\\(.*\\)$/\\1\\2\\3 \\1/p'")
			set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, space}
			set {mAddr, mName} to {text item 1 of results, text item 2 of results}
			set AppleScript's text item delimiters to tids
			close access fref
		end if
	on error e number n
		-- Chris Stone
		try
			close access fref
		end try
		set {cr, sep} to {return, "------------------------------------------"}
		set errmsg to sep & cr & "Error: " & e & cr & sep & cr & "Error 
	Number: " & n & cr & sep
		try
			tell application "SystemUIServer"
				activate
				display dialog errmsg
			end tell
		end try
		return null
	end try
	return {mAddr, mName}
end getReceipStuff


Edit
Its tested…

Sorry for the late reply, i tried it, the error code i obtain is this:

execution error: Can't get item 1 of null. (-1728)

Any idea about it? How u tested it? how it was your text file?

I need both the mail address with a code and then i need another code to retrieve only the part before the @ character.

Hello.

Here is the text file I used, with Unix LF as line endings. Though I think return should work equally well.

hajydhtn@mail.xxx aohauaho@mail.xxx iiksjjiwow@mail.xxx pjaiowjondon@mail.xxx
It may fail if you are calling the handler from within a tell block or such, then you should add “my” in front of the handler. Otherwise you should try to insert “log statements” within the handler, as I can’t see from here where it fails, y the information you have provided.

The handler returns both values the full mail address and the username of the receipient.

I am trying it in automaton and in keyboard maestro and the error is the same, about handlers i don’t know what that is can you do an example, where should i put “my”? Sorry for my noobism :slight_smile:

Hi minipower.

The immediate cause of error you’re reporting is that the ‘getReceipStuff’ handler is returning ‘null’ because of another error, but the third line of the script’s expecting a list with at least two items. The script should be displaying an message explaining the other error before that happens. What does it say?

The error is this:

execution error: Can't get item 1 of null. (-1728)

nothing else, consider i am opening it with automaton and/or keayboard maestro which gives some number after the message /private/var/folders/7p/svbq_n050fl47k7jpg1h54540000gn/T/Keyboard-Maestro-Script-28C00471-7DE8-4C55-99BD-96DB47DDB3D3:91:140: execution error: Can’t get item 1 of null. (-1728)
I don’ know if this is useful to understand what is wrong

Hello!

I wonder if you can post just how you use it, that is, how you call the handler, and specify the file containing the mail addresses. The script as it stands works for me, but maybe we’ll have to adjust some.

I don’t really know anything about how a script for Keyboard Maestro should look like.

minipower should test it in AppleScript Editor first before trying to run it in other environments.

If ‘automaton’ is “Automator”, the script may need to be able to receive parameters.

@Nigel: i try it in automator and in maestro

@McUsr: i can post the code as i put it in both the programs

property parnum : 0
set mailList to ((path to documents folder as text) & "email200.txt")

set {mAddr, mName} to getReceipStuff for mailList

on getReceipStuff for mailList
	try
		set fref to open for access mailList
		set parnum to parnum + 1
		set thePars to every paragraph of (read fref as «class utf8»)
		set parCount to length of thePars
		if parnum > (parCount - 1) then
			error "The file is consumed, no more adresses to be had,
open the script to start over" number 3000
		else
			set thePar to item parnum of thePars
			
			set results to (do shell script "echo " & thePar & "|sed -n 's/^\\([^@]*\\)\\([@][m][a][i][l]\\)\\(.*\\)$/\\1\\2\\3 \\1/p'")
			set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, space}
			set {mAddr, mName} to {text item 1 of results, text item 2 of results}
			set AppleScript's text item delimiters to tids
			close access fref
		end if
	on error e number n
		-- Chris Stone
		try
			close access fref
		end try
		set {cr, sep} to {return, "------------------------------------------"}
		set errmsg to sep & cr & "Error: " & e & cr & sep & cr & "Error 
   Number: " & n & cr & sep
		try
			tell application "SystemUIServer"
				activate
				display dialog errmsg
			end tell
		end try
		return null
	end try
	return {mAddr, mName}
end getReceipStuff

Can you McUsr post the script exactly how you use it, in what you use it and maybe post the text file you use too?
I can do a screencast or snapshot maybe?

Hello.

I have made an ‘email200.txt’ files in my documents folder, and filled with the data above. When i run the script, it works exactly as it was supposed to.

On the other hand when an error occur, ( it did that for me the first time, as I didn’t have any data in the file), then I get the same error as you did.

I now think the error to be that yoiu run the script from automator or something, and that the dialog is blatantly surpressed! (That has happend for me with another script when I used SystemUIServer to show an error dialog.)

So, how about the script just dying if something goes wrong, and the script starting with the first mailaddress, when the last is reached. I am not that competent in interfacing AppleScript with Automator, with regards to error messages.

Edit

Change the line that reads:

tell application "SystemUIServer"

to

tell application "Finder"

I hope this will evoke some error message! :slight_smile:

Here are a couple of shorter versions for when the problem’s ironed out. :wink:

sed:

property parnum : 1

set mailList to quoted form of POSIX path of ((path to documents folder as text) & "email200.txt")
set {mAddr, mName, parCount} to paragraphs of (do shell script ("tr '\\r' '\\n' <" & mailList & " | sed -En '" & parnum & " { p; s/@.+//p ; } ; $ = ;'"))

set parnum to parnum + 1
if (parnum > parCount) then
	tell application (path to frontmost application as text)
		display dialog "This is the last line in the file. The script will start again at the top next time." buttons "OK" default button 1 with icon note
	end tell
	set parnum to 1
end if

{mAddr, mName}

Vanilla:

property parnum : 1

set mailList to (path to documents folder as text) & "email200.txt"
set txt to (read file mailList as «class utf8») -- Assuming it *is* UTF-8 text!
set mAddr to paragraph parnum of txt
set mName to text 1 thru ((offset of "@" in mAddr) - 1) of mAddr
set parCount to (count txt each paragraph)

set parnum to parnum + 1
if (parnum > parCount) then
	tell application (path to frontmost application as text)
		display dialog "This is the last line in the file. The script will start again at the top next time." buttons "OK" default button 1 with icon note
	end tell
	set parnum to 1
end if

{mAddr, mName}

Edit: Goof in the vanilla script corrected. :rolleyes:

Shorter is always better. I figured the conversion of newlines wasn’t needed, since the input consists only of one line at a time. Actually, in this particular case, I think those scripts extracts mail-addresses better than mine, since sooner than later a mail address without mail in it will come around.

As for Utf8, if the file is made since Leopard, you have to purposefully make something other than utf8 or utf16, which I doubt the OP has done. (He may have an older file though.)

So if he is in doubt, he should open his mailaddress file with either TextWrangler or TextEdit, with TextEdit, he should go into preferences, and see to that it saves in utf-8 format. (Which can be easily spotted at the bottom-bar in TextWrangler.)

dear Nigel, your codes work but they give as result every time the first email address of the list, so now how can i be able to have a different address every time i execute the script again?

McUsr’s script and my two rely on the persistence of a script’s properties between runs. The property ‘parnum’, which represents the number of a line in the text file, is incremented on each run and starts off with the new value on the next run. If you run the scripts several times in AppleScript Editor, you’ll see that they work and that they go one line further into the text file each time. There are circumstances, though, when changed property values don’t persist between runs and that’s obviously what’s happening when you run the scripts the way you do.

Another course of action would be to change something in the text file, as you originally suggested. What would be acceptable? Do you want the e-mail addresses preserved, or can they be zapped as they’re returned?

mhm this question is difficult to answer but given that i can always store copies of the file if it is easier to “zap” let’s zap them and viceversa, if i was chuck norris all of this would not be so difficult, it would be necessary only a nod. :slight_smile:

I think this does the job, but it’s way past my bed time.

It appends an additional line to the beginning of the file and uses this to store the original number of the next line to process. When it’s the last line’s turn, the additional line is deleted.

main()

on main()
	set mailList to (path to documents folder as text) & "email200.txt"
	
	set fRef to (open for access file mailList with write permission)
	try
		set txt to (read fRef as «class utf8») -- Assuming it *is* UTF-8 text! 
		-- From the first line, get the original number of the next line to process, adding 1 to compensate for the presence of the first line. Prepare to write the text back to the file with a new first line.
		try
			set n to ((paragraph 1 of txt) as integer) + 1
			set newTxt to (n as text) & linefeed & text from paragraph 2 to -1 of txt
		on error -- Just started. The number line's not been appended yet.
			set n to 1
			set newTxt to "2" & linefeed & txt
		end try
		-- If the indexed line is the last in the text, prepare to write the text back to the file without the added first line.
		if ((count txt each paragraph) ≤ n) then
			showError("All the lines in the file have now been read.")
			set newTxt to text from paragraph 2 to -1 of txt
		end if
		-- Do the write-back.
		set eof fRef to 0
		write newTxt as «class utf8» to fRef
		close access fRef
	on error errMsg
		close access fRef
		showError("While reading or marking the file data: " & errMsg)
		error number -128
	end try
	
	set mAddr to paragraph n of txt
	set mName to text 1 thru ((offset of "@" in mAddr) - 1) of mAddr
	
	return {mAddr, mName}
end main

on showError(msg)
	tell application (path to frontmost application as text)
		display dialog msg buttons "OK" default button 1 with icon stop
	end tell
end showError

Very nice, and generally useful for storing data, that is to be consumed at separate intervals in time Nigel! :slight_smile: