EXCEL VBA: THE MARCO TO COPY DATA TO MERGED CELLS

Overview

Help me improve my English!
As you probably see, I'm not a native English speaker.
If you find an English expression that feel incorrect or awkward, please let me know.

Message box of Disqus is under the article.
Or my E-Mail is here.

ABOUT THIS ARTICLE

In Excel, when copying data from normal cells to merged ones, we'll encounter a warning that says 'We can't do that to merged cells' and are prohibited to do copy-paste.

For example, in image below we try to copy a green range of 'Valerie'-'Terry' to Name column in the table, and then we'll get a error.

Copy Trial

Get a Error

To avoid this, in advance the pasted cells must be th same merging-style as copied cells, or we must create a dedicated macro.
This article describes the latter.

CREATION ENVIRONMENT

  • windows10
  • MSOffice 2016

REQUIREMENT

  1. Before the macro runs, the user copy data of target cells to clipboard.
    And after running the cells the user is selecting at that time will get data from clipboard.
  2. It can work with any format-style of both copied or pasted cells.
  3. In fact, the individual cell which make up a merged cell is empty except for top left cell.
    So it's desiable for the macro to ignore empty cells.

PROCESSING FLOW

Processing Flow

CODES

SUB PROCEDURE: COPY_TO_MERGED_CELLS

  1'******************************************************************************************
  2'*Function : copy from cells to cells
  3'            both source cells and destination cells can be normal or merged
  4'******************************************************************************************
  5Public Sub copyToMergedCells()
  6    
  7    'Consts
  8    Const FUNC_NAME As String = "copyToMergedCells"
  9    
 10    'Vars
 11    Dim arr() As Variant
 12    Dim row As Long: row = 0
 13    Dim col As Long: col = 1
 14    Dim dicIgnoreRow As Object: Set dicIgnoreRow = CreateObject("Scripting.Dictionary")
 15    Dim dicIgnoreCol As Object: Set dicIgnoreCol = CreateObject("Scripting.Dictionary")
 16    
 17    On Error GoTo ErrorHandler
 18        
 19    'check if the data is in text format.
 20    If Application.ClipboardFormats(1) <> xlClipboardFormatText Then MsgBox "The data in the clipboard is not in text format.", vbExclamation, FUNC_NAME: GoTo ExitHandler
 21        
 22    'step 1. move data from clipboard to 2-dimensional array
 23    '   delimiter of rows   : vbCrLf (Carriage return & Line feed)
 24    '   delimiter of columns: vbTab (Tab key)
 25    With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
 26        
 27        .GetFromClipboard
 28        Dim c, d
 29        ReDim arr(1 To 1, 1 To 1)
 30        For Each c In Split(.GetText, vbCrLf)
 31            row = row + 1
 32            If row > 1 Then arr = redimPreserveFor1stDimension(arr, row)
 33            'currentCol: the index of the column currently being stored
 34            Dim currentCol As Long: currentCol = 0
 35            For Each d In Split(c, vbTab)
 36                currentCol = currentCol + 1
 37                If currentCol > col Then
 38                    col = col + 1
 39                    ReDim Preserve arr(1 To row, 1 To col)
 40                End If
 41                arr(row, currentCol) = Trim(d)
 42            Next d
 43        Next c
 44    End With
 45    
 46    'step 2. Record the rows and columnswhose cells is all emnpty
 47    '   Ignore them when pasting is done.
 48    
 49    'check rows
 50    Dim i, j As Long
 51    Dim isIgnore As Boolean
 52    For i = 1 To UBound(arr)
 53        isIgnore = True
 54        For j = 1 To UBound(arr, 2)
 55            'the row isn't ignored if target element isn't empty
 56            If Trim(arr(i, j)) <> "" Then isIgnore = False: Exit For
 57        Next j
 58        If isIgnore Then dicIgnoreRow.Add i, True
 59    Next i
 60    'check columns
 61    For j = 1 To UBound(arr, 2)
 62        isIgnore = True
 63        For i = 1 To UBound(arr)
 64            'the column isn't ignored if target element isn't empty
 65            If Trim(arr(i, j)) <> "" Then isIgnore = False: Exit For
 66        Next i
 67        If isIgnore Then dicIgnoreCol.Add j, True
 68    Next j
 69    
 70    'step 3. paste the array starting from the selected top left cell
 71    Dim k, l As Long
 72    Dim r, tmp As Range
 73    Set r = Selection(1)
 74    For k = 1 To UBound(arr): Do
 75        'continue if the row must be ignored
 76        If dicIgnoreRow.exists(k) Then Exit Do
 77        'store the current range object
 78        Set tmp = r
 79        
 80        For l = 1 To UBound(arr, 2): Do
 81            'continue if the column must be ignored
 82            If dicIgnoreCol.exists(l) Then Exit Do
 83            'paste a value
 84            r.Value = arr(k, l)
 85            'move the paste destination cell one column to the right
 86            Set r = r.Offset(, 1)
 87        Loop While False: Next l
 88        'move the paste destination cell one row to the below
 89        Set r = tmp.Offset(1)
 90    Loop While False: Next k
 91    
 92    Application.CutCopyMode = False
 93    
 94ExitHandler:
 95
 96    Exit Sub
 97    
 98ErrorHandler:
 99
100    MsgBox "An error has occurred and the macro will be terminated." & _
101           vbLf & _
102           "Func Name:" & FUNC_NAME & _
103           vbLf & _
104           "Error No." & Err.Number & vbNewLine & _
105           Err.Description, vbCritical, "Macro"
106        
107    GoTo ExitHandler
108        
109End Sub
110

FUNCTION PROCEDURE: REDIM_PRESERVE_FOR_1ST_DIM

 1'******************************************************************************************
 2'*Function: expantion of Redim Preserve statement
 3'           Redim Preserve statement can't change the length of first dimension of 2-dimensional array.
 4'           Thus the function works well in such case.
 5'*Arg     : target array
 6'*Arg     : upper limit on the number of elements in the first dimension 
 7'*Return  : True > normal termination; False > abnormal termination
 8'******************************************************************************************
 9Private Function redimPreserveFor1stDimension(ByVal arr As Variant, ByVal sLen As Long) As Variant
10    
11    'Consts
12    Const FUNC_NAME As String = "redimPreserveFor1stDimension"
13    
14    'Vars
15    Dim tspsedArr As Variant
16        
17    On Error Resume Next
18    
19    'transpose target array
20    tspsedArr = WorksheetFunction.Transpose(arr)
21    'step A. Redim the second dimension of the array to the length of argument number
22    ReDim Preserve tspsedArr(1 To UBound(tspsedArr, 1), 1 To sLen)
23
24    redimPreserveFor1stDimension = WorksheetFunction.Transpose(tspsedArr)
25    
26    'step B. if the array is '1 * N' style, by being transposed it turns 1-dimensional array and a error occurs at the step A.
27    '   Instead, at that case, the error will be ignored and the following process replaces it.
28    If Err.Number = 9 Then
29        Dim newArr As Variant
30        Dim i As Long
31        Err.Clear
32        On Error GoTo ErrorHandler
33        ReDim newArr(1 To UBound(arr, 1) + 1, 1 To 1)
34        'reflect a existing value to new array
35        For i = 1 To UBound(arr, 1)
36            newArr(i, 1) = arr(i, 1)
37        Next i
38        redimPreserveFor1stDimension = newArr
39    End If
40    
41ExitHandler:
42
43    Exit Function
44    
45ErrorHandler:
46
47    MsgBox "An error has occurred and the macro will be terminated." & _
48           vbLf & _
49           "Func Name:" & FUNC_NAME & _
50           vbLf & _
51           "Error No." & Err.Number & vbNewLine & _
52           Err.Description, vbCritical, "Macro"
53        
54    GoTo ExitHandler
55        
56End Function

HOW TO USE

  1. Copy the range you want.
  2. Select the top left cell of the range in which you want to paste.
  3. Run the function.

DEMO

I. FORM NORMAL CELLS TO MERGED CELLS

As you can see below,
after copying 'Valerie'-'Terry' by pressing ctrk + c and so on, then select the Name cell of No.5 row and run the macro.
Then name cells will be filled with the data you copied.

Before Running

After Running

II. FROM MERGED CELLS TO NORMAL CELLS

As you can see below,
you can copy data from address column No1-4 and paste it to blue area.

Before Running

After Running

III. FROM MERGED CELLS TO MERGED CELLS

Even if both range consist of merged cells, it works.

Data of the orange color area can be pasted to the range of Address cells of No.5-7.

Before Running

After Running

See Also

comments powered by Disqus

Translations: