+ Reply to Thread
Results 1 to 7 of 7

Trying to make a nice Title Case

Hybrid View

  1. #1
    Valued Forum Contributor
    Join Date
    12-02-2009
    Location
    Austin, Tx
    MS-Off Ver
    Office 365 64-Bit, 2108, build 14326.21018
    Posts
    4,056

    Trying to make a nice Title Case

    I'm using a macro I found at https://excelribbon.tips.net/T010560...ain_Words.html, to create a macro that will let me apply a good Title Case to selected cells. I'm trying to use Peter Atherton's solution from the bottom of the page (code shown below). The macro works well, with one exception, which I've since found out is a feature of the PROPER function, to wit, letters following apostrophe's are capitalized. The idea is that "o'leary" should convert to "O'Leary", but the problem is "Jim's" shouldn't convert to "Jim'S". I've looked and found a possible solution, the formula
    SUBSTITUTE(PROPER(SUBSTITUTE(A1,"'","z-z")),"z-Z","'")
    , but I'm not sure how to plumb that into this function without losing all the other functionality I want to keep. Any help on this would be greatly appreciated.
    Function Title(ByVal ref As Range, Optional bFormal As Boolean = True) As String
    'Thanks to Jim Cone who pointed out that the original function _
    did not deal with hyphens & upper case words such as 'IBM' or indeed Mcs and Macs.
    'Completed 5 Jan 2015
    '
    Dim vaArray As Variant
    Dim LLo As Long, LMid As Long, LHi As Long
    Dim c As String, sTemp As Variant
    Dim i As Integer, iWrdCap As Variant
    Dim iPos As Integer, iMc As Integer, _
    iMac As Integer, iHyphen As Integer
    Dim vaLCase As Variant
    Dim Str As String, sChr As String
        
        'Is there a capitalised word in the reference? e.g. IBM or BAE _
        if so find out its position for later
        sTemp = Split(ref, " ")
        iWrdCap = ""
        For i = LBound(sTemp) To UBound(sTemp)
            If sTemp(i) = StrConv(sTemp(i), vbUpperCase) Then
                iWrdCap = i
                Exit For
            End If
        Next i
        
        ' Array contains terms that should be lower case
        vaLCase = Array("A", "Am", "An", "And", "Be", "Do", "In", "Is", _
        "Of", "On", "Or", "Than", "The", "To", "With")
        
        If bFormal Then
            c = WorksheetFunction.Proper(ref)
        Else
            c = StrConv(ref, vbProperCase)
        End If
        '=======================================
        'Special Cases
        iMac = InStr(1, c, "Mac")
        If iMac > 0 Then
            Mid(c, iMac + 3, 1) = UCase(Mid(c, iMac + 3, 1))
        End If
        
        iMc = InStr(1, c, "Mc")
        If iMc > 0 Then
            Mid(c, iMc + 2, 1) = UCase(Mid(c, iMc + 2, 1))
        End If
        
        iPos = InStr(1, c, "-On-")
        If iPos > 0 Then
            c = Replace(c, "-On-", "-on-")
        End If
        
        iHyphen = InStr(1, c, " - ")
        If iHyphen > 0 Then
            c = Replace(c, " - ", "-")
        End If
        '=======================================
        'split the words into an array
        vaArray = Split(c, " ")
        
        'i ignores the first value - that should be Proper case
        For i = 1 To UBound(vaArray)
            LLo = LBound(vaLCase)
            LHi = UBound(vaLCase)
            If Right(vaArray(i), 1) Like "[',.]" Then
                sChr = Left(vaArray(i), Len(vaArray(i)) - 1)
            Else
                sChr = vaArray(i)
            End If
            
            'Binary Search for sChr
            Do Until LLo > LHi
                'Find the midpoint of the array
                LMid = (LLo + LHi) / 2
                If sChr = vaLCase(LMid) Then
                    'sChr is found so return the location & quit loop
                    vaArray(i) = LCase(sChr)
                    Exit Do
                    
                ElseIf sChr < vaLCase(LMid) Then
                    'sFind is higher than mid-point so _
                    throw away the top half
                    LHi = LMid - 1
                Else
                    'sFind is lower than than mid-point so _
                    discard the bottom half
                    LLo = LMid + 1
                End If
            Loop
        Next i
        
        ' rebuild the sentence
        Str = ""
        For i = LBound(vaArray) To UBound(vaArray)
            If i = iWrdCap Then
                Str = Str & " " & UCase(vaArray(i))
            Else:
                Str = Str & " " & vaArray(i)
            End If
        Next i
        
        Title = Trim(Str)
    End Function
    I know I'm not stupid, but I suspect I'm a lot stupider than I think I am

  2. #2
    Administrator 6StringJazzer's Avatar
    Join Date
    01-27-2010
    Location
    Tysons Corner, VA, USA
    MS-Off Ver
    MS 365 Family 64-bit 2502
    Posts
    26,789

    Re: Trying to make a nice Title Case

    I would add code like so (insert red code after existing line of code):
            c = WorksheetFunction.Proper(ref)
            If Right(c, 2) = "'S" then
               c = mid(c, Len(c) - 2) & "'s"
            End If
    Jeff
    | | |會 |會 |會 |會 | |:| | |會 |會
    Read the rules
    Use code tags to [code]enclose your code![/code]

  3. #3
    Forum Expert
    Join Date
    11-22-2016
    Location
    Cornwall,UK
    MS-Off Ver
    office 365
    Posts
    4,240

    Re: Trying to make a nice Title Case

    The example you gave was 'S
    But are there not several more? Like: can'Nt, I'Ve, he'D etc

    Other than when it follows an unaccompanied O like O'Shannon, when would any letter following an apostrophe be capitalised?

    My example(O'Shannon) conflicts with the 'S rule
    - if all 'S converted to 's, then further code required to reinstate all of the O'Shannons etc to upper case
    Last edited by kev_; 01-19-2018 at 03:02 AM.
    Click *Add Reputation to thank those who helped you. Ask if anything is not clear

  4. #4
    Valued Forum Contributor
    Join Date
    12-02-2009
    Location
    Austin, Tx
    MS-Off Ver
    Office 365 64-Bit, 2108, build 14326.21018
    Posts
    4,056

    Re: Trying to make a nice Title Case

    Kev,
    Your objections are mine as well. it can't be just S, 'cause then we'd have "Don'T", or "You'Ve". Seems like it might be a placement issue: if it's in the back half of the word, make it lowercase, but if it's in the front half it should be capitalized.

    Actual names from my database of 15K people that would cause trouble.
    Triciana La'Chelle
    La'Shondria Shantille
    De'a Rane
    Di'Jon

    Words that PROPER violates:
    Don'T
    He'S
    Wouldn'T
    I'Ve
    He'D
    She'D
    Last edited by jomili; 01-18-2018 at 06:31 PM.

  5. #5
    Administrator 6StringJazzer's Avatar
    Join Date
    01-27-2010
    Location
    Tysons Corner, VA, USA
    MS-Off Ver
    MS 365 Family 64-bit 2502
    Posts
    26,789

    Re: Trying to make a nice Title Case

    You can develop an algorithm that covers dictionary word contractions but you'll never have an algorithm that knows the difference between La'Shondria Shantille and De'a Rane.

  6. #6
    Forum Expert
    Join Date
    11-22-2016
    Location
    Cornwall,UK
    MS-Off Ver
    office 365
    Posts
    4,240

    Re: Trying to make a nice Title Case

    Function LateAdjustments is now called from your original function (see below for minor amendment)
    - I would rather not change the original function

    This should get you close
    - you can add more replacements
    - but think through any consequences fully!!
    - the sequence may be critical
    - I have ignored your list of difficulat names most will be correct already
    - De'a Rane Replace "De'A " with De'a " (note that the final character is a space)

    Function LateAdjustments(TheString)
    
        TheString = Replace(TheString, "'S ", "'s ", , , vbTextCompare) 'note space after 's
        TheString = Replace(TheString, "O's", "O'S", , , vbTextCompare)
        TheString = Replace(TheString, "O'Clock", "o'clock", , , vbTextCompare)
        TheString = Replace(TheString, "n'T", "n't", , , vbTextCompare)
        TheString = Replace(TheString, "e'D", "e'd", , , vbTextCompare)
        TheString = Replace(TheString, "e'Ll", "e'll", , , vbTextCompare)
        TheString = Replace(TheString, "I'Ve", "I've", , , vbTextCompare)
        
        LateAdjustments = TheString
    End Function
    Function Title(ByVal ref As Range, Optional bFormal As Boolean = True) As String
    
    previous code...................
    
    Replace
        Title = Trim(Str)
    With
        Str = LateAdjustments(Trim(Str))
        Title = Str
    End Function

  7. #7
    Valued Forum Contributor
    Join Date
    12-02-2009
    Location
    Austin, Tx
    MS-Off Ver
    Office 365 64-Bit, 2108, build 14326.21018
    Posts
    4,056

    Re: Trying to make a nice Title Case

    Kev,
    Sorry it took me so long to get back. I was off work Friday and the weekend, so just getting back. I tried your solution and it rocks! As 6String Jazzer pointed out, I'll never have a 100% solution, but your methodology brings me really close. Plus, it allows me flexibility to add more criteria if needed. the only one I've added so far is Re as in "They're".
    TheString = Replace(TheString, "'Re ", "'re ", , , vbTextCompare) 'note space after 're
    Thank you so much!

    I've added my full Formatting macro below in case anyone else wants to use it. Any tips on making it more compact would be appreciated. BTW, Speedon and Speedoff are just separate subs I've made for turning calculation, screenupdating, etc. off and on.
    Sub Cells_ConvertCase()
        'in Tools to Format...
        Dim FormatChoice As String
        Dim QuestionString As String
        Dim rAcells As Range, rLoopCells As Range
        Dim Hack As VbMsgBoxResult
        Dim varFormulas As Variant
        
        'Check to make sure we have no formulas
        On Error Resume Next
        varFormulas = Selection.Cells.SpecialCells(xlCellTypeFormulas).Count
        On Error GoTo 0
        If varFormulas > 0 Then
            MsgBox "Macro is exiting because there are" & vbCrLf & _
            "formulas in the range to be worked.", vbOKOnly + vbCritical, "CAN'T PROCESS FORMULA CELLS"
            Exit Sub
        End If
        
        'Set variable to needed cells
        Hack = MsgBox("Do you want to convert your selection only?" & vbCrLf & _
        "Select NO to convert your whole used range", vbYesNoCancel, "WARNING:Slow on Large Ranges")
        On Error Resume Next    'In case of NO text constants.
        Select Case Hack
            Case vbYes
            If Selection.Cells.Count = 1 Then
                Set rAcells = Selection
            Else
                Set rAcells = Selection.SpecialCells(xlCellTypeConstants, xlTextValues)
            End If
            Case vbNo
            Set rAcells = ActiveSheet.UsedRange.SpecialCells(xlCellTypeConstants, xlTextValues)
            Case vbCancel
            Exit Sub
        End Select
        
        If rAcells Is Nothing Then
            MsgBox "Could not find any text."
            On Error GoTo 0
            Exit Sub
        End If
        
        On Error GoTo HandleErr
        QuestionString = " 1  Title Case, like Joe-Bob, Mary Margaret, Don't" & vbCrLf & vbCrLf & _
                        " 2  Proper (AKA Title), like Joe-bob, Mary Margaret, Don'T" & vbCrLf & vbCrLf & _
                        " 3  UPPER, like JOE-BOB, MARY MARGARET, DON'T" & vbCrLf & vbCrLf & _
                        " 4  lower, like joe-bob, mary margaret,don't" & vbCrLf & vbCrLf & _
                        " 5  Sentence, which capitalizes the first word."
        'Ask the user what format to apply
        FormatChoice = InputBox(QuestionString, "Enter a Case Choice for Your Data", 0)
        
        SpeedOn
        
        'based on the FormatChoice, format the selected text
        Select Case FormatChoice
            Case 1      ' Convert to Title Case
            TitleCase rAcells
            
            Case 2      ' Convert to Proper Case
            If rAcells.Count = 1 Then
                rAcells.Value = StrConv(rAcells, vbProperCase)
            Else
                With rAcells
                    .Value = Evaluate("=Index(PROPER(" & .Address & "),)")
                End With
            End If
            Case 3      ' Convert to Upper Case
            If rAcells.Count = 1 Then
                rAcells.Value = StrConv(rAcells, vbUpperCase)
            Else
                With rAcells
                    .Value = Evaluate("=Index(UPPER(" & .Address & "),)")
                End With
            End If
            
            Case 4      ' Convert to lower Case
            If rAcells.Count = 1 Then
                rAcells.Value = StrConv(rAcells, vbLowerCase)
            Else
                With rAcells
                    .Value = Evaluate("=Index(LOWER(" & .Address & "),)")
                End With
            End If
            
            Case 5      ' Convert to Sentence Case
            If rAcells.Count = 1 Then
                rAcells.Value = StrConv(rAcells, vbLowerCase)
            Else
                With rAcells
                    .Value = Evaluate("=Index(LOWER(" & .Address & "),)")
                End With
            End If
            ' code taken from http://vbamacros.blogspot.com/2007_09_01_archive.html
            For Each rLoopCells In rAcells
                s = rLoopCells.Value
                Start = True
                For i = 1 To Len(s)
                    ch = Mid$(s, i, 1)
                    Select Case ch
                        Case "."
                        Start = True
                        Case "?"
                        Start = True
                        Case "a" To "z"
                        If Start Then ch = UCase$(ch)
                        Start = False
                        Case "A" To "Z"
                        If Start Then
                            Start = False
                        Else
                            ch = LCase$(ch)
                        End If
                    End Select
                    Mid$(s, i, 1) = ch
                Next i
                rLoopCells.Value = s
            Next rLoopCells
            
            Case Else
            
            MsgBox "You chose to cancel, or picked an invalid choice." & vbCrLf & _
            "Either way, this is Goodbye for now."
            GoTo ExitSub
        End Select
        
    ExitSub:
        SpeedOff
        Exit Sub
        
    HandleErr:
        MsgBox "There's Been an Unexpected Error: " & Err & vbCrLf & _
        Err.Description & vbCrLf & _
        "Try again; if it happens again call or email John with the details."
        
        GoTo ExitSub
    End Sub
    
    Sub TitleCase(R As Range)
    ' Used by Cells_ConvertCase
    Dim Cell As Range
        For Each Cell In Intersect(R, R.Worksheet.UsedRange)
            If Not Cell.HasFormula And _
                VarType(Cell.Value) = vbString And Len(Cell.Text) Then
                Cell.Value = Title(Cell)
            End If
        Next Cell
    End Sub
    
    Function Title(ByVal ref As Range, Optional bFormal As Boolean = True) As String
    ' Used by Cells_ConvertCase/TitleCase
    'https://excelribbon.tips.net/T010560_Making_PROPER_Skip_Certain_Words.html
    'Thanks to Jim Cone who pointed out that the original function _
    did not deal with hyphens & upper case words such as 'IBM' or indeed Mcs and Macs.
    'Completed 5 Jan 2015
    '
    Dim vaArray As Variant
    Dim LLo As Long, LMid As Long, LHi As Long
    Dim c As String, sTemp As Variant
    Dim i As Integer, iWrdCap As Variant
    Dim iPos As Integer, iMc As Integer, _
    iMac As Integer, iHyphen As Integer
    Dim vaLCase As Variant
    Dim Str As String, sChr As String
        
        'Is there a capitalised word in the reference? e.g. IBM or BAE _
        if so find out its position for later
        sTemp = Split(ref, " ")
        iWrdCap = ""
        For i = LBound(sTemp) To UBound(sTemp)
            If sTemp(i) = StrConv(sTemp(i), vbUpperCase) Then
                iWrdCap = i
                Exit For
            End If
        Next i
        
        ' Array contains terms that should be lower case
        vaLCase = Array("A", "Am", "An", "And", "Be", "Do", "In", "Is", _
        "Of", "On", "Or", "Than", "The", "To", "With")
        
        If bFormal Then
            c = WorksheetFunction.Proper(ref)
        Else
            c = StrConv(ref, vbProperCase)
        End If
        '=======================================
        'Special Cases
        iMac = InStr(1, c, "Mac")
        If iMac > 0 Then
            Mid(c, iMac + 3, 1) = UCase(Mid(c, iMac + 3, 1))
        End If
        
        iMc = InStr(1, c, "Mc")
        If iMc > 0 Then
            Mid(c, iMc + 2, 1) = UCase(Mid(c, iMc + 2, 1))
        End If
        
        iPos = InStr(1, c, "-On-")
        If iPos > 0 Then
            c = Replace(c, "-On-", "-on-")
        End If
        
        iHyphen = InStr(1, c, " - ")
        If iHyphen > 0 Then
            c = Replace(c, " - ", "-")
        End If
        '=======================================
        'split the words into an array
        vaArray = Split(c, " ")
        
        'i ignores the first value - that should be Proper case
        For i = 1 To UBound(vaArray)
            LLo = LBound(vaLCase)
            LHi = UBound(vaLCase)
            If Right(vaArray(i), 1) Like "[',.]" Then
                sChr = Left(vaArray(i), Len(vaArray(i)) - 1)
            Else
                sChr = vaArray(i)
            End If
            
            'Binary Search for sChr
            Do Until LLo > LHi
                'Find the midpoint of the array
                LMid = (LLo + LHi) / 2
                If sChr = vaLCase(LMid) Then
                    'sChr is found so return the location & quit loop
                    vaArray(i) = LCase(sChr)
                    Exit Do
                    
                ElseIf sChr < vaLCase(LMid) Then
                    'sFind is higher than mid-point so _
                    throw away the top half
                    LHi = LMid - 1
                Else
                    'sFind is lower than than mid-point so _
                    discard the bottom half
                    LLo = LMid + 1
                End If
            Loop
        Next i
        
        ' rebuild the sentence
        Str = ""
        For i = LBound(vaArray) To UBound(vaArray)
            If i = iWrdCap Then
                Str = Str & " " & UCase(vaArray(i))
            Else:
                Str = Str & " " & vaArray(i)
            End If
        Next i
        
        'Title = Trim(Str)
        Str = LateAdjustments(Trim(Str))
        Title = Str
    End Function
    Function LateAdjustments(TheString)
    'Used by Function Title, Made by Kev at
    'https://www.excelforum.com/newreply.php?do=postreply&t=1216122
        TheString = Replace(TheString, "'S ", "'s ", , , vbTextCompare) 'note space after 's
        TheString = Replace(TheString, "'Re ", "'re ", , , vbTextCompare) 'note space after 're
        TheString = Replace(TheString, "O's", "O'S", , , vbTextCompare)
        TheString = Replace(TheString, "O'Clock", "o'clock", , , vbTextCompare)
        TheString = Replace(TheString, "n'T", "n't", , , vbTextCompare)
        TheString = Replace(TheString, "e'D", "e'd", , , vbTextCompare)
        TheString = Replace(TheString, "e'Ll", "e'll", , , vbTextCompare)
        TheString = Replace(TheString, "I'Ve", "I've", , , vbTextCompare)
        
        LateAdjustments = TheString
    End Function

+ Reply to Thread

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Make Upper Case in cells become lower case
    By davidx in forum Excel General
    Replies: 2
    Last Post: 12-02-2013, 08:40 AM
  2. Replies: 7
    Last Post: 11-08-2012, 03:06 PM
  3. Auto change column to Title Case
    By Zyphon in forum Excel Programming / VBA / Macros
    Replies: 4
    Last Post: 09-08-2008, 11:18 AM
  4. How can I force Title Case in a cell?
    By Zyphon in forum Excel General
    Replies: 8
    Last Post: 01-29-2008, 09:22 AM
  5. making text in Title Case automatically
    By tweety127 in forum Excel Programming / VBA / Macros
    Replies: 1
    Last Post: 06-09-2006, 07:10 PM
  6. [SOLVED] Title case for text in columns
    By Annalise Vogel in forum Excel General
    Replies: 3
    Last Post: 12-08-2005, 12:50 AM
  7. Title Case--No mail merge
    By Derek Y via OfficeKB.com in forum Excel General
    Replies: 3
    Last Post: 07-29-2005, 03:05 PM
  8. Change case from UPPER to Title Case??
    By Mamacsee in forum Excel General
    Replies: 2
    Last Post: 07-05-2005, 05:05 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts

Search Engine Friendly URLs by vBSEO 3.6.0 RC 1