I am trying to find a quick & easy way to take a phone number and see if anyone in my Contacts app has that phone number. If yes, I would like to output the name or names (could be 1 or more individuals, could be a company).
I was trying to do this with sqlite and then remembered that AppleScript has (or at least had) good ways of working with contacts. I’m not sure if that is still true or not.
Looking around for examples, it seems that potential problems are:
Some phones may be shared with multiple people
People may have more than one phone number associated with their name
Although Contacts app may display phone numbers consistently, that does not mean they are consistent in the DB. For example, any of these formats could be found:
Maybe the code below will help with your project. —Stan C.
(***************************************************************
Find Phone Numbers in Contacts
Written by Stan Cleveland
****************************************************************
Script dependencies:
macOS X Mojave v10.14.6 or higher
****************************************************************
Notes:
1. Possible phone number formats:
"+1 (458) 204-4219"
"+19712454542"
"(503) 799-6280"
"503-465-0195"
"503.225.0515"
"5417657600"
Other shorter messaging numbers
2. There apears to be two different space characters used in Contacts.
****************************************************************
Version history:
v1r0 (2021/07/20) -- Initial version.
****************************************************************)
-- define search criteria
set phoneNumberToFind to "503-222-5566"
------------------------------------------------------------------------------------------
---------------------------------- MAIN SCRIPT ----------------------------------
------------------------------------------------------------------------------------------
-- generate normalized list of phone number information
tell application "Contacts"
set {pNames, pLabels, pNumbers} to ¬
{name, label of phones, value of phones} of every person
end tell
-- normalize phone numbers and compile a number cross-reference
set phoneRecords to {}
repeat with i from 1 to (count pNames)
set thisName to item i of pNames
set labelsList to item i of pLabels
set numbersList to item i of pNumbers
repeat with j from 1 to (count numbersList)
set thisLabel to item j of numbersList
set thisNumber to normalize(item j of numbersList)
set end of phoneRecords to thisNumber & "_" & thisLabel & "_" & thisName
end repeat -- with j from 1 to (count labelsList)
end repeat -- with i from 1 to (count pNames)
-- cycle through phone information, looking for target number
set foundRecords to {}
repeat with i from 2 to (count phoneRecords)
set thisRecord to item i of phoneRecords
if thisRecord starts with phoneNumberToFind then
-- break record into relevant parts
tid("_")
set {phoneNumber, phoneType, phoneName} to text items of thisRecord
tid("")
set end of foundRecords to {number:phoneNumber ¬
, type:phoneType, name:phoneName}
end if -- thisRecord starts with targetNumber
end repeat -- with i from 2 to (count phoneRecords)
return foundRecords
------------------------------------------------------------------------------------------
----------------------------------- HANDLERS -----------------------------------
------------------------------------------------------------------------------------------
on normalize(phoneNumber)
phoneNumber
tid({"+1 ", "+1 ", "+1", "(", ") ", ") ", "-", ".", " ", " "})
set parts to text items of phoneNumber
tid("")
set keeperParts to {}
repeat with i from 1 to (count parts)
set thisPart to item i of parts
if thisPart is in {"1", " ", ""} then
-- ignore it
else
set end of keeperParts to thisPart
end if
end repeat -- with i from 1 to (count parts)
if (count keeperParts) is 1 then
if (length of item 1 of keeperParts) is 10 then
set thisPart to item 1 of keeperParts
set fixedNumber to text 1 thru 3 of thisPart & "-" & ¬
text 4 thru 6 of thisPart & "-" & text 7 thru 10 of thisPart
else -- (length of item 1 of keeperParts) is not 10
set fixedNumber to keeperParts as text
end if -- (length of item 1 of keeperParts) is not 10
else -- (count keeperParts) > 1
tid("-")
set fixedNumber to keeperParts as text
tid("")
end if -- (count keeperParts) > 1
return fixedNumber
end normalize
on tid(d)
set my text item delimiters to d
end tid
One probably-dumb question: would it be difficult to this in a shell script or something where I would give the phone number as an ‘argument’ to the script?
Almost anything is possible, but I leave it to you to adjust things to meet your needs. I posted a general solution to get you started, but am not in a position to take on custom coding. Learning AppleScript isn’t easy, but is quite possible and well worth the time and effort, you’ll find.
I’ve taken a bit of a different tack than Stan and gone for pure speed. This script takes about 0.4 seconds to run on my fairly old hardware.
I’ve not normalized all the phone number formats – just a couple – more is an exercise for the user.
I’ve not massaged the input number – another exercise for the user.
Look for this line to test, and feed it a valid number in the given format from your contacts.
set findPattern to "(000) 111-2222"
I’ve emplaced code to use Keyboard Maestro as the input/run mechanism if desired.
If one or more numbers are found a choose-from dialog displays all found records.
If nothing is found a system notification is run to indicate same.
If you need help fleshing-out the phone number normalizing code let me know.
-Chris
--------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2021/07/20 23:37
# dMod: 2021/07/20 23:43
# Appl: Contacts
# Task: Check to see if a given phone number is in your contacts.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @Contacts
--------------------------------------------------------
use AppleScript version "2.4" --» Yosemite or later
use framework "Foundation"
use scripting additions
--------------------------------------------------------
tell application "Contacts"
if not running then run
end tell
--------------------------------------------------------
--» Get phone number to search for from Keyboard Maestro
set kmInstance to system attribute "KMINSTANCE"
tell application "Keyboard Maestro Engine"
set findPattern to getvariable "local_FindPattern" instance kmInstance
end tell
--------------------------------------------------------
--» •• Phone Number to search for testing if not available from Keyboard Maestro. ••
set findPattern to "(000) 111-2222"
--» Escape parenthesis in phone number for regular expression.
set findPattern to my cngStr:"([()])" intoString:"\\\\$1" inString:findPattern
--------------------------------------------------------
--» Generate flat list of contact records.
tell application "Contacts"
set {nameList, labelList, phoneNumList} to {name, label of phones, value of phones} of every person
end tell
set collatedPhoneNumList to {}
set AppleScript's text item delimiters to " · "
repeat with ndx1 from 1 to length of labelList
set tempLabelList to item ndx1 of labelList
set tempPhoneNumList to item ndx1 of phoneNumList
set tempRecord to {}
repeat with ndx2 from 1 to length of tempLabelList
set end of tempRecord to item ndx2 of tempLabelList
set end of tempRecord to item ndx2 of tempPhoneNumList
end repeat
set itemRef to (a reference to item ndx1 of phoneNumList)
set itemRef's contents to (item ndx1 of nameList) & " · " & (tempRecord as text)
end repeat
set AppleScript's text item delimiters to linefeed
set phoneNumList to phoneNumList as text
set phoneNumList to my cngStr:"\\t" intoString:" · " inString:phoneNumList
--» Normalize Phone Number Formats.
set phoneNumList to my cngStr:"(\\d{3})(\\d{3})(\\d{4})" intoString:"($1) $2-$3" inString:phoneNumList
set phoneNumList to my cngStr:"(\\d{3})-(\\d{3})-(\\d{4})\\b" intoString:"($1) $2-$3" inString:phoneNumList
set findPattern to ("(?m)^.*" & findPattern & ".*$")
set foundRecord to my extractUsingPattern:findPattern fromString:phoneNumList resultTemplate:"$0"
if foundRecord ≠ {} then
set AppleScript's text item delimiters to linefeed
choose from list foundRecord with title "Contacts Search"
else
display notification "Phone Number NOT Found!" with title "Search Contacts" subtitle "···························" sound name "Tink"
end if
--------------------------------------------------------
--» HANDLERS
--------------------------------------------------------
on cngStr:findString intoString:replaceString inString:dataString
set anNSString to current application's NSString's stringWithString:dataString
set dataString to (anNSString's ¬
stringByReplacingOccurrencesOfString:findString withString:replaceString ¬
options:(current application's NSRegularExpressionSearch) range:{0, length of dataString}) as text
end cngStr:intoString:inString:
--------------------------------------------------------
on extractUsingPattern:thePattern fromString:theString resultTemplate:templateStr
set theString to current application's NSString's stringWithString:theString
set theRegEx to current application's NSRegularExpression's regularExpressionWithPattern:thePattern options:0 |error|:(missing value)
set theFinds to theRegEx's matchesInString:theString options:0 range:{0, theString's |length|()}
set theResult to current application's NSMutableArray's array()
repeat with aFind in theFinds
set foundString to (theRegEx's replacementStringForResult:aFind inString:theString |offset|:0 template:templateStr)
(theResult's addObject:foundString)
end repeat
return theResult as list
end extractUsingPattern:fromString:resultTemplate:
--------------------------------------------------------