可变搜索单元VBA
我有以下专栏(1): 这需要变成两列可变搜索单元VBA,vba,excel,Vba,Excel,我有以下专栏(1): 这需要变成两列 1 15 150 1500000 06700 1500000 07290 1500000 07500 2 22 220 2200000 00900 我最初的想法是: 创建额外的列 当找到长度为7位的数字时,通过行循环,在变量中注册单元格和值 将其下的值移动到B列,直到值的长度为5 从变量中保存的单元格开始,将值从变量复制到A列,直到A列不再为空 在上述过程之后,循环行并删除其中
1
15
150
1500000 06700
1500000 07290
1500000 07500
2
22
220
2200000 00900
我最初的想法是:
- 创建额外的列
- 当找到长度为7位的数字时,通过行循环,在变量中注册单元格和值
- 将其下的值移动到B列,直到值的长度为5
- 从变量中保存的单元格开始,将值从变量复制到A列,直到A列不再为空
- 在上述过程之后,循环行并删除其中A为长度7且B为空的行
这段代码必须每月在一个新的大型excel文件上运行。在编写了逻辑之后,记住了Jeeped的输入,我最终按照以下方式编写:
- 强制将列A转换为文本
- 创建额外的列
- 获取包含数据的行数
- 循环1:如果A列单元格长度为5,则将单元格移动到B列
- 循环2:如果列A单元格长度为7,则将该值复制到变量
- 循环2:如果列A单元格长度为0,则将变量粘贴到单元格中
- 在上述过程之后,循环行并删除其中A为长度7且B为空的行。(性能反向循环)
Sub FixCols()
'First trim the numbers (text) with 2 methods. VBA trim and Worksheet formula trim
Range("A:A").NumberFormat = "@"
Dim Cell As Range
For Each Cell In ActiveSheet.UsedRange.Columns("A").Cells
x = x + 1
Cell = Trim(Cell)
Cell.Value = WorksheetFunction.Trim(Cell.Value)
Next
'Now insert empty column as B
Columns("B:B").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
'Determine rows with values for loop
With ActiveSheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'Loops to move around the data
Dim i As Long
Dim CellValue As Long
For i = 1 To LastRow
'move items to column B
If Len(Range("A" & i).Value) = 5 Then
Range("A" & i).Select
Selection.Cut
Range("B" & i).Select
ActiveSheet.Paste
End If
Next i
For i = 1 To LastRow
'if the row is a reknr we copy the value
If Len(Range("A" & i).Value) = 7 Then
CellValue = Range("A" & i).Value
End If
'Paste the reknr to the rows with item
If Len(Range("A" & i).Value) = 0 Then
Range("A" & i).Value = CellValue
End If
Next i
'Reverse loop (performance) to check for rows to delete (reknr without item)
i = LastRow
Do
If Len(Range("A" & i).Value) = 7 And Len(Range("B" & i).Value) = 0 Then
Rows(i).Delete
End If
i = i - 1
Loop While Not i < 1
End Sub
Sub-FixCols()
'首先用两种方法修剪数字(文本)。VBA修剪和工作表公式修剪
范围(“A:A”).NumberFormat=“@”
暗淡单元格作为范围
对于ActiveSheet.UsedRange.Columns(“A”)单元格中的每个单元格
x=x+1
单元=修剪(单元)
Cell.Value=工作表function.Trim(Cell.Value)
下一个
'现在将空列插入为B
列(“B:B”)。选择
选择。插入Shift:=xlToRight,CopyOrigin:=xlFormatFromLeftOrAbove
'确定具有循环值的行
使用ActiveSheet
LastRow=.Cells(.Rows.Count,“A”).End(xlUp).Row
以
'循环以在数据周围移动
我想我会坚持多久
将单元格值设置为“长”
对于i=1到最后一行
'将项目移动到B列
如果Len(范围(“A”&i).Value)=5,则
范围(“A”和i)。选择
选择,剪
范围(“B”和i)。选择
活动表。粘贴
如果结束
接下来我
对于i=1到最后一行
'如果该行是reknr,则复制该值
如果Len(范围(“A”&i).Value)=7,则
CellValue=范围(“A”&i).值
如果结束
'将reknr粘贴到包含项的行
如果Len(范围(“A”&i).Value)=0,则
范围(“A”&i)。值=单元格值
如果结束
接下来我
'反向循环(性能)以检查要删除的行(不带项的reknr)
i=最后一行
做
如果Len(范围(“A”)和i.Value)=7且Len(范围(“B”)和i.Value)=0,则
第(i)行。删除
如果结束
i=i-1
循环而不是i<1
端接头
无论您的5位数字(c/w/前导零)是单元格格式为00000
的真数字,还是看起来像带a的数字的文本,都应该能够从显示的文本中确定其修剪长度
下面的代码遵循您的逻辑步骤进行了一些修改;最明显的是它从A列的底部走到顶部。这是为了避免跳过已删除的行
Sub bringOver()
Dim rw As Long, v As Long, vVAL5s As Variant, vREV5s As Variant
'put the cursor anywhere in here and start tapping F8
'it will help if you can also see the worksheet with your
'sample data
ReDim vVAL5s(0) 'preset some space for the first value
With Worksheets("Sheet1") '<~~ set this worksheet reference properly!
'ensure a blank column B
.Columns(2).Insert
'work from the bottom to the top when deleting rows
'or you risk skipping a row
For rw = .Cells(Rows.Count, 1).End(xlUp).Row To 2 Step -1
'determine the length of the trimmed displayed length
'and act accordingly
Select Case Len(Trim(.Cells(rw, 1).Text))
Case Is < 5
'do nothing
Case 5
'it's one to be transferred; collect it
vVAL5s(UBound(vVAL5s)) = .Cells(rw, 1).Text
'make room for the next
ReDim Preserve vVAL5s(UBound(vVAL5s) + 1)
Case 7
'only process the transfer if there is something to transfer
If CBool(UBound(vVAL5s)) Then
'the array was built from the bottom to the top
'so reverse the order in the array
ReDim vREV5s(UBound(vVAL5s) - 1)
For v = UBound(vVAL5s) - 1 To LBound(vVAL5s) Step -1
vREV5s(UBound(vREV5s) - v) = vVAL5s(v)
Next v
'working With Cells is like selecting htem but without selecting them
'want to work With a group of cells tall enough for all the collected values
With .Cells(rw, 1).Resize(UBound(vREV5s) + 1, 1)
'move over to column B and put the values in
.Offset(0, 1) = Application.Transpose(vREV5s)
'make sure they show leading zeroes
.Offset(0, 1).NumberFormat = "[Color13]00000;[Color9]@"
'if there was more than 1 moved over, FillDown the 7-wide value
If CBool(UBound(vREV5s)) Then .FillDown
'delete the last row
.Cells(.Rows.Count + 1, 1).EntireRow.Delete
End With
'reset the array for the next first value
ReDim vVAL5s(0)
End If
Case Else
'do nothing
End Select
'move to the next row up and continue
Next rw
'covert the formatted numbers to text
Call makeText(.Columns(2))
End With
End Sub
Sub makeText(rng As Range)
Dim tCell As Range
For Each tCell In rng.SpecialCells(xlCellTypeConstants, xlNumbers)
tCell.Value = Format(tCell.Value2, "\'00000;@")
Next tCell
End Sub
Sub-bringOver()
尺寸rw为长,v为长,vVAL5s为变型,vREV5s为变型
'将光标放在此处的任意位置,然后开始按F8键
'如果您还可以使用您的
"样本数据,
ReDim vVAL5s(0)'为第一个值预设一些空间
工作表(“Sheet1”)是一个有趣的项目,您已经编写了一个不错的软件规范,但它仍然是一个软件规范,不是一个免费的代码编写服务。开始使用宏录制器,然后回来编辑您的问题,以包括您在为更大的目的重新编写录制的代码时遇到的困难。感谢您的阅读,我不是在请求代码,也不是在审查代码。我在问我的逻辑是否有缺陷,我是否忘记了一个重要的步骤,一旦写了这个步骤,功能就会失效。我目前正在阅读并学习写上面的内容。你的逻辑可以工作,但可以优化。二维变量数组速度更快,行可以在一个片段中删除,而不是在多个小片段中删除。唯一突出的是你对长度的依赖。是将00900
等格式化为文本还是将单元格编号格式化为00000
以实现前导零?当你浏览这些行时,从底部开始,一直到顶部。它们确实被格式化为文本。我想你在我的逻辑中发现了一个有趣的缺陷。一旦我做了修剪,它就不再被认为是文本了。我需要保持领先的0。我在ActiveSheet.UsedRange.Columns(“A”).Cells x=x+1 Cell.Value=WorksheetFunction.Trim(Cell.Value)中使用Dim Cell作为每个单元格的范围。接下来取消上述操作,在修剪之前再次强制将其放入文本。有A、A和A。.Text是显示的文本,因此它可以是5个字符的文本字符串,也可以是格式为00000
的数字。我第一次遇到这个问题,但那是因为我的数字格式仅为00000
;一旦我把它们改成文本,一切似乎都很顺利。
Sub bringOver()
Dim rw As Long, v As Long, vVAL5s As Variant, vREV5s As Variant
'put the cursor anywhere in here and start tapping F8
'it will help if you can also see the worksheet with your
'sample data
ReDim vVAL5s(0) 'preset some space for the first value
With Worksheets("Sheet1") '<~~ set this worksheet reference properly!
'ensure a blank column B
.Columns(2).Insert
'work from the bottom to the top when deleting rows
'or you risk skipping a row
For rw = .Cells(Rows.Count, 1).End(xlUp).Row To 2 Step -1
'determine the length of the trimmed displayed length
'and act accordingly
Select Case Len(Trim(.Cells(rw, 1).Text))
Case Is < 5
'do nothing
Case 5
'it's one to be transferred; collect it
vVAL5s(UBound(vVAL5s)) = .Cells(rw, 1).Text
'make room for the next
ReDim Preserve vVAL5s(UBound(vVAL5s) + 1)
Case 7
'only process the transfer if there is something to transfer
If CBool(UBound(vVAL5s)) Then
'the array was built from the bottom to the top
'so reverse the order in the array
ReDim vREV5s(UBound(vVAL5s) - 1)
For v = UBound(vVAL5s) - 1 To LBound(vVAL5s) Step -1
vREV5s(UBound(vREV5s) - v) = vVAL5s(v)
Next v
'working With Cells is like selecting htem but without selecting them
'want to work With a group of cells tall enough for all the collected values
With .Cells(rw, 1).Resize(UBound(vREV5s) + 1, 1)
'move over to column B and put the values in
.Offset(0, 1) = Application.Transpose(vREV5s)
'make sure they show leading zeroes
.Offset(0, 1).NumberFormat = "[Color13]00000;[Color9]@"
'if there was more than 1 moved over, FillDown the 7-wide value
If CBool(UBound(vREV5s)) Then .FillDown
'delete the last row
.Cells(.Rows.Count + 1, 1).EntireRow.Delete
End With
'reset the array for the next first value
ReDim vVAL5s(0)
End If
Case Else
'do nothing
End Select
'move to the next row up and continue
Next rw
'covert the formatted numbers to text
Call makeText(.Columns(2))
End With
End Sub
Sub makeText(rng As Range)
Dim tCell As Range
For Each tCell In rng.SpecialCells(xlCellTypeConstants, xlNumbers)
tCell.Value = Format(tCell.Value2, "\'00000;@")
Next tCell
End Sub