简体   繁体   English

Excel宏可将特定单元格从行移到列

[英]Excel macro to transpose specific cells from row to column

I am working with data from an image analysis software which exports data in the following way : 我正在使用通过以下方式导出数据的图像分析软件中的数据:

样本图片

In every case, two empty rows separate the Image name from the different annotations put on the Image itself. 在每种情况下,都有两个空行将图像名称与放置在图像本身上的不同注释分开。 The next Image is separated from the last annotation by three empty rows. 下一个图像与最后一个注释由三个空行分隔。 All annotations are refered to by their number and consist of a measurement, its unit and a comment about which kind of measurement it is. 所有注释均按编号编号,并由度量,度量单位和有关度量类型的注释组成。 However, this disposition is not practical. 但是,这种配置不切实际。 It would be much easier to manage the data if it were displayed like this: 如果这样显示数据,将更容易管理数据:

SampleImage2

In the form of a table with "Annotation", "Comment", "Value" and "Unit" as headers, with all information about the annotation in the same row. 以带有“批注”,“注释”,“值”和“单位”作为标题的表的形式,有关批注的所有信息都在同一行中。 So far I've tried to transpose the data manually, but this takes way too long when many images are involved. 到目前为止,我已经尝试过手动转置数据,但是当涉及到许多图像时,这花费了太长时间。 I also tried to use the macro recorder to automate the process, but it doesn't work since it uses fixed positions in the worksheet. 我还尝试使用宏记录器来自动执行该过程,但由于它在工作表中使用固定位置,因此无法正常工作。 Moreover, all Images don't possess the same number of annotations. 而且,所有图像都没有相同数量的注释。

Could anyone help me create a macro to do such a thing? 谁能帮我创建一个宏来做这样的事情? I've started dabbling with the VBA code recently, but this is way out of my league. 我最近开始涉猎VBA代码,但是这超出了我的范围。

This macro will do the work except for the lines between records, 3 lines will remain. 除了记录之间的行,此宏将完成工作,将保留3行。 The main point is that the record should start with "Image Name" (the check is case-insensitive). 要点是,记录应以“图像名称”开头(检查不区分大小写)。 You can adjust it later to match the requirements. 您可以稍后对其进行调整以符合要求。

Sub ReorderImageRecords()
Dim cnt As Long, curidx As Long

For i = 1 To ActiveSheet.UsedRange.Rows.Count
 cnt = 0
 If Left(LCase(Cells(i, 1)), 10) = "image name" Then
   Cells(i + 1, 1).EntireRow.Delete
   Cells(i + 1, 1).EntireRow.Delete
   curidx = i
   Cells(curidx + 1, 1) = "Annotation"
   Cells(curidx + 1, 2) = "Comment"
   Cells(curidx + 1, 3) = "Value"
   Cells(curidx + 1, 4) = "Unit"
   While Not IsEmpty(Cells(curidx + cnt + 2, 2))
     cnt = cnt + 1
     Cells(curidx + cnt + 1, 2) = Cells(curidx + cnt + 2, 3)
     Cells(curidx + cnt + 2, 2).EntireRow.Delete
   Wend
   i = i + cnt + 1
 End If
Next i

End Sub

UPDATE UPDATE

And here is an optimized version without curidx and with the code to remove extra lines in between image records: 这是一个没有curidx的优化版本,并带有删除图像记录之间多余行的代码:

Sub ReorderImageRecords()
Dim cnt As Long, i As Long

For i = 1 To ActiveSheet.UsedRange.Rows.Count
 cnt = 0
 If i > 1 Then ' If it is not the 1st row
   If Application.CountA(Cells(i - 1, 1).EntireRow) = 0 Then
     Cells(i - 1, 1).EntireRow.Delete ' Delete if the whole preceding row is empty
   End If
   If Application.CountA(Cells(i - 1, 1).EntireRow) = 0 Then
     Cells(i - 1, 1).EntireRow.Delete ' Repeat row removal
   End If
 End If
 If Left(LCase(Cells(i, 1)), 10) = "image name" Then ' We found an image record start
   Cells(i + 1, 1).EntireRow.Delete ' We delete unnecessary blank rows
   Cells(i + 1, 1).EntireRow.Delete ' Repeat removal
   Cells(i + 1, 1) = "Annotation"   ' Insert headers
   Cells(i + 1, 2) = "Comment"
   Cells(i + 1, 3) = "Value"
   Cells(i + 1, 4) = "Unit"
   While Not IsEmpty(Cells(i + cnt + 2, 2)) ' If we are still within one and the same record
     cnt = cnt + 1
     Cells(i + cnt + 1, 2) = Cells(i + cnt + 2, 3) ' Copy comment
     Cells(i + cnt + 2, 2).EntireRow.Delete        ' Remove row with comment
   Wend
   i = i + cnt + 1 ' Increment row index to the current value
 End If
Next i

End Sub

I already mentioned I'll post a possible solution so here it goes (although kinda late). 我已经提到过,我会发布一个可能的解决方案,以便在这里解决(尽管有点晚)。

Sub Test()
    Dim lr As Long, r As Range
    Application.ScreenUpdating = False
    With Sheet1 'source worksheet; change to suit
        lr = .Range("B" & .Rows.Count).End(xlUp).Row
        Set r = .Range("A1:D" & lr)
        r.Replace "Length", "": r.AutoFilter 1, "<>"
        r.SpecialCells(xlCellTypeVisible).Copy Sheet4.Range("A1")
        .AutoFilterMode = False
        r.AutoFilter 2, "<>"
        r.Offset(0, 2).Resize(, 1).SpecialCells(xlCellTypeVisible).Copy _
            Sheet4.Range("E1")
        .AutoFilterMode = False
    End With

    With Sheet4 'output worksheet; change to suit
        lr = .Range("A" & .Rows.Count).End(xlUp).Row
        .Range("B1:B" & lr).Copy: .Range("E1:E" & lr).PasteSpecial xlPasteValues, , True
        .Range("E1:E" & lr).Replace "Attribute Name", "Comment"
        .Range("E1:E" & lr).Cut .Range("B1")
        .Range("C1:C" & lr).AutoFilter 1, "<>"
        .Range("D2:D" & lr).SpecialCells(xlCellTypeVisible).Replace "", "Unit"
        .AutoFilterMode = False
    End With
    Application.ScreenUpdating = True
End Sub

This will work if the data is as consistent as what you've posted above. 如果数据与上面发布的数据一致,则此方法有效。
Also result will be something like this (no space between Image name). 结果也将是这样的(图像名称之间没有空格)。
Also it needs an output worksheet (in above case it is Sheet4). 它还需要一个output worksheet (在上面的例子中是Sheet4)。 HTH. HTH。

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM