实例需求:
在Word文档的多列表格中,需要按照第一列进行排序,同时保持其他列的数据对应顺序不变。想必大家都知道,在Excel中可以简单地使用排序功能实现这种需求,但是对于Word表格则需要使用VBA代码进行处理。
原始数据:
fruit | vegetable |
---|---|
apple | eggplant |
pear | carrot |
apple | cabbage |
apple | potato |
pear | yam |
orange | marrow |
排序后的数据:
(第二列保留其在原始表格中的先后顺序)
fruit | vegetable |
---|---|
apple | eggplant |
apple | cabbage |
apple | potato |
pear | carrot |
pear | yam |
orange | marrow |
示例代码:
Sub SortTableInWord()
Dim oTable As Table
Dim aData(), Temp
Dim i As Long, j As Long
Dim RowsCnt As Long, c As Range
Dim Dic As Object, aKey, aItem, k
Set oTable = ActiveDocument.Tables(1)
RowsCnt = oTable.Rows.Count
ReDim aData(1 To RowsCnt, 1 To 2)
For i = 1 To RowsCnt
For j = 1 To 2
Set c = oTable.Cell(i, j).Range
aData(i, j) = ActiveDocument.Range(c.Start, c.End - 1).Text
Next j
Next i
Set Dic = CreateObject("scripting.dictionary")
For i = 2 To RowsCnt
Temp = aData(i, 1)
If Dic.Exists(Temp) Then
Dic(Temp) = Dic(Temp) & "|" & aData(i, 2)
Else
Dic(Temp) = aData(i, 2)
End If
Next i
aKey = Dic.keys
For i = 0 To Dic.Count - 1
For j = i + 1 To Dic.Count - 1
If aKey(i) = aKey(j) Then
Temp = aKey(i)
aKey(i) = aKey(j)
aKey(j) = Temp
End If
Next j
Next i
j = 2
For i = 0 To Dic.Count - 1
aItem = Split(Dic(aKey(i)), "|")
For k = 0 To UBound(aItem)
oTable.Cell(j, 1).Range.Text = aKey(i)
oTable.Cell(j, 2).Range.Text = aItem(k)
j = j + 1
Next
Next i
End Sub
【代码解析】
第7行代码获取活动文档中的第一个表格对象。
第8行代码获取表格行数。
第9行代码定义二维数组存表格数据。
第10~15行代码双层For循环加载表格数据到数组。
第12行代码获取单元格Range对象。
第13行代码读取单元格文本到数组,其中Range(c.Start, c.End - 1)
用于剔除单元格内容结尾的Chr(13)
,也可以读取Text
属性后,使用Replace
函数进行替换。
第16行代码创建字典对象。
第17~24行代码循环处理每行数据。
第18行代码获取当前行第一列值为字典对象的键。
第19~23行代码判断键是否存在。
- 如果存在,则第20行代码将表格中第2列的值追加到字典中,使用竖线作为分隔符。
- 如果不存在,则第22行代码在字典对象中增加新键。
第25行代码获取字典键列表。
第26~34行代码使用双层For
循环对字典键列表排序。
第28~32行代码交换变量实现排序。
第35行代码初始化写入行号。
第36~43行代码循环写入排序后的数据。
第37行代码拆分值列表。
第39~41行代码写入键和对应值。
第42行代码行号指针加一。
小结:
利用字典对象可以方便地存储表格数据,通过键值对应关系保证排序后数据顺序正确性,如果使用普通的排序算法对于二维数组排序,那么在排序过程中交换数组元素时,将打乱第2列数据的顺序。