【问题标题】:Split blocks using regex in VBA在 VBA 中使用正则表达式拆分块
【发布时间】:2020-06-16 19:16:22
【问题描述】:

我有数据,我需要拆分每个块,以便将每个块存储在单独的行中。整个文本看起来像:

م
مطروح
الحمام
school
الصف
:
الصف الأول
 1
 458316219 
 30709101600371 
ابراهيم وليد ابراهيم ابوالحمد
منافذ فورى
 2
 458361688 
 30702263300318 
احمد ابوالريش فرج عبدالله
منافذ فورى
 3
 458312720 
 30703143300418 
اسلام فتحى محمد ناجى
منافذ فورى
 4
 458790904 
 30606101802299 
اسلام نصار حسين نصار حسين عبد الونيس
منافذ فورى
 5
 458312908 
 30612013300259 
ايمن راضى صالح سلومه
منافذ فورى
 6
 458884564 
 30802203300186 
بسمه محمد ابراهيم ظدم
منافذ فورى
 7
 477625786 
 30708263300235 
بشار نصر الله مصوف السايب
منافذ فورى

我使用了https://regex101.com/,我可以像这样定义每个块的开始

\d{1,3}\n

这会突出显示每个块的开头

如何拆分和分隔每个块>>并且每个块必须在一行中?

这是整个页面的 HTML:https://pastebin.com/nu0dLvch

这是完整数据的链接:https://pastebin.com/dWcu97Wt

我会突出显示所需的部分(这些是要匹配的组)。从...开始

以...结尾

共有22个数据块(组)。

查看@Wiktor Stribiżew 在 cmets 中提供的正则表达式: https://regex101.com/r/dmCNuH/1

匹配 11 是第一个真正需要的数据(匹配组),但会截断最后一行。

在我从 Wiktor 获得了令人惊叹的模式之后,我尝试获取所有匹配项

Sub Test()
    Dim a(), s As String, i As Long, j As Long
        Dim bot As New ChromeDriver
    With bot
        .AddArgument "--headless"
        .Get "file:///C:\Sample.html"
        s = .FindElementByCss("table[id='all']").Text

    End With
        a = GetMatches(s, "^\s*\d{1,3}(?:(?:\r\n|[\r\n])(?!\s*\d{1,3}\n).*)+")
        For i = LBound(a) To UBound(a)
            Debug.Print a(i)
        Next i
End Sub

Function GetMatches(ByVal inputString As String, ByVal sPattern As String) As Variant
    Dim arrMatches(), matches As Object, iMatch As Object, s As String, i As Long
    With CreateObject("VBScript.RegExp")
        .Global = True
        .MultiLine = True
        .IgnoreCase = True
        .Pattern = sPattern
        If .Test(inputString) Then
            Set matches = .Execute(inputString)
            ReDim arrMatches(0 To matches.Count - 1)
            For Each iMatch In matches
                arrMatches(i) = iMatch.SubMatches.Item(0)
                i = i + 1
            Next iMatch
        Else
            ReDim arrMatches(0)
            arrMatches(0) = vbNullString
        End If
    End With
    GetMatches = arrMatches
End Function

但这对我不起作用并引发错误。

【问题讨论】:

  • 试试^\s*\d{1,3}(?:(?:\r\n|[\r\n])(?!\s*\d{1,3}\n).*)*regExp.Multiline = True
  • 图片中的字符串是哪里来的?来自文本文件,还是来自 Excel 单元格?我问的是,由于可以使用标准 VBA 轻松完成行拆分。并将结果粘贴到 excel 中,在单独的单元格上...
  • 有很多前导尾随空格。在一个区块开始后,他们会一直在第一行和第二行吗?这样,我们就可以区分块的开头和下面有数字的行。
  • 你需要regex101.com/r/dmCNuH/2吗?
  • @YasserKhalil 您可能希望正则表达式也停止在看起来像日期字符串的行之前,对吧?然后你需要regex101.com/r/dmCNuH/4^\s*\d{1,3}(?:\n(?!\s*\d{1,3}\n|\d{4}/\d{2}/\d{2}\n).*)+。如果您在 Excel 中的单元格内有换行符,则可能是 CR,因此您需要 \r 而不是 \n

标签: regex excel vba


【解决方案1】:

你可以使用

^\s*\d{1,3}(?:\n(?!\s*\d{1,3}\n).*){4}

请参阅regex demo。与.Global = True.MultiLine = True 选项一起使用,您不需要将.IgnoreCase 设置为True

注意:由于在 Excel 单元格值中使用\r 回车来定义换行符,您可能需要将模式中的所有\n 字符替换为\r

正则表达式匹配可能缩进或不缩进且包含 1、2 或 3 位数字的行,然后抓取与初始模式不匹配的接下来的四行。

更多详情

  • ^ - 行首
  • \s* - 0 个或更多空白字符
  • \d{1,3} - 一到三位数
  • (?:\n(?!\s*\d{1,3}\n).*){4} - 匹配四个 ({4}) 出现的 non-capturing group
    • \n - 换行符 (\n),即...
    • (?!\s*\d{1,3}\n) - (negative lookahead) 没有立即跟在后面:
      • \s* - 0 个或多个空格
      • \d{1,3} - 一位、两位或三位数字
      • \n - 换行符
    • .* - 除换行符之外的任何 0 个或多个字符,尽可能多。

要提取组的详细信息,您可以使用

^[^\S\n]*(\d{1,3})\n\s*(\d{6,})[^\S\n]*\n\s*(\d{14})[^\S\n]*\n(.+)\n(.+)

this regex demo

  • ^ - 字符串开头
  • [^\S\n]* - 0 个或多个空格字符,换行符除外
  • (\d{1,3}) - 一到三位数
  • \n - 换行
  • \s* - 任何 0+ 个空格
  • (\d{6,}) - 第 2 组:
  • [^\S\n]*\n\s* - 除了换行符、换行符和任何 0 个或多个空格之外,还有 0 个或多个空格字符
  • (\d{14}) - 第 3 组:十四位数字
  • [^\S\n]*\n - 除了换行符和换行符之外,还有 0 个或多个空白字符
  • (.+) - 第 4 组:除换行符之外的任何一个或多个字符,尽可能多
  • \n - 换行符
  • (.+) - 第 5 组:除换行符之外的任何一个或多个字符,尽可能多

【讨论】:

  • @YasserKhalil 尽可能多地练习,你会感觉更确定。使用regexone.com 作为启动器。检查regular-expressions.inforexegg.com
  • 使用 VBA 正则表达式是不可能的。 Repeated capturing groups 在大多数正则表达式库中都是如此。
  • @YasserKhalil 是的,但您必须“解开”量化部分,并在需要它们的组中使用更长的模式。
  • @YasserKhalil 试试this one
  • @YasserKhalil 如果您不在乎匹配是否在单行上,那当然。
【解决方案2】:

非常感谢 Wiktor 和 QHarr 在这个问题上为我提供了很多帮助。我非常感谢他们的帮助。 这是最终代码,我欢迎对代码有任何其他想法或修改

Sub Test()
    Dim x, a(1 To 1000, 1 To 5), bot As New ChromeDriver, col As Object, sInput As String, sPattern As String, i As Long, j As Long, cnt As Long
    sPattern = "^\s*\d{1,3}(?:\n(?!\s*\d{1,3}\n).*){4}"
    With bot
        .AddArgument "--headless"
        .Get "file:///C:\Sample.html"
        sInput = .FindElementByCss("table[id='all']").Text
    End With
    With CreateObject("VBScript.RegExp")
        .Global = True: .MultiLine = True: .IgnoreCase = True
        .Pattern = sPattern
        If .Test(sInput) Then
            Set col = .Execute(sInput)
            For i = 0 To col.Count - 1
                x = Split(col.Item(i), vbLf)
                cnt = cnt + 1
                For j = LBound(x) To UBound(x)
                    a(i + 1, j + 1) = Application.WorksheetFunction.Clean(Trim(x(j)))
                Next j
            Next i
        End If
    End With
    ActiveSheet.Range("A1").Resize(cnt, UBound(a, 2)).Value = a
End Sub

【讨论】:

    猜你喜欢
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 2017-01-18
    • 2021-04-23
    • 1970-01-01
    相关资源
    最近更新 更多