excel 通过使用正则表达式提取值从单元格中的字符串创建表

mm5n2pyu  于 2023-05-08  发布在  其他
关注(0)|答案(2)|浏览(95)

我正在尝试编写一个相当大的宏来从一个工作表中提取数据,并将其解析和转换到不同的工作表中。
其他方面都很顺利。但是,我被一部分卡住了。
我在一个单元格中有多行文本(本例中为11行,但可以是动态的)
下面是我试图构建代码的示例文本(各行用空格分隔,每行最后一个字符后用Alt+Enter):

Flat where a figure is quoted but theshold based on the following lanes
IL STD  $5.00 above $75.00 USD 
SG STD  $11 above SGD400 
TR STD  $3 above €30 EUR 
AU EXP $2 for value>AUD 1000
IL EXP $2 for value>USD 75
JP EXP $2 for value>USD 65
NZ EXP $2 for value>NZD 400
PH EXP $2 for value>USD 165
SG EXP $2 for value>SGD 400
TW EXP $2 for value>TWD 2000

我的要求是将此文本解析为一个表,如下所示:

我从逻辑开始,我将计算换行符/回车的数量,然后使用循环创建数组来计算行数。
但我没能做到这一点。
我已经尝试了下面的代码的变化得到没有。但输出始终为0。

Sub tresholds()

Dim strTest As String
Dim NewLines As Long

strTest = ThisWorkbook.Sheets("Rate Card").Range("D10").Text
NewLines = UBound(Split(strTest, Chr(32) & vbCrLf))
'NewLines = UBound(Split(strTest, " " & vbCrLf))
'NewLines = UBound(Split(strTest, vbCrLf))
'NewLines = UBound(Split(strTest, vbLf))
'NewLines = UBound(Split(strTest, Chr(32) & vbLf))

Debug.Print NewLines

End Sub

我也不太擅长正则表达式。而且弦上有多种模式。有些行有货币符号,有些行没有。一些具有“值高于”,而另一些具有值>。无法解释这些变化。
如果你们能帮忙我会很感激的。

mspsb9vt

mspsb9vt1#

此解决方案使用几个正则表达式来匹配各种模式。如果没有正则表达式,您可以很容易地找出各个国家的行,但是如果没有正则表达式,每行中的一些字段将很难找到。你也可以更好地使用regex。你将来会发现它很有用。
在VBA中使用正则表达式需要将引用(工具/引用)设置为Microsoft VBScript Regular Expressions 5.5
此代码没有错误检查;那就看你的了此外,我相信您可以将输出写入工作表,因此我也将其留给您。我已经注意到了输出代码所属的子程序。
如果你需要正则表达式方面的帮助,请在评论中提出具体的问题。另外,SO有一个很棒的regex摘要:How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops

Sub ParseThreshold()
    Dim rngInput As Range, regexMatch As RegExp, strPattern As String, strInput As String, vntRc As Variant, strPartLine As String
    Dim nCount As Integer, nIndex As Integer, vntMatches As Variant, arstrItems() As String, strCountry As String, strSE As String
    Dim dblDollars As Double, dblThreshold As Double
    
    Set regexMatch = New RegExp
    Set rngInput = ActiveSheet.Range("a1")
    strInput = rngInput.Value
    
    ' Define the regex pattern to match each country's line
    strPattern = "^[A-Z]{2} *(STD|EXP) *\$[0-9.]* (above|for value>[A-Z]{3}).*$"
    
    With regexMatch
        .Pattern = strPattern
        .Global = True
        .MultiLine = True
        nCount = .Execute(strInput).Count
    End With
    
    Set vntMatches = regexMatch.Execute(strInput)
    
    If nCount > 0 Then
        ReDim arstrItems(0 To nCount - 1)
        
        For nIndex = 0 To nCount - 1 '
            arstrItems(nIndex) = vntMatches(nIndex)
            strCountry = Left(arstrItems(nIndex), 2)
            strSE = Mid(arstrItems(nIndex), 4, 3)
            
            dblDollars = DollarAmount(arstrItems(nIndex))
            dblThreshold = Threshold(arstrItems(nIndex))
            
            ' Output the values to your table here
        Next nIndex
    End If
    
End Sub  ' ParseThreshold

Function DollarAmount(strInput As String)
    Dim regexMatch As RegExp, strPattern As String, vntRc As Variant
    
    strPattern = "(STD|EXP) *\$[0-9.]*"
    Set regexMatch = New RegExp
    
    With regexMatch
        .Pattern = strPattern
        .Global = False
        .MultiLine = False
        nCount = .Execute(strInput).Count
    End With
    
    Set vntMatches = regexMatch.Execute(strInput)
    If nCount > 0 Then
        vntRc = vntMatches(0)
        vntRc = Replace(vntRc, "STD ", "")
        vntRc = Replace(vntRc, "EXP ", "")
        vntRc = Replace(vntRc, "$", "")
        vntRc = Trim(vntRc)
    End If
    
    DollarAmount = vntRc
    
End Function  ' DollarAmount

Function Threshold(strInput As String)
    Dim regexMatch As RegExp, strPattern As String, vntRc As Variant, nLength As Integer, vntMatches As Variant
    
    nLength = Len(strInput)
    Set regexMatch = New RegExp
    
    strPattern = "[0-9.]+"
    strTarget = "above"
    nPosition = InStr(strInput, strTarget)
    If nPosition > 0 Then
        strPartLine = Mid(strInput, nPosition + Len(strTarget) + 1, nLength)
    Else
        strTarget = "value>"
        nPosition = InStr(strInput, strTarget)
        If nPosition > 0 Then
            strPartLine = Mid(strInput, nPosition + Len(strTarget) + 1, nLength)
        End If
    End If
    
    With regexMatch
        .Pattern = strPattern
        .Global = False
        .MultiLine = False
        nCount = .Execute(strPartLine).Count
        Set vntMatches = .Execute(strPartLine)
    End With
    
    If nCount > 0 Then
        vntRc = vntMatches(0)
    End If
    
    Threshold = vntRc
    
End Function  ' Threshold
xkftehaa

xkftehaa2#

另一种方法...
Sheet 1单元格A1值与示例数据相同

Sub test()
Dim rslt As Range, cnt As Integer, splitVal as String
Dim i As Integer, j As Integer, k As Integer, arr

Set rslt = Sheet2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
arr = Split(Sheet1.Range("A1").Value, Chr(10))

For i = 1 To UBound(arr)
    rslt.Value = application.trim(Split(arr(i), " ")(0))
    rslt.Offset(0, 1).Value = application.trim(Split(arr(i), " ")(1))
    Set rslt = rslt.Offset(0, 2)
    For j = 2 To UBound(Split(arr(i), " "))
        splitVal = Split(arr(i), " ")(j)
        If splitVal Like "*#*" Then
            For k = 1 To Len(splitVal)
                If Mid(splitVal, k, 1) = "." Then Exit For
                If Mid(splitVal, k, 1) >= "0" And Mid(splitVal, k, 1) <= "9" Then rslt.Value = rslt.Value & Mid(splitVal, k, 1)
            Next k
            Set rslt = rslt.Offset(0, 1)
        End If
        If rslt.Column = 5 Then Exit For
    Next j
    Set rslt = Sheet2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
Next i

End Sub

rslt是一个范围变量,结果将放在其中。在本例中,结果将从单元格A2开始放入sheet 2中。
arr变量具有来自sheet 1单元格A1的值,该值用换行符分割。
潜水艇里有三个回路。
1.每行循环
1.循环为每个“字”在循环线分裂与空间
1.循环“单词”中的每个字符
第一个循环是将循环行字符串中的第一个字作为i变量放入sheet 2列A,并将第二个字作为i变量放入sheet 2列B。然后将rslt设置为offset(0,2)。
在第二个循环中,它循环到循环行中的每个单词。由于第一个字和第二个字不再需要,它从2开始作为j变量。它将循环的字放入splitVal变量中,并检查splitVal值是否包含数字,然后它进入第三个循环。
在第三个循环中,它检查splitVal(循环的字)值的每个字符作为k变量。如果循环的字符是“.”,那么它退出循环--->这将忽略十进制值(因为我假设你不需要结果的十进制值)。
然后检查循环字符是否>= 0和<=9,并将结果放入sheet 2列C(rslt变量)。并设置rslt offset(0,1),以便将下一个结果放入列D中。
请注意,如果循环的单词是像这样的SGD.400(在数字前面有一个点),代码将失败。

相关问题