超级神奇!一键导出Excel表格成带有边框的TXT,妈妈再也不用担心我分享数据啦!

Posted by

大家好,我是你们的Excel小助手,今天要给大家分享一个超酷的小技巧,绝对能让你成为办公室里的最靓的仔!
大家都知道Excel表格复制成txt后无法带边框,然后发现复制粘贴总是格式乱七八糟。别着急,今天我就要教你一个神奇的VBA技巧,一键导出带有管道符的TXT文件,格式整整齐齐,再也不怕txt显示不了表格啦!

代码示例

下面是实现这一功能的VBA代码,你只需要将这段代码插入到Excel的VBA编辑器中,然后运行它,即可将选中的表格区域导出为带有制表符的TXT文件。

'======================================================
'将选中区域导出为带有制表符的TXT文件,注意需要使用等宽字体(如新宋体)才能正确显示
'参数:selection,可通过给Rng重新赋值来修改要导出的区域
'生成的TXT文件路径和名称与当前文档一样
'======================================================
Public StrLength As Integer '每个单元格一行所容纳的最大字符长度
Public rng As Range '要导出的单元格区域

Sub Table()
    Dim arr() As Variant, brr() As Variant
    Dim row As Integer, Col As Integer
    Dim i As Integer, j As Integer, k As Integer
    Dim Max As Integer
    Dim cell As Range, cell2 As Range
    Dim StartRow As Integer, EndRow As Integer
    Dim StartCol As Integer, EndCol As Integer
    Dim L As Integer
    Dim n As Integer
    Dim width As Integer
    Dim crr As Variant
    Dim ColWidth() As Variant '导出后所有列的字节数
    
    
    StrLength = 16 '字符长度限制为16,即32个字节【此数值限制最大列宽】
    Set rng = Selection '设置导出的区域,默认是选中的区域
    If rng.count <= 1 Then MsgBox "不支持独立单元格的导出!": Exit Sub '错误提示
    '设置带制表符的数组的大小
    arr = rng.Value
    row = UBound(arr, 1) * 2 + 1
    Col = UBound(arr, 2) * 2 + 1
    ReDim arr(1 To row, 1 To Col)
    '生成四角框
    arr(1, 1) = "┌"
    arr(1, Col) = "┐"
    arr(row, 1) = "└"
    arr(row, Col) = "┘"
    '生成内框和内部数据
    For i = 2 To row - 1
        For j = 2 To Col - 1
            Select Case i Mod 2
            Case 1
                If j Mod 2 = 1 Then arr(i, j) = "┼"
                If j Mod 2 = 0 Then arr(i, j) = "─"
            Case 0
                If j Mod 2 = 1 Then arr(i, j) = "│"
                If j Mod 2 = 0 Then arr(i, j) = rng.Cells(i / 2, j / 2)
            End Select
        Next j
    Next i
    '生成外框
    For i = 2 To row - 1
        If i Mod 2 = 0 Then
            arr(i, 1) = "│"
            arr(i, Col) = "│"
        Else
            arr(i, 1) = "├"
            arr(i, Col) = "┤"
        End If
    Next i
    For j = 2 To Col - 1
        If j Mod 2 = 0 Then
            arr(1, j) = "─"
            arr(row, j) = "─"
        Else
            arr(1, j) = "┬"
            arr(row, j) = "┴"
        End If
    Next j
    '求列宽
    ReDim ColWidth(1 To Col)
    '单元格从右向左倒序,便于计算合并单元格的字节数
    For j = Col - 1 To 2 Step -2
        Max = 0
        For i = 2 To row - 1 Step 2 '数据所在行
            With rng.Cells(i / 2, j / 2)
                Select Case .MergeCells
                Case False '不属于合并单元格
                    L = LenB(StrConv(arr(i, j), vbFromUnicode))
                Case True '属于合并单元格
                    If .MergeArea.Column = .Column Then
                        width = 0
                        brr = .MergeArea.Value
                        If UBound(brr, 2) > 1 Then '列数>1
                            For k = 2 To (UBound(brr, 2) - 1) * 2
                                width = width + ColWidth(j + k)
                            Next k
                            '这个值应该是合并单元格上方的非合并单元格的字节数
                            L = CellWidth(i, j, rng, ColWidth) - 2 * (UBound(brr, 2) - 1) - width
                        Else '列数=1
                            L = CellWidth(i, j, rng, ColWidth)
                        End If
                    Else
                        L = 0
                    End If
                End Select
            End With
            If Max < L Then Max = L
        Next i
        If Max Mod 2 = 1 Then Max = Max + 1 '字节数必须是偶数
        ColWidth(j) = Application.Min(Max, StrLength * 2)
        If Max < StrLength * 2 Then
            ColWidth(j) = Max
        Else
            ColWidth(j) = StrLength * 2
        End If
    Next j
    '整理格式
    For j = 2 To Col - 1 Step 2 '遍历字符所在列
' If j Mod 2 = 0 Then '字符所在列
            For i = 1 To row
                L = LenB(StrConv(arr(i, j), vbFromUnicode)) '字节数
                Select Case i Mod 2
                Case 0 '如果是偶数行,即数据所在行
                    Set cell = rng.Cells(i / 2, j / 2)
                    If Not cell.MergeCells Then
                        If ColWidth(j) > L Then _
                            arr(i, j) = arr(i, j) & String(ColWidth(j) - L, " ")
                    ElseIf cell.MergeArea.Column = cell.Column Then
                        If CellWidth(i, j, rng, ColWidth) > L Then _
                            arr(i, j) = arr(i, j) & String(CellWidth(i, j, rng, ColWidth()) - L, " ")
                    ElseIf cell.MergeArea.Column <> cell.Column Then
                        arr(i, j) = ""
                    End If
                Case 1 '如果是奇数行,即制表符行
' L = LenB(StrConv(arr(i, j), vbFromUnicode)) '字节数
                    If ColWidth(j) >= L Then
                        arr(i, j) = arr(i, j) & String((ColWidth(j) - L) / 2, "─")
                    Else
                        arr(i, j) = "" '如果制表符字节数比max大则代表这一列的单元格内容都为空,则删除制表符
                    End If
                End Select
            Next i
' End If
    Next j
    '处理合并单元格
    For Each cell In rng
        If cell.MergeCells Then
            '利用数组来找到合并单元格的起始位置和结束位置
            brr = cell.MergeArea.Value
            StartRow = cell.MergeArea.row - rng.row + 1
            StartCol = cell.MergeArea.Column - rng.Column + 1
            EndRow = StartRow + UBound(brr, 1)
            EndCol = StartCol + UBound(brr, 2)
            '调用处理合并单元格子函数
            merge arr, StartRow, EndRow, StartCol, EndCol
        End If
    Next
    '处理换行符
    For Each cell In rng
        n = Len(cell) - Len(Replace(cell, Chr(10), ""))
        If n > 0 Then
            i = (cell.row - rng.row + 1) * 2
            j = (cell.Column - rng.Column + 1) * 2
            width = CellWidth(i, j, rng, ColWidth) / 2
            crr = Split(cell.Value, Chr(10))
            For k = 0 To n - 1
                L = Len(crr(k))
                Select Case L
                Case Is <= width
                    crr(k) = crr(k) & String(width - L, " ")
                Case Is > width
                    crr(k) = crr(k) & String(width - (L Mod width), " ")
                End Select
            Next k
            arr(i, j) = Join(crr, "")
' Debug.Print arr(i, j), LenB(StrConv(arr(i, j), vbFromUnicode))
            [a30] = arr(i, j)
        End If
    Next
    '处理换行
    ' 从倒数第2行开始遍历所有数据所在行,避免插入新行后对arr中未整理的行号造成影响
    i = UBound(arr, 1)
    Do While i > 1
        Max = 0
        For j = 2 To Col - 1 Step 2 '数据所在列
            L = LenB(StrConv(arr(i, j), vbFromUnicode))
            width = CellWidth(i, j, rng, ColWidth)
            If L > width And width <> 0 Then
                n = Int(Len(arr(i, j)) / (width / 2)) '换行数
                If Max < n Then Max = n
            End If
        Next j
        If Max > 0 Then InsertLine arr, i, Max '插入行
        i = i - 1 '跳至下一个数据行
    Loop
    SaveTxt arr
End Sub
'======================================================
'将表格中的某个区域导出TXT文档
'参数:数组变量
'生成的TXT文件路径和名称与当前文档一样
'======================================================
Sub SaveTxt(ByVal arr As Variant)
    Dim path As String
    Dim i As Integer, j As Integer
    Dim Str As String
    path = ThisWorkbook.path & "\" & Left(ThisWorkbook.Name, _
        Application.Find(".", ThisWorkbook.Name) - 1) & ".txt"
    Open path For Output As #1
    For i = 1 To UBound(arr, 1)
        For j = 1 To UBound(arr, 2)
            Str = Str & arr(i, j)
        Next j
        Print #1, Str
        Str = ""
    Next i
    Close #1
End Sub
'处理合并单元格的制表符格式
Sub merge(ByRef arr() As Variant, ByVal stRow As Integer, _
    ByVal edRow As Integer, ByVal stCol As Integer, ByVal edCol As Integer)
    Dim Row1 As Integer
    Dim Row2 As Integer
    Dim Col1 As Integer
    Dim Col2 As Integer
    Dim i As Integer, j As Integer
    '数组中的位置
    Row1 = stRow * 2 - 1
    Col1 = stCol * 2 - 1
    Row2 = edRow * 2 - 1
    Col2 = edCol * 2 - 1
    '处理内部线框
    For i = Row1 + 1 To Row2 - 1
        For j = Col1 + 1 To Col2 - 1
            If i Mod 2 <> 0 Then
                arr(i, j) = String(LenB(StrConv(arr(i, j), vbFromUnicode)), " ")
            ElseIf j Mod 2 <> 0 Then
                arr(i, j) = ""
            End If
        Next j
    Next i
    '处理上下框线
    For i = Col1 + 1 To Col2 - 1
        arr(Row1, i) = Replace(arr(Row1, i), "┼", "┴")
        arr(Row1, i) = Replace(arr(Row1, i), "┬", "─")
        arr(Row2, i) = Replace(arr(Row2, i), "┼", "┬")
        arr(Row2, i) = Replace(arr(Row2, i), "┴", "─")
    Next i
    '处理左右框线
    For i = Row1 + 1 To Row2 - 1
        arr(i, Col1) = Replace(arr(i, Col1), "┼", "┤")
        arr(i, Col1) = Replace(arr(i, Col1), "├", "│")
        arr(i, Col2) = Replace(arr(i, Col2), "┼", "├")
        arr(i, Col2) = Replace(arr(i, Col2), "┤", "│")
    Next i
End Sub
Sub InsertLine(ByRef arr() As Variant, ByVal InsRow As Integer, ByVal n As Integer)
    Dim i As Integer, j As Integer
    Dim brr() As Variant
    Dim Length As Integer, L As Integer
    Dim row As Integer, Col As Integer
    '插入后表格的行数和列数
    row = UBound(arr, 1) + n
    Col = UBound(arr, 2)
    ReDim brr(1 To row, 1 To Col)
    '把arr的内容逐个复制到brr中,同时插入换行的内容
    For i = 1 To row
        For j = 1 To Col
            Select Case i
                '复制插入之前的行
                Case Is <= InsRow
                    brr(i, j) = arr(i, j)
                '处理插入行的内容
                Case Is <= InsRow + n
                    Select Case j Mod 2
                    Case Is = 1 '奇数列即制表符列,直接复制上一行的内容
                        brr(i, j) = arr(InsRow, j)
                    Case Is = 0 '偶数列即数据所在列,按行号截取字符串内容
                        Length = LenB(StrConv(arr(InsRow, j), vbFromUnicode)) '字符串字节数
                        L = CellWidth(InsRow, j, rng, ColWidth) / 2
         '单元格字节数/2
                        If Length <= L * 2 Then
                            brr(i, j) = String(Length, " ")
                        Else
                            brr(i, j) = Mid(arr(InsRow, j), L * (i - InsRow) + 1, L)
' Debug.Print arr(InsRow, j),LenB(StrConv(arr(InsRow, j), vbFromUnicode))
                            '使插入的单元格字节长度符合要求
                            Length = LenB(StrConv(brr(i, j), vbFromUnicode))
                            If Length < L * 2 Then brr(i, j) = brr(i, j) & String(L * 2 - Length, " ")
                            '处理原单元格的字符内容
                            brr(InsRow, j) = Left(arr(InsRow, j), L)
                            Length = LenB(StrConv(brr(InsRow, j), vbFromUnicode))
                            If Length < L * 2 Then brr(InsRow, j) = brr(InsRow, j) & _
                                String(L * 2 - Length, " ")
                        End If
                    End Select
                '复制插入行之后的内容
                Case Else
                    brr(i, j) = arr(i - n, j)
            End Select
        Next j
    Next i
    '将brr的值赋给arr
    ReDim arr(1 To row, 1 To Col)
    arr = brr
End Sub
'Function IsFirstCol(ByVal i As Integer, ByVal j As Integer, Rng As Range)
' With Rng.Cells(i / 2, j / 2)
' If .MergeArea.Column = .Column Then
' IsFirstCol = True
' Else
' IsFirstCol = False
' End If
' End With
'End Function
'单元格宽度
Function CellWidth(ByVal i As Integer, ByVal j As Integer, rng As Range, ColWidth As Variant)
    Dim width As Integer
    Dim brr() As Variant
    Dim L As Integer
    Dim k As Integer
    Dim strL As Integer
    With rng.Cells(i / 2, j / 2)
        strL = LenB(StrConv(.Value, vbFromUnicode))
        If .MergeCells Then
            If .MergeArea.Column = .Column Then
                width = 0
                brr = .MergeArea.Value
                If UBound(brr, 2) > 1 Then
                    For k = 2 To (UBound(brr, 2) - 1) * 2
                        width = width + ColWidth(j + k)
                    Next k
                    L = 2 * (UBound(brr, 2) - 1) + width + ColWidth(j)
                    If L < strL Then L = Application.Max(StrLength * 2, L)
                Else
                    L = Application.Max(ColWidth(j), Application.Min(StrLength * 2, strL))
                End If
            Else
                L = 0
            End If
        Else
            L = ColWidth(j)
        End If
    End With
    If i Mod 2 = 1 Then L = ColWidth(j)
    If L Mod 2 = 1 Then L = L + 1
    CellWidth = L
End Function

一点小提示

在导出之前,记得选中你想要导出的表格区域哦!
导出的txt文件字体需要选择等宽字体(如新宋体),格式才能对齐哟!

嘿,是不是觉得这个小魔法很有趣?以后再也不用为分享Excel表格而烦恼了,一键导出,整整齐齐,妈妈再也不用担心我分享数据啦!如果你还有其他有趣的VBA小技巧,快快留言分享给大家吧!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注