Import contact info from Mac Address Book 4.0.6

the magician

Active Member
Joined
Nov 9, 2006
Messages
496
At job, Mac OSX and Address Book 4.0.6 with contact info including in many cases emails. I'd like to get it of there, into Excel to manipulate, and ultimately into a FileWrecker Pro database. How to export 1087 entries from Address Book including only selective data fields is the question, and I know that's "slightly" OT, but I do want to import into Excel, so I hope that vindicates me! :) If not, and you can point me to a good MacForum, I'll settle.

Thanks.

el mago

"poof"
 

Excel Facts

Enter current date or time
Ctrl+: enters current time. Ctrl+; enters current date. Use Ctrl+: Ctrl+; Enter for current date & time.
Here is the import routine that I came up with.
Since VBA's MacScript function permits writting scripts on-the-fly, I'm sure that someone skilled in AppleScript could have Excel drive the export. I'm working on becoming more skilled.

Code:
Option Explicit
Dim newWorkbook As Workbook

Sub MainRoutine()
    Call ImportFromAddressBook
    Call RearrangeData
    Call parseNewWorksheet
    Application.Dialogs(xlDialogSaveAs).Show , 1
End Sub

Private Sub parseNewWorksheet(Optional argument As Boolean)
Dim rangeWidth As Long, oneCell As Range
    
    With newWorkbook.Sheets(1)
        With Range(.Cells(1, .Columns.Count).End(xlToLeft), .Cells(.Rows.Count, 1).End(xlUp))
            rangeWidth = .Columns.Count
            
            Rem remove semi-colons
            .Offset(0, rangeWidth).FormulaR1C1 = "=TRIM(SUBSTITUTE(RC[-" & .Columns.Count & "],"";"","" ""))"
            .Offset(0, rangeWidth).FormulaR1C1 = "=ParsingAddresses.xls!CleanDelimiters(RC[-" & .Columns.Count & "])"
            With .Resize(, rangeWidth - 1)
                .Value = .Offset(0, rangeWidth).Value
                .Offset(0, rangeWidth).Delete shift:=xlToLeft
            End With
            
            Rem parse address column
            With .Offset(0, rangeWidth + 1).Columns(1)
                .FormulaR1C1 = "=MID(RC[-2],FIND(LEFT(RC[-1],1),RC[-2]),1000)"
                .Value = .Value
                .Offset(0, -2).Resize(, 2).EntireColumn.Delete
            End With
            On Error Resume Next
                .Columns(1).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
            On Error GoTo 0
        End With
        
        Rem format headers
        With Range(.Cells(1, .Columns.Count).End(xlToLeft), .Cells(.Rows.Count, 1).End(xlUp))
            With .Rows(1)
                .HorizontalAlignment = xlCenter
                With .Font
                    .Bold = True
                    .Underline = xlUnderlineStyleSingle
                End With
            End With
            .Columns.AutoFit
            
            Rem format phone numbers
            For rangeWidth = 1 To .Columns.Count
                If .Cells(1, rangeWidth) Like "*Phone*" Then
                    With Range(.Cells(2, rangeWidth), Cells(.Rows.Count, rangeWidth))
                        For Each oneCell In .Cells
                            If oneCell <> vbNullString Then
                                oneCell.Value = NumbersOnly(oneCell.Value)
                            End If
                        Next oneCell
                        .NumberFormat = "[<=9999999]###-####;(###) ###-####"
                    End With
                End If
            Next rangeWidth
        End With
    End With
End Sub

Private Sub RearrangeData(Optional argument As Boolean)
    Dim fieldIndicators As Variant, Headers As Variant
    Dim outRRay As Variant
    Dim lookRow As Long, putRow As Long, putCol As Long
    Dim testVal As String, putVal As String
    
    fieldIndicators = Array("N", "EMAIL*WORK*", "EMAIL*HOME*", "TEL*WORK*", "TEL*CELL*", "TEL*HOME*", "*URL*", "CATEGORIES*", "*.ADR*")
    Headers = Array("Name", "WorkE-mail", "HomeE-Mail", "WorkPhone", "CellPhone", "HomePhone", "URL", "Category", "Address")
    On Error GoTo HaltRoutine
    
    With newWorkbook.Sheets(1).Range("A:A")
        With Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp))
            .TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _
            TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
            Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar _
            :=":", FieldInfo:=Array(Array(1, 1), Array(2, 1))
        End With
        With Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp))
            Rem rejoin colon delimited data
            With .Offset(0, 3)
                .FormulaR1C1 = "=RC[-2]&IF(LEN(RC[-1])=0,"""","":""&RC[-1])"
                .Value = .Value
            End With
            .Offset(0, 1).Resize(, 2).Delete shift:=xlToLeft
            
            Rem rearrange data
            ReDim outRRay(Application.CountIf(.Cells, "BEGIN"), 1 To UBound(Headers) + 1)
            For lookRow = 1 To .Rows.Count
                testVal = .Cells(lookRow, 1).Value
                putVal = .Cells(lookRow, 2).Value
                If testVal = "BEGIN" Then
                    putRow = putRow + 1
                Else
                    For putCol = 0 To UBound(fieldIndicators)
                        If testVal Like fieldIndicators(putCol) Then
                            outRRay(putRow, putCol + 1) = putVal
                            Exit For
                        End If
                    Next putCol
                End If
            Next lookRow
        
            Rem write to sheet
            With .Parent.Range("C1")
                .Resize(1, UBound(Headers) + 1).Value = Headers
                .Offset(1, 0).Resize(UBound(outRRay, 1), UBound(outRRay, 2)).Value = outRRay
            End With
            Rem remove old data
            .Resize(, 2).EntireColumn.Delete
        End With
    End With
    On Error GoTo 0
    Exit Sub
HaltRoutine:
    On Error GoTo 0
    MsgBox "There is a problem with the imported data."
    End
End Sub

Private Sub ImportFromAddressBook(Optional argument As Boolean)
    Dim pathStr As String
    
    pathStr = Application.GetOpenFilename
    
    If Not (pathStr = "False") Then
        On Error GoTo HaltRoutine
        Set newWorkbook = Workbooks.Open(pathStr)
    End If
    On Error GoTo 0
    Exit Sub
HaltRoutine:
    On Error GoTo 0
    MsgBox "File Error"
    End
End Sub

Function NumbersOnly(ByVal inputString As String) As Double
Dim i As Long, oneChar As String, outStr As String
inputString = "a" & inputString
For i = 1 To Len(inputString)
    oneChar = Mid(inputString, i, 1)
    If oneChar Like "[0-9]" Then
        outStr = outStr & oneChar
    End If
Next i
NumbersOnly = Val(outStr & ".0")
End Function

Function CleanDelimiters(ByVal inputString As String, Optional Delimiter As String) As String
If Delimiter = vbNullString Then Delimiter = ";"
inputString = Trim(inputString)
If Left(inputString, 1) = Delimiter Then
    CleanDelimiters = CleanDelimiters(Mid(inputString, 2), Delimiter)
Else
    CleanDelimiters = Application.Trim(Application.Substitute((Application.Substitute(inputString, Delimiter, ", ", 1)), ";", " "))
End If
End Function
 
Upvote 0
Mike - Firstly, thanks so much for all your efforts. I hope you are getting something out of this as well (fun, learning, etc).

As to this code, it calls to "ParsingAddress.xls". Not sure what that is, but figued you might? :)

Also, after cancelling on that call (as if that wouldn't have any detrimental effect) I got error 13 on
Code:
 With Range(.Cells(2, rangeWidth), Cells(.Rows.Count, rangeWidth))
 
Upvote 0
ParsingAddresses was the name of the worksheet in which this code was written. That line puts a UDF into a formula in a cell in the new workbook and so the location of the UDF need to be inculded in the function call. Replacing that line with
Code:
.Offset(0, rangeWidth).FormulaR1C1 = "=" & ThisWorkbook.Name & "!CleanDelimiters(RC[-" & .Columns.Count & "])"
should fix things.

The other line just needs full qualification (a dot before the second Cells)
Code:
With Range(.Cells(2, rangeWidth), .Cells(.Rows.Count, rangeWidth))

This project has been great for me. Working on the (unsolved) import is teaching me a lot about Scripting and automation on the Mac.
 
Upvote 0
Mike, glad to hear you're having fun too. That said............

leading intp this section of parseNewWorksheet sub:
Code:
            Rem remove semi-colons
            .Offset(0, rangeWidth).FormulaR1C1 = "=TRIM(SUBSTITUTE(RC[-" & .Columns.Count & "],"";"","" ""))"
            .Offset(0, rangeWidth).FormulaR1C1 = "=" & "GroupvCards.vcf" & "!CleanDelimiters(RC[-" & .Columns.Count & "])"
the new worksheet has the nine columns with correct headers in A1:I1. Data beneath looks fine also.
After the first .offset line, the nine columns have been duplicated in J1:R1, with semicolons removed.
After the second .offset line, J1:R1088 all display "#NAME?". J1 contains
Code:
=GroupvCards.vcf!CleanDelimiters(A1)
Seems to be that "CleanDelimiters" reference. Is that a sub I'm missing?
 
Upvote 0
CleanDelimiters is the last function in the code of post#32.

It looks like you substituted a hardcoded name "GroupvCards.vcf" for the ThisWorkbook.Name in the formula.

If that is to be hard-coded it should be the name of the excel workbook in which the code resides, (e.g."ParsingAddress.xls") not the name of the new workbook and not the name of the file being imported.

I'd suggest leaving it as
Code:
.Offset(0, rangeWidth).FormulaR1C1 = "=" & ThisWorkbook.Name & "!CleanDelimiters(RC[-" & .Columns.Count & "])"
so that Saving your boss workbook As doesn't require changing the code.
 
Last edited:
Upvote 0
Okay, went back to ThisWorkbook.Name.
Now here's what's happening: I have created a new workbook called Import.xls and pasted your code into the ThisWorkbook section of the code area.
I run the MainRoutine(). In Sub ImportFromAddressBook I am prompted to select my text file of address book data with Application.GetOpenFilename.
Then,
Code:
Set newWorkbook = Workbooks.Open(pathStr)
creates a new workbook called "GroupvCards.vcf" according to the name of my database text file of address book info.
So when .Offset......ThisWorkbook.Name runs, it is modifying cells in GroupvCards.vcf as I indicated earlier, but those cells now have this formula: "=import.xls!CleanDelimiters(A1)" (and A2, A3, etc).
So cells in GroupvCards.vcf are "calling" to a function in "import.xls" and it doesn't seem to be making connection.
Does that make sense?
 
Upvote 0

Forum statistics

Threads
1,222,554
Messages
6,166,760
Members
452,069
Latest member
myanis72

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top