【问题标题】:Regex: Starting from a specific point on each line正则表达式:从每行的特定点开始
【发布时间】:2018-07-04 21:59:59
【问题描述】:

我有一个显示机器上安装的软件的 HTML 文件,我想删除 HTML 文件中表格中的一些单元格。 以下是代码示例:

<tr><td>Adobe Acrobat Reader DC</td><td>18.009.20050</td><td>20171130</td><td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td></tr>
<tr><td>Adobe Flash Player 28 ActiveX</td><td>28.0.0.137</td><td></td><td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td></tr>

...等等。

我想要完成的是删除从 td 标记的第 4 个实例开始的所有内容,并在每行的结束 /tr 标记之前停止,因此基本上消除了...

<td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td>
<td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td>

...这样我就剩下...

<tr><td>Adobe Acrobat Reader DC</td><td>18.009.20050</td><td>20171130</td></tr>
<tr><td>Adobe Flash Player 28 ActiveX</td><td>28.0.0.137</td><td></td></tr>

我使用的正则表达式是

(?<=<td>)(.*)(?=<\/tr>)

我遇到的问题是上面的正则表达式正在选择整行代码。如何更改它,使其从每行的第 4 个标记实例开始?

请参阅以下链接,其中包含我正在使用的 HTML 文件和应用的正则表达式的完整示例:https://regex101.com/r/C9lkMc/3

编辑 1: 此 HTML 由 PowerShell 脚本生成,用于获取远程计算机上已安装的软件。代码是:

    Invoke-Command -ComputerName $hostname -ScriptBlock {
    if (!([Diagnostics.Process]::GetCurrentProcess().Path -match '\\syswow64\\')) {

        $unistallPath = "\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
        $unistallWow6432Path = "\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"
        @(
            if (Test-Path "HKLM:$unistallWow6432Path" ) { Get-ChildItem "HKLM:$unistallWow6432Path"}
            if (Test-Path "HKLM:$unistallPath" ) { Get-ChildItem "HKLM:$unistallPath" }
            if (Test-Path "HKCU:$unistallWow6432Path") { Get-ChildItem "HKCU:$unistallWow6432Path"}
            if (Test-Path "HKCU:$unistallPath" ) { Get-ChildItem "HKCU:$unistallPath" }
        ) |
            ForEach-Object { Get-ItemProperty $_.PSPath } |
            Where-Object {
            $_.DisplayName -and !$_.SystemComponent -and !$_.ReleaseType -and !$_.ParentKeyName -and ($_.UninstallString -or $_.NoRemove)
        } |
            Sort-Object DisplayName | Select-Object -Property DisplayName, DisplayVersion, InstallDate | ft
    }
}

【问题讨论】:

标签: html regex powershell parsing


【解决方案1】:

正则表达式不适合解析 HTML;可能会有很多奇怪的场景;例如如果你有一个节点&lt;td /&gt;&lt;td colspan="2"&gt;,而你希望有&lt;td&gt;,会发生什么?同样,HTML(令人讨厌)并不总是遵循 XML 规则。所以 XML 解析器将无法工作(例如,&lt;hr&gt; 没有结束标记/&lt;hr /&gt; 被视为无效)。

因此,如果要解析 HTML,您最好使用 HTML 解析器。为此,PowerShell 可以访问 HtmlFile com 对象,记录在此:https://msdn.microsoft.com/en-us/library/aa752574(v=vs.85).aspx

这里有一些例子......

此代码查找所有 TR 元素,然后去除前 4 个 TD 之后的所有 TD,并返回该行的外部 HTML。

$html = @'
some sort of html code
<hr> an unclosed tab so it's messy like html / unlike xml
<table>
<tr><th>Program Name</th><th>version</th><th>install date</th><th>computer name</th><th>ID</th><th>Installed</th></tr>
<tr><td>Adobe Acrobat Reader DC</td><td>18.009.20050</td><td>20171130</td><td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td></tr>
<tr><td>Adobe Flash Player 28 ActiveX</td><td>28.0.0.137</td><td></td><td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td></tr>
<tr><td /><td>123</td><td></td><td>hello.com</td><td>456</td><td>True</td></tr>
</table>
etc...
'@

$Parser = New-Object -ComObject 'HTMLFile' #see https://msdn.microsoft.com/en-us/library/aa752574(v=vs.85).aspx
$Parser.IHTMLDocument2_write($html) #if you're using PS4 or below use instead: $Parser.IHTMLDocument2_write($html)

$parser.documentElement.getElementsByTagName('tr') | %{
    $tr = $_
    $tr.getElementsByTagName('td') | select-object -skip 4 | %{$tr.removeChild($_)} | out-null
    $tr.OuterHtml
}

这以类似的方式工作;但只是拉回每行中前 4 个单元格的值:

$html = @'
some sort of html code
<hr> an unclosed tab so it's messy like html / unlike xml
<table>
<tr><th>Program Name</th><th>version</th><th>install date</th><th>computer name</th><th>ID</th><th>Installed</th></tr>
<tr><td>Adobe Acrobat Reader DC</td><td>18.009.20050</td><td>20171130</td><td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td></tr>
<tr><td>Adobe Flash Player 28 ActiveX</td><td>28.0.0.137</td><td></td><td>kratos.kcprod1.com</td><td>4104917a-93f2-46e5-941a-c4efd54504b7</td><td>True</td></tr>
<tr><td /><td>123</td><td></td><td>hello.com</td><td>456</td><td>True</td></tr>
</table>
etc...
'@

$Parser = New-Object -ComObject 'HTMLFile' #see https://msdn.microsoft.com/en-us/library/aa752574(v=vs.85).aspx
$Parser.IHTMLDocument2_write($html) #if you're using PS4 or below use instead: $Parser.IHTMLDocument2_write($html)

$parser.documentElement.getElementsByTagName('tr') | %{
    $tr = $_
    $a,$b,$c,$d = $tr.getElementsByTagName('td') | select-object -first 4 | %{"$($_.innerText)"} #we do this istead of `select -expand innerText` to ensure nulls are returned as blanks; not ignored
    (New-Object -TypeName 'PSObject' -Property ([ordered]@{
        AppName = $a
        Version = $b
        InstallDate = $c
        ComputerName = $d
    }))
} 

【讨论】:

  • 太棒了!谢谢。
猜你喜欢
  • 2016-11-14
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 2022-01-23
  • 2018-03-08
  • 2022-11-16
相关资源
最近更新 更多