I am trying to rename some pdf files with this kind of name: "2020-01-24-GOOGLE.NY-JPM-XXXXXXXXX.pdf"
into: "2020 01 24 - GOOGLE - JPM - 30p.pdf" with 30p meaning 30 pages (the number of pages in the pdf file).
The structure of the name is always the same, only the letters / numbers change.
I have already prepared some code (that you can find below), yet I am struggling with two things:
How can I "extract" the Broker name, (here JPM)
How can I get the number of pages in the pdf ? I have seen some solutions on the forum requiring Adobe Pro, yet I do not have access to it
Do you have any ideas to solve this problem ?
Here is the code:
Sub FetchName()
Dim nameArray() As Variant
Dim renameArray() As Variant
Dim myPath As String
Dim myFile As String
Dim r As Integer
Dim Year As String
Dim Month As String
Dim Day As String
Dim Company As String
Dim Broker As String
Dim NPage As String
Dim numElements As Integer
Dim s As Integer
Dim t As Integer
Dim AcroDoc As Object
Dim StartNum As Integer
Dim numCar As Integer
'get two inputs
myPath = Worksheets("Cover").Cells(3, 4)
Company = Worksheets("Cover").Cells(3, 2)
'get names in an array
myFile = Dir(myPath & "*.pdf")
r = 1
Do While myFile <> ""
ReDim Preserve nameArray(r)
nameArray(UBound(nameArray)) = myFile
r = r + 1
myFile = Dir
Loop
numElements = UBound(nameArray) - LBound(nameArray) + 1
'prepare array with new names
s = 1
For s = 1 To numElements
Year = Left(nameArray(s), 4)
Month = Mid(nameArray(s), 6, 2)
Day = Mid(nameArray(s), 9, 2)
StartNum = InStr(1, Replace(nameArray(s), "-", "~", 4), "~")
numCar = InStr(1, Replace(nameArray(s), "-", "~", 5), "~") - InStr(1, Replace(nameArray(s), "-", "~", 4), "~") + 1
Broker = Mid(nameArray(s), StartNum, numCar)
'numpage
'ReDim Preserve renameArray(r)
'renameArray(UBound(renameArray)+1) = Year & " " & Month & " " & Day & " - " & Company & " - " & Broker & " - " & NPage & "p"
s = s + 1
Next s
'rename files with renameArray
t = 1
For t = 1 To numElements
Name myPath & nameArray(1) As myPath & renameArray(1)
t = t + 1
Next t
End Sub
enter code here
For the Broker name, you can use InStrRev to search for the position of the last and second last dashes:
namePDF = "2020-01-24-GOOGLE.NY-JPM-XXXXXXXXX.pdf"
lastDashAt = InStrRev(namePDF, "-")
secondLastDashAt = InStrRev(namePDF, "-", lastDashAt - 1)
Broker = Mid(namePDF, secondLastDashAt + 1, lastDashAt - secondLastDashAt - 1)
Related
my string may have short or long name like below
short: String = "Stack Over Flow"
long: String = "Stack Over Flow Access VBA Coding"
now I need to split this string into 2 groups as
1st group will have first 3 words Stack Over Flow and 2nd group will have Access VBA Coding
if the string is short then 2nd group will have blank
below code does not work need your help
Dim str As String, Result As String
Dim Start_Point As Long, No_Characters As Long
str = cmbName.Text
Start_Point = InStr(str, " ") + 1
No_Characters = Len(str) - Start_Point
group1 = Left(str, No_Characters + 1)
group2 = Right(str, No_Characters + 1)
MsgBox group1 & " - " & group2
Try using Limit parameter of Split function like this
Private Function SplitInTwo(sText As String) As Variant
Dim vSplit As Variant
Dim sSecond As String
vSplit = Split(sText, " ", Limit:=4)
If UBound(vSplit) >= 3 Then
sSecond = vSplit(3)
ReDim Preserve vSplit(0 To 2) As String
End If
SplitInTwo = Array(Join(vSplit, " "), sSecond)
End Function
Here are some use-cases
Dim vParts As Variant
vParts = SplitInTwo("Stack Over Flow")
Debug.Print vParts(0) & " - " & vParts(1) '--> Stack Over Flow -
vParts = SplitInTwo("Stack Over Flow Access VBA Coding")
Debug.Print vParts(0) & " - " & vParts(1) '--> Stack Over Flow - Access VBA Coding
I'm trying to open the most recent file in a folder. In this folder, we have a lot of versions of different files, separated by date and time in the file name.
I can't figure out how to separate by the hour of modification.
The format is like this "Raio X - Grafico - 17.09.2018 07.39.pdf". The only thing that changes is the date and the hour, in the end of the name of the file, every new version.
Dim FileSys, objFile, myFolder, c As Object
Dim Fldname As String
Dim FPath As String
Dim FileN As String
Dim MDataFile As String
Dim Date1 As Date
Dim RDate As String
Dim Hour1 As Date
Dim RHour As String
Date1 = Now()
RDate = Format(Date1, "dd.mm.yyyy")
Hour1 = Time
RHour = Format(Hour1, " hh.mm")
FPath = "R:\TL - Comando de Montagem - Relatorios Internos\Raio X"
FileN = FPath & "\" & "Raio X - Grafico - " & RDate & RHour & ".pdf"
ActivePresentation.FollowHyperlink _
Address:=FileN, _
NewWindow:=True, AddHistory:=True
End Sub
I need to compare the System Hour with the hour of the files in the folder.
Since the positions are at a fixed distance from the end, you can use the Mid and Len functions.
Here's an example:
FileName = "Raio X - Grafico - 17.09.2018 07.39.pdf"
FileHour = Mid(FileName, Len(FileName) - 8, 2)
FileMinute = Mid(FileName, Len(FileName) - 5, 2)
I have a macro which pass through paragraphs of a word document. This code is intended to pass the paragraph, identify its outline level and retrieve the content when the desired paragraph outline level is found. With this information, I'm populating a listbox that will allow users to choose from what point they want to export some text in a document.
This functionality is working, however, I'm looking for a way to improve its speed. Right now I'm handling a document with 5678 paragraphs, and it is taking over 30 minutes to process all the information. Do you have any suggestion?
I had tried to approaches without having success:
1 - I've tried to use the object TableOfContents, however I was not able to have a clean information and differentiate outline levels from the paragraphs.
2 - I've tried to adapt the code from here Getting the headings from a Word document, specially because of the use of the command _docSource.GetCrossReferenceItems(wdRefTypeHeading), also with no success
Here there is the image of the form, and the code I'm using.
Sub ProcessHeaders()
Dim j As Long
Dim Paragraph_Number() As Variant
Dim Paragraph_Content() As Variant
Dim Paragraph_Mapping() As Variant
j = 1
With UserForm1
If .ComboBox4.ListCount > 0 Then
.ComboBox4.Clear
End If
For i = 1 To wordDoc.Paragraphs.Count
If wordDoc.Paragraphs.Item(i).OutlineLevel = wdOutlineLevel1 _
Or wordDoc.Paragraphs.Item(i).OutlineLevel = wdOutlineLevel2 _
Or wordDoc.Paragraphs.Item(i).OutlineLevel = wdOutlineLevel3 _
Or wordDoc.Paragraphs.Item(i).OutlineLevel = wdOutlineLevel4 Then
If wordDoc.Paragraphs.Item(i).Range.ListFormat.ListString <> "" Then
ReDim Preserve Paragraph_Number(j)
ReDim Preserve Paragraph_Content(j)
Paragraph_Content(j) = wordDoc.Paragraphs.Item(i).Range.ListFormat.ListString & " " & Trim(Left(wordDoc.Paragraphs.Item(i).Range.Text, (Len(wordDoc.Paragraphs.Item(i).Range.Text) - 1)))
Paragraph_Number(j) = i
j = j + 1
End If
End If
Next i
ReDim Preserve Paragraph_Mapping(1 To UBound(Paragraph_Content), 1)
For i = 1 To UBound(Paragraph_Number)
Paragraph_Mapping(i, 0) = Paragraph_Content(i)
Paragraph_Mapping(i, 1) = Paragraph_Number(i)
Next i
.ComboBox4.List = Paragraph_Mapping
End With
End Sub
Edit 1 - I Achieve to reduce the time from 32 minutes to 8 minutes of execution with the code below. Any suggestions to improve even more? Thanks in advance
Sub ProcessHeaders()
Dim j As Long
Dim thisOutlineLevel As WdOutlineLevel
Dim thisHeader As String
Dim thisList As String
Dim ParagraphCount As Long
Dim Paragraph_Number_Base() As Variant
Dim Paragraph_Content_Base() As Variant
Dim Paragraph_ListItem_Base() As Variant
Dim ParagraphContent() As Variant
Dim ParagraphNumber() As Variant
Dim Paragraph_Mapping() As Variant
Dim StartTime As Double
Dim MinutesElapsed As String
j = 1
With UserForm1
If .ComboBox4.ListCount > 0 Then
.ComboBox4.Clear
End If
ParagraphCount = wordDoc.Paragraphs.Count
ReDim Paragraph_Content_Base(ParagraphCount + 1)
ReDim Paragraph_ListItem_Base(ParagraphCount + 1)
ReDim Paragraph_Number_Base(ParagraphCount + 1)
StartTime = Timer
For i = 1 To ParagraphCount
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
UserForm1.Label7.Caption = "Reading Paragraphs. " & Format(i / ParagraphCount, "0%") & " | Total of Paragraphs Found: " & ParagraphCount & " | Time Elapsed: " _
& MinutesElapsed & " Minutes"
With wordDoc.Paragraphs.Item(i)
Select Case .OutlineLevel
Case wdOutlineLevelBodyText
GoTo ResumeNext
Case wdOutlineLevel1, wdOutlineLevel2, wdOutlineLevel3, wdOutlineLevel4
Paragraph_Content_Base(i) = .Range.Text
Paragraph_ListItem_Base(i) = .Range.ListFormat.ListString
Paragraph_Number_Base(i) = i
End Select
End With
ResumeNext:
Next i
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
UserForm1.Label7.Caption = ParagraphCount & " read on " & MinutesElapsed & " Minutes. Now, identifying the Headers"
For i = 0 To UBound(Paragraph_Content_Base)
If Paragraph_Content_Base(i) <> "" And Paragraph_ListItem_Base(i) <> "" Then
ReDim Preserve ParagraphContent(j)
ReDim Preserve ParagraphNumber(j)
ParagraphContent(j) = Trim(Paragraph_ListItem_Base(i)) & " " & Trim(Left(Paragraph_Content_Base(i), Len(Paragraph_Content_Base(i)) - 1))
ParagraphNumber(j) = Paragraph_Number_Base(i)
j = j + 1
End If
Next i
Erase Paragraph_Content_Base
Erase Paragraph_ListItem_Base
Erase Paragraph_Number_Base
ReDim Preserve Paragraph_Mapping(1 To UBound(ParagraphContent), 1)
For i = 1 To UBound(ParagraphNumber)
Paragraph_Mapping(i, 0) = ParagraphContent(i)
Paragraph_Mapping(i, 1) = ParagraphNumber(i)
Next i
.ComboBox4.List = Paragraph_Mapping
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
UserForm1.Label7.Caption = "Identifying Headers: " & j & " identified. Total Time: " & MinutesElapsed & " minutes"
End With
Edit 2 - With the Help of Cindy, the code which was initially running in 32 minutes right now is running on 32 seconds. Here is the final Code.
Sub ProcessHeaders()
Dim rng As Word.Range
Dim para As Word.Paragraph
Dim lstFormat As Word.ListFormat
Dim paraNr() As Variant
Dim paraContent() As Variant
Dim counter As Long, paraIndex As Long
Dim Paragraph_Mapping() As Variant
Dim ParagraphCount As Long
Dim i, j As Long
Dim StartTime As Double
Dim StartRealTime As Date
Dim MinutesElapsed As String
With UserForm1
If .ComboBox4.ListCount > 0 Then
.ComboBox4.Clear
End If
counter = 1
paraIndex = 1
i = 0
j = 1
StartTime = Timer
StartRealTime = Now
Set rng = wordDoc.Content
ParagraphCount = rng.ListParagraphs.Count
For Each para In rng.ListParagraphs
i = i + 1
Set lstFormat = para.Range.ListFormat
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
.Label7.Caption = "Reading Paragraphs. " & Format(i / ParagraphCount, "0%") & " | Total of Paragraphs Found: " & ParagraphCount & _
" | Start Time: " & StartRealTime & " | Time Elapsed: " & MinutesElapsed & " Minutes"
'CheckOutLine = rng.ListParagraphs.Item(1).OutlineLevel
If lstFormat.ListString <> "" And Len(lstFormat.ListString) >= 2 Then
ReDim Preserve paraNr(counter)
ReDim Preserve paraContent(counter)
paraContent(counter) = lstFormat.ListString & " " _
& Trim(Left(para.Range.Text, (Len(para.Range.Text) - 1)))
paraNr(counter) = i
wordDoc.Bookmarks.Add Name:="ExpContent" & i, Range:=para.Range
counter = counter + 1
End If
paraIndex = paraIndex + 1
Next
j = 1
ReDim Preserve Paragraph_Mapping(1 To UBound(paraNr), 1)
For i = UBound(paraNr) To 1 Step -1
Paragraph_Mapping(j, 0) = paraContent(i)
Paragraph_Mapping(j, 1) = paraNr(i)
j = j + 1
Next i
.ComboBox4.List = Paragraph_Mapping
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
.Label7.Caption = "Identifying Headers: " & j & " identified. Total Time: " & MinutesElapsed & " minutes"
End With
'
' For counter = 1 To UBound(paraNr)
' Debug.Print paraNr(counter) & vbTab & paraContent(counter)
' Next
End Sub
And After the user choose the paragraph, the bookmarks are being managed by this call
With objWord.Selection
BookmarkID = "ExpContent" & PositionReference
wordDoc.Bookmarks(BookmarkID).Select
.InsertParagraphBefore
End With
Once again, thank you
I think the fastest approach is going to be looping only the numbered paragraphs, rather than all paragraphs. This can be done using the ListParagraphs object. For example:
Sub IdOutlineLevels()
Dim rng As word.Range
Dim para As word.Paragraph
Dim lstFormat As word.ListFormat
Dim paraNr() As Variant
Dim paraContent() As Variant
Dim counter As Long, paraIndex As Long
counter = 1
paraIndex = 1
Set rng = ActiveDocument.content
For Each para In rng.ListParagraphs
Set lstFormat = para.Range.ListFormat
Select Case lstFormat.ListLevelNumber
Case 1, 2, 3, 4
If lstFormat.ListString <> "" Then
ReDim Preserve paraNr(counter)
ReDim Preserve paraContent(counter)
paraContent(counter) = lstFormat.ListString & " " _
& Trim(Left(para.Range.Text, (Len(para.Range.Text) - 1)))
paraNr(counter) = paraIndex
counter = counter + 1
ActiveDocument.Bookmarks.Add Name:="ExpContent" & counter, Range:=para.Range
End If
Case Else
End Select
paraIndex = paraIndex + 1
Next
For counter = 1 To UBound(paraNr)
Debug.Print paraNr(counter) & vbTab & paraContent(counter)
Next
End Sub
Rather than relying on the index number of the paragraph in the document to locate the paragraph again I've added bookmarks to each of the paragraphs using the same "counter" as the paragraph number. This is the technique Word, itself, uses for cross-referencing.
I'm currently using the below code in a VB.Net console app that takes the contents of a text file and extracts certain info and then exports it to a CSV.
All seems to work well but the problem is the file originally comes through as a PDF (only option possible) and i have to manually open the file in Adobe and 'Save as Text'.
Is there a way of either automating the conversion of PDF to text file or reading the PDF in place of the text file.
Any guidance or options would be appreciated
Dim iLine, iEnd, c, iField As Integer
Dim iSecs, iMax As Long
Dim sText, sTemp, sSchema As String
Dim sHotel, sEndDate, sMon, sPLU, sTots, sValue, sDept, sFile, sOutFile, sDesc As String
Dim tdate As Date
Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\temp\TX.accdb;")
Dim LUse As Boolean
sHotel = "Unknown Hotel"
sEndDate = "01/01/2015"
sMon = "MAR"
sPLU = ""
sTots = "0"
sValue = "0"
sDept = "Unknown Dept"
sDesc = ""
LUse = True
sTemp = ""
iField = 0
sSchema = "Chester"
'Open input file
sFile = "c:\temp\input.txt"
Dim InFile As New System.IO.StreamReader(sFile)
'Open lookup data table
con.Open()
Dim dbAdapter As OleDbDataAdapter = New OleDbDataAdapter( _
"SELECT * FROM Plookup", con)
Dim dsTX As DataSet = New DataSet()
Dim changes As DataTable
Dim cmdbuilder As OleDbCommandBuilder = New OleDbCommandBuilder(dbAdapter)
dbAdapter.FillSchema(dsTX, SchemaType.Source, "Plookup")
dbAdapter.Fill(dsTX, "Plookup")
Dim rstx As DataTable = dsTX.Tables(0)
iMax = rstx.Rows.Count
Dim productrow() As Data.DataRow
'Open Output file
iSecs = Timer
sOutFile = "c:\temp\TX" & Format$(Now, "yymmdd") & Trim$(Str$(iSecs)) & ".csv"
FileCopy(sFile, "c:\temp\TX" & Format$(Now, "yymmdd") & Trim$(Str$(iSecs)) & ".txt")
Dim OutFile As New System.IO.StreamWriter(sOutFile)
'Write header
OutFile.WriteLine("outlet,dept,epos,tots sold,total price,date of sales")
iLine = 0
Do While InFile.Peek() <> -1
'Read in text
iLine = iLine + 1
sText = InFile.ReadLine
sText = sText.Replace(",", "")
If Len(sText) > 2 And Len(sText) < 9 Then
If Mid$(sText, 3, 1) = "-" Then ' Department Name
sText = sText & Space(9 - Len(sText))
End If
End If
'Process all rows except header row - read data into array
If Len(sText) > 8 Then
Select Case Left(sText, 7)
Case "Consoli" ' Ignore
Case "Quanti " ' Ignore
Case "Group b" ' Ignore - but next row is the Hotel Name
iLine = iLine + 1
sText = InFile.ReadLine
sText = sText.Replace(",", "")
sHotel = Trim$(Left(sText, 20)) 'The username follows so we may truncate the hotel name
Case "Date ra" ' End date
sEndDate = Mid$(sText, 29, 2) & "/" & Mid$(sText, 32, 2) & "/" & Mid$(sText, 35, 4)
tdate = CDate(sEndDate).AddDays(-1)
sEndDate = tdate.ToString("dd/MM/yyyy")
Case Else 'Possible Code
If Mid$(sText, 3, 1) = "-" Then ' Department Name
sDept = Trim(sText)
Else
If IsNumeric(Left(sText, 7)) Then 'Got a code
sPLU = Trim(Str(Val(Left(sText, 7))))
'We don't know where the description ends as it contains spaces
'So best way is to start at the end and work back...
iEnd = Len(sText)
iField = 0
For c = iEnd To 9 Step -1
If Not (Mid(sText, c, 1) = " ") Or iField > 10 Then
sTemp = Mid(sText, c, 1) & sTemp
Else
iField = iField + 1
If iField = 9 Then
sValue = sTemp
ElseIf iField = 11 Then
sTots = sTemp
End If
sTemp = ""
End If
Next
If iField = 10 Then
sTots = Trim(sTemp)
sDesc = ""
Else
sDesc = Trim$(sTemp)
End If
'lookup code
productrow = rstx.Select("FileID = 'Chester' and PLU = '" & sPLU & "'")
If productrow.Length = 0 Then ' product not found
iMax = iMax + 1
rstx.Rows.Add(sSchema, sPLU, sDesc, False)
LUse = True
Else
LUse = Not productrow(0)("Exclude")
End If
If (Val(sTots) + Val(sValue) > 0) And LUse Then ' We have a non-zero sale or value and it is not excluded
OutFile.WriteLine(sHotel & "," & sDept & "," & sPLU & "," & sTots & "," & sValue & "," & sEndDate)
End If
End If
End If
End Select
End If
Loop
'dbAdapter.Update(dsTX.Tables(0))
'Close input / output csv files
'rstx.Rows.Add("303030", "Another Test", False)
dbAdapter.UpdateCommand = cmdbuilder.GetUpdateCommand(True)
dbAdapter.InsertCommand = cmdbuilder.GetInsertCommand(True)
dbAdapter.DeleteCommand = cmdbuilder.GetDeleteCommand()
changes = rstx.GetChanges()
If changes IsNot Nothing Then dbAdapter.Update(changes)
InFile.Close()
OutFile.Close()
con.Close()
Try itextSharp. itextSharp is a .NET DLL with the help of which you can extract content from PDF. Click here for reference & sample code(although code is in c#, its just a reference to give you an idea).
I'm a graphic artist, new to Excel and VBA but trying to use it to process mountains of data in excel to be used as variable data in Illustrator.
If I want to convert cells with product names for signs like "Budwieser, Bud Light & Bud Black Crown" to an abbreviation following the format "Budweiser_BL_BBC"
I have written a function that I thought would accomplish my task but it returns #VALUE!
Edit
To explain the logic: my idea was to take the string, split it on " & " and then split the first position of the resulting array on ", " then adding what was after the "&" to the end of the second array - this array, sProd, has the products separated into different positions of the array.
Then looping through that array and splitting each product at the spaces creating a jagged array.
Then loop through that array again creating a string taking only the first letter of each word in each product, separating products with an underscore. The exception being that the first word of the first product is spelled out and set in proper case. (Just saw an error in my logic and added the code for the first word exception).
Edit #2
The function should return a string with the first word of the original string set in proper case with all other words abbreviated to their first letter and products separated by underscores. So "Budweiser, Bud Light & Bud Light Lime" returns "Budweiser_BL_BLL", "All Coke & Dr Pepper Products" would return "AllC_DPP" and "Gatorade" returns "Gatorade".
This is my first bout with Excel and VBA.
Function Abbrev(p As String) As String
Dim sAmpersand() As Variant
Dim sProd() As Variant
sAmpersand = Split(p, " & ")
sProd = Split(sAmpersand(0), ", ")
sProd(UBound(sProd)) = sAmpersand(1)
Dim ProductCount As Integer
Dim ProductEnd As Integer
ProductEnd = UBound(sProd) - 1
For ProductCount = 0 To ProductEnd
sProd(ProductCount) = Split(sProd(ProductCount), " ")
ProductCount = ProductCount + 1
Next ProductCount
Dim WordCount As Integer
Dim WordEnd As Integer
WordEnd = UBound(sProd(ProductCount)) - 1
Abbrev = StrConv(sProd(0)(0), vbProperCase)
For ProductCount = 0 To ProductEnd
For WordCount = 0 To WordEnd
If ProductCount = 0 Then
WordCount = 1
End If
Abbrev = Abbrev & Left(sProd(ProductCount)(WordCount), 1)
WordCount = WordCount + 1
Next WordCount
If ProductCount + 1 < ProductEnd Then
Abbrev = Abbrev & "_"
End If
ProductCount = ProductCount + 1
Next ProductCount
End Function
Working code:
Function Abbrev(p As String) As String
Dim res As String, w1, w2
res = Split(Split(p, ",")(0), " ")(0)
If res = Split(p, ",")(0) Then res = res & "_"
For Each w1 In Split(Mid(Replace(p, " &", ","), Len(res) + 1), ",")
For Each w2 In Split(w1, " ")
res = res & Left(w2, 1)
Next w2
res = res & "_"
Next w1
Abbrev = IIf(Right(res, 1) <> "_", res, Left(res, Len(res) - 1))
End Function
Here's a better abbreviate function:
Function Abbreviate(Name As String) As String
Dim I As Integer
Dim sResult As String
Dim sTemp As String
I = InStr(Name, " ")
If I < 1 Then
Abbreviate = Name
Exit Function
End If
sResult = Left$(Name, I)
sTemp = Name
Do While I > 0
sTemp = Right$(sTemp, Len(sTemp) - I)
If Left$(sTemp, 1) = "(" Then
If Mid$(sTemp & "***", 3, 1) = ")" Then
sResult = sResult & " " & Left$(sTemp, 3)
Else
sResult = sResult & " " & Left$(sTemp, 1)
End If
Else
sResult = sResult & " " & Left(sTemp, 1)
End If
I = InStr(sTemp, " ")
Loop
Abbreviate = sResult
End Function
This is from user al_b_cnu on mrexcel.com
Here is a modified version to shorten up the result a bit:
Function Abbreviate(Name As String) As String
Dim I As Integer
Dim sResult As String
Dim sTemp As String
I = InStr(Name, " ")
If I < 1 Then
Abbreviate = Name
Exit Function
End If
sResult = Left$(Name, I)
sTemp = Name
Do While I > 0
sTemp = Right$(sTemp, Len(sTemp) - I)
If Left$(sTemp, 1) = "(" Then
If Mid$(sTemp & "***", 3, 1) = ")" Then
sResult = sResult & Left$(sTemp, 3)
Else
sResult = sResult & Left$(sTemp, 1)
End If
Else
sResult = sResult & Left(sTemp, 1)
End If
I = InStr(sTemp, " ")
Loop
Abbreviate = sResult
End Function