Search code examples
excelvbadate

How to recolor dates without recoloring other text or numbers


I am trying to recolor black colored Dates [(RGB(0, 0, 0)] without recoloring the other text or numbers using VBA for Excel to blue [RGB(0, 112, 192)]. The dates are in the format d/m, dd/m, d/mm, dd/mm, d/m/yy, dd/m/yy, d/mm/yy, dd/mm/yy and d/m/yyyy, dd/m/yyyy, d/mm/yyyy, dd/mm/yyyy with other text, both before and after the dates. I tried to do that with this VBA code, but it needs some tweaking. What can I add to skip recoloring a 0 (zero) if it is just before a date, skip recoloring every two digit number after a date and skip recoloring numbers 3, 5 and 6 after a date if they are followed by a space or number 30 in subscript format?

Sub TestDateRecoloring()

    '### adjust these colors to suit your purpose ###
    Const FIND_CLR As Long = vbBlack  'look for "date-like" text with this color
    Const NEW_CLR As Long = vbBlue  '...and recolor the text using this color
    
    Dim c As Range
    
    For Each c In ActiveSheet.UsedRange.EntireRow.Columns("J").Cells
        RecolorDates c, FIND_CLR, NEW_CLR
    Next c
    
End Sub

Sub RecolorDates(c As Range, clr As Long, clrNew As Long)
    
    Dim col As New Collection, i As Long, iStart As Long, iLen As Long
    Dim v As String, ch As String, itm
    
    v = c.Value
    If Len(v) = 0 Then Exit Sub               'skip empty cells
    If c.HasFormula Then Exit Sub             'skip formulas
    
    For i = 1 To Len(v) 'loop over characters in cell content
        ch = Mid(v, i, 1)
        If ch = "/" Or ch Like "#" Then 'could be a character in a date?
            If c.Characters(i, 1).Font.Color = clr Then
                If iStart = 0 Then iStart = i 'save start of this run
                iLen = iLen + 1               'increment run length
            Else
                'wrong color so add any existing run
                AddAnyRun col, c, iStart, iLen
            End If
        Else
            'not a "date character" so add any existing run
            AddAnyRun col, c, iStart, iLen
        End If
    Next i
    AddAnyRun col, c, iStart, iLen 'add any remaining run
    
    For Each itm In col 'recolor all matched runs
        If itm.Text Like "*#/#*" or itm.Text Like "*##/#*" or itm.Text Like "*#/##*" or itm.Text Like "*##/##*" or itm.Text Like "*#/#/##" or itm.Text Like "*##/#/##" or itm.Text Like "*##/##/##" or itm.Text Like  "*##/##/##" or itm.Text Like "*#/#/####" or itm.Text Like "*##/##/####" or itm.Text Like "*#/##/####" or itm.Text Like "*##/##/####" Then itm.Font.Color = clrNew
    Next itm
End Sub

'add run of characters from cell `c` to `col` and reset `iStart` and `iLen`
Sub AddAnyRun(col As Collection, c As Range, ByRef iStart As Long, ByRef iLen As Long)
    If iLen > 2 Then col.Add c.Characters(iStart, iLen) 'if more than 2 characters then recolor the run
    iLen = 0       'reset start position and length
    iStart = 0
End Sub

Sample data:-
Kali Bichrom.200(BHP)+Ant.crud.200(eczema)+45 200(arthralgia)2/9/2448 200+6 200+3 200(cough)+6 30(1-1-1-vomiting)5/96 1M17/126 200+6 1M1/12/20246 10M
37 20016/548 200+6 20025/548 1M+6 1M
19/548 200+Lyco.200+6 20025/548 1M+6 1M
1/1248 200+34 200+6 20025/547 1M+6 1M
19/9630(1-1-1-vomiting)5/106 1M17/126 200+6 1M15/1/256 10M

Note: The 30 in 630(1-1-1-vomiting) in the last line is in subscript format

Whatever is in bold is actually black but not in bold in the original excel sheet and I want to recolor it blue

I am using Microsoft Office 2007, so please keep that in mind.


Solution

  • You can use regular expressions in VBA to return the substrings you consider dates, and then apply the formatting.

    You gave no rules as to the allowable date range. Examining your data showed that a range of 2000-2039 might be appropriate but this could be adjusted in the regex.

    Be sure to set the VBA reference (see first line/comment in the code)
    Note that I used RED/BOLD for the font as it displays better in the screenshot. You should change that to your desired DarkBlue

    'Set reference to Microsoft VBScript Regular Expressions 5.5
    Option Explicit
    Public Sub ChangeBlue()
       Dim DarkBlue As Long
       Dim LightBlue As Long
       Dim Cell As Range
       Dim C As Long
       
       Dim RE As RegExp, MC As MatchCollection, M As Match
       
       DarkBlue = RGB(0, 112, 192)
       LightBlue = RGB(173, 216, 230)
       
    'Initialize Regular Expressions to look for properly formatted dates
    'Note this will only include years from 2000-2039 but can be modified to include a wider range
    
    Set RE = New RegExp
    With RE
        .Global = True
        .MultiLine = True
        .Pattern = "(?:3[01]|[12][0-9]|0?[1-9])/(?:1[0-2]|0?[1-9])(?:/(?:20[0-9]\d|[0-3]\d))?"
    End With
    
    For Each Cell In Intersect(ActiveSheet.UsedRange, ActiveSheet.Range("J:J"))
        If Not Cell.HasFormula Then
            If RE.Test(Cell.Value) Then
            
            'remove existing font formats
                With Cell
                    .Font.Bold = False
                    .Font.Color = vbBlack
                End With
                  Set MC = RE.Execute(Cell.Value)
                  For Each M In MC
                        With Cell.Characters(M.FirstIndex + 1, M.Length).Font
                          .Color = vbRed 'change to dark blue for use
                          .Bold = True   'optional
                        End With
                
                Next M
            End If
        End If
    Next Cell
    
    
    End Sub
    

    enter image description here