楼主 liuguansky |
问题的提出:
数量/箱来计算每件或每箱的数量,同时来对原版中的内容进行分配。 分配规则如下: 类似这样的表达方式1-R28L748(36):前面是代码,后面()中的是数量。 先分配前面的,再依次向后进行分配,同一编号用同一原版进行处理。 比如1.2.231.80100编号:第一个记录是288/4=72 那么应该分配前面的两个36/36,结果应该返回为: 1-R28L748(36) 1-R28L749(36) 第二条记录,就拉着分配: 1-R28L750(72) 这样依次下去。 如果一箱的数量小于一个代码的数量,则需把代码进行拆分返回。
问题的分析: 1.对于特殊形式的字符串处理,我们可以很容易的考虑到正则表达式,同时结合分组来进行数据的提取。 2.在为同一编号,运用同一原版,故可以想到用字典来进行编号的惟一性识别。 3.因为同一编号是对同一原版进行数量的判断处理,故可以设置数组进行相应的数量元素的减少或消失[设置为空文本] 因为字典的ITEM项目操作多种 元素会比较烦琐,故直接引用数组入ITEM项目。 4.对每条记录的实际数量,与字典ITEM数组中的数量元素进行比较判断来进行字符串返回即可。
问题的实现:- Sub justtest()
- Dim arr, i&, arrt() As String, K&, d, j%, StrTemp$, arrk, ark '定义变量
- arr = Range("a2:d" & Cells(Rows.Count, 1).End(3).Row).Value '获取待处理数据区域入数组
- Set d = CreateObject("scripting.dictionary") '创建字典项目
- ReDim arrt(1 To UBound(arr, 1), 1 To 1) '重定义结果数组
- With CreateObject("vbscript.regexp") '创建正则项目
- '知识点1:正则对字符串的处理
- .Global = True '全局为真
- .Pattern = "(\d-R\d{2}L\d{3})\((\d+)\)" '匹配代码段与数量段,进行分组$1$2
- '知识点2:分组便于分段截获项目
- For i = 1 To UBound(arr, 1) '循环数据源数组
- If Not d.exists(arr(i, 1)) Then '如果字典项目不存在的话
- If .test(arr(i, 3)) Then '如果原版匹配有正则段
- ark = Split(.Replace(Replace(arr(i, 3), " ", ""), "@$1@$2"), "@") '生成代码段与数量段间隔数组
- '知识点3:正则.replace方法的分组替换,配合SPLIT返回结果数组
- End If
- d.Add arr(i, 1), ark '同时创建项目,设置ITEM项为数组,方便后续处理
- '知识点4:依处理需求,添加数组入字典ITEM项目
- End If
- K = arr(i, 2) / arr(i, 4) '返回每箱装数量
- arrk = d(arr(i, 1)) '获取相应编码对应的字典ITEM项入数组,方便后续取值判断
- StrTemp = "" '初始化返回代码+数量字符串
- '知识点5:标识字符串或标识位的初始化,防止前期结果对后期标识的影响
- For j = 1 To UBound(arrk) Step 2 '循环原版处理后的字符串,因代码段与数量段相隔,故STEP2
- If arrk(j) <> "" Then '对非空元素 进行判断处理
- If K >= CLng(arrk(j + 1)) Then '如果待生成数量不小于元素数量
- StrTemp = StrTemp & " " & arrk(j) & "(" & CLng(arrk(j + 1)) & ")" '则返回对应代码+数量
- K = K - CLng(arrk(j + 1)): arrk(j) = "": arrk(j + 1) = "" '同时对K进行减少,清空对应的数组元素
- If K = 0 Then Exit For '如果刚好处理完,则跳出循环
- '知识点6:循环达到目的即跳出循环,避免无用或多余的循环判断
- Else '如果待生成数量小于元素数量
- StrTemp = StrTemp & " " & arrk(j) & "(" & K & ")" '生成对应代码+待生成数量
- arrk(j + 1) = CLng(arrk(j + 1)) - K '处理对应元素的数量
- Exit For '同时进行循环跳出
- End If
- End If
- Next j
- d(arr(i, 1)) = arrk '更新字典对应项目的ITEM项
- '知识点7:字典ITEM项目的独立性[只依附于对应的KEY],需重新赋值回去
- arrt(i, 1) = Mid(StrTemp, 3) '返回字符串
- '知识点8:字符串连接后,直接以MID来去除第一个连接多余间隔符。
- Next i
- Range("e:e").ClearContents '清空返回数据区域
- Range("e2").Resize(i - 1, 1) = arrt '返回结果
- End With
- Set d = Nothing '清空变量
- End Sub
知识点分析: 1.正则用于处理字符串上有很大的优势,通过分析数据的通性,来书写PATTERN进行目标字符的匹配,可以很方便的辅以我们来进行后续的其他操作。 2.匹配后,当我们要抽取其中的部分匹配结果可以用()加以分组,分组后有两种方式返回: 第一种就是通过每一个匹配结果的submatches集合进行调用。 第二种就是本例中的结合replace来进行处理。 每一个分组在REPLACE中的匹配结果用$1/2/3...这样编号下去。 本例中把代码与数量分组,进行特殊字符的间隔REPLACE后再SPLIT返回为数组,是一种常用的取分组匹配结果入数组的方式。 3.关于字典的ITEM,它是个大肚能容天下物的东西,数组、字典、对象都可以放进去。 所以有时我们可以根据我们处理的数据结果,对其进行不同的赋值。 需要注意的是ITEM为数组、字典、对象等的时候,要把它赋值时的变量名与其本身区分开来。 ITEM是个依附于对应KEY值而存在的,不能单独去获取其值,所以只能字典进行返回,所以进行ITEM的处理时,应先赋值给对象/变量,操作完后再赋值回字典的ITEM项目 4.有时我们在数组的循环中,会设定很多标识位/参照值等等的中间变量 ,这些变量我们要分清哪些是在全过程累加,哪些是只在单一循环中累加,这个时候我们要进行合理的分析并进行清空与初始化。 5.循环过程中,如果达到某些条件后,我们应该进行跳出循环处理 ,防止循环的继续运行,发生多余或不必要的循环。
写在最后: 此例是一个字典+正则+数组的结合实例,对我们综合处理问题很有帮助。其中涉及的几个小技巧与知识点很实用,希望以上分析对大家有帮助,若对上述实例中的知识点或代码有疑问或更好的建议,请跟帖或短消息我。
桌面.rar
该帖已经同步到 |