【问题标题】:Powershell: using regex to retrieve substrings from text/filePowershell:使用正则表达式从文本/文件中检索子字符串
【发布时间】:2018-08-20 12:26:38
【问题描述】:

我有一堆日志文件应该被解析并从中提取一些信息。 示例行(不幸的是,在修剪敏感数据后看起来像 xml 的行):

<SerialNumber>xxxxxxxxx</SerialNumber><IP>X.X.X.X</IP><UserID>user@domain.com</UserID><NumOfFiles>1</NumOfFiles><LocaleID>ENU</LocaleID><Vendor>POLYCOM</Vendor><Model>VVX311</Model><Revision>Rev-A</Revision><CurrentTime>2018-03-12T02:42:59</CurrentTime><CurrentModule><FileName>cpe.nbt</FileName><FileVersion>

我想获取 ip(在 ip 标签中)和 usermail(在 userid 标签之间)

我目前的“求解器”

$regex = "<UserID>"

$files = Get-ChildItem -path 'c:\path\*.log'
foreach ($infile in $files) {
$res = select-string -Path $infile -Pattern $regex -AllMatches  {
$txt = $res[$res.count-1]

# get user
$pos1= $txt.line.IndexOf("<UserID>")
$pos2= $txt.line.IndexOf("</UserID>")
$Puser = $txt.Line.Substring($pos1+8,$pos2-$pos1-8)

....
}

它有效,但我想知道不同的方法是否会更好,想看看如何做到这一点 选择字符串模式 ...

尝试了几个“GUI”正则表达式构建器,但我不知道如何选择需要的东西 谢谢

PS:

结果

$regex = '<IP>(.*)</IP>'
$res = select-string -Path $infile -Pattern $regex
$res

0312092535|cfg  |4|00|DevUpdt|[LyncDeviceUpdateC::prepareAndSendRequest] '<?xml version="1.0" encoding="utf-8"?><Request><DeviceType>3PIP</DeviceType><MacAddress>11-11-11-11-11-11</MacAddress><SerialNumber>111111111111</SerialNumber><IP>10.1.1.1</IP><UserID>user@domain.com</UserID><NumOfFiles>1</NumOfFiles><LocaleID>ENU</LocaleID><Vendor>POLYCOM</Vendor><Model>VVX311</Model><Revision>Rev-A</Revision><CurrentTime>2018-03-12T09:25:35</CurrentTime><CurrentModule><FileName>cpe.nbt</FileName><FileVersion><Major>5</Major><M

日志文件示例 (100Kb+)

0312104211|nisvc|2|00|Invoker's nCommands,CurrentKey:2,(106)Responder
0312104211|nisvc|2|00|Response(-1)nisvc,(-1),(-1)app,(22),(Expiry,TransactionId,Time,Type):(-1,-1,1520844131,1)IndicationCode:(400)
0312104211|app1 |5|00|[CWPADServiceEwsRsp::execute] PAC file failed with ''
0312104301|cfg  |4|00|DevUpdt|[LyncDeviceUpdateC::prepareAndSendRequest] '<?xml version="1.0" encoding="utf-8"?><Request><DeviceType>3PIP</DeviceType><MacAddress>11-11-11-11-11-11</MacAddress><SerialNumber>64167F2A8451</SerialNumber><IP>10.1.1.1</IP><UserID>user@domain.com</UserID><NumOfFiles>1</NumOfFiles><LocaleID>ENU</LocaleID><Vendor>POLYCOM</Vendor><Model>VVX311</Model><Revision>Rev-A</Revision><CurrentTime>2018-03-12T10:43:00</CurrentTime><CurrentModule><FileName>cpe.nbt</FileName><FileVersion><Major>5</Major><Minor>
0312104301|nisvc|2|00|Request(-1)nisvc,(701)NIServiceHttpReqMsgKey,(-1)proxy,(1001)AuthRsp,(Expiry,TransactionId,Time,Type):(45000,1306758696,1520844181,0)IndicationLevel:(200)

【问题讨论】:

  • 你为什么要解析xml....
  • 如果 XML 都在一行中,那么正则表达式应该非常简单,类似于 &lt;IP&gt;(.*)&lt;/IP&gt;.*&lt;UserID&gt;(.*)&lt;UserID&gt;。使用 XML 现有类从 XML 数据中获取信息要容易得多;-)
  • 该文件不是 xml 文件,它是一个到处都有“类似 xml”行的日志文件。示例行只是一个示例 - 日志文件中的数千行我粘贴了包含信息的一行。问题是如何使用 Select-string -Pattern 提取(如果可能)值正如我已经写的那样 - 我确实以不同的方式解决了任务
  • 更新第 1 篇文章:添加完整的日志文件示例和当前结果

标签: regex powershell


【解决方案1】:

此代码将获取所有文件,逐行读取每个文件,并使用用户和 ip 创建对象并将它们放入数组中。

[regex]$ipUserReg = '(?<=<IP>)(.*)(?:<\/IP><UserID>)(.*)(?=<\/UserID>)'
$files = Get-ChildItem $path -filter *.log
$users = @(
    foreach ($fileToSearch in $files) {
        $file = [System.IO.File]::OpenText($fileToSearch)
        while (!$file.EndOfStream) {
            $text = $file.ReadLine()
            if ($ipUserReg.Matches($text).Success -or $userReg.Matches($text).Success) {
                New-Object psobject -Property @{
                    IP = $ipUserReg.Matches($text).Groups[1].Value
                    User = $ipUserReg.Matches($text).Groups[2].Value
                }
            }
        }
        $file.Close()
})

为了构建我的正则表达式,我经常使用regexr.com,但请记住,PowerShell 在某些正则表达式方面略有不同。

编辑:这是一个使用选择字符串而不是逐行读取的示例:

[regex]$ipUserReg = '(?<=<IP>)(.*)(?:<\/IP><UserID>)(.*)(?=<\/UserID>)'
$files = Get-ChildItem $path -filter *.log
$users = @(
    foreach ($fileToSearch in $files) {
        Select-String -Path $fileToSearch.FullName -Pattern $ipUserReg -AllMatches | ForEach-Object {
            $_.Matches | ForEach-Object{
                New-Object psobject -property @{
                    IP = $_.Groups[1].Value
                    User = $_.Groups[2].Value
                }
            }
        }
    }
)

【讨论】:

  • 我说得对吗,文本中的正则表达式变量是 $ipUserReg?在这里和那里用作 $ipReg 或 $userReg 0-o 工作正常,1 个问题 - 这样程序运行速度几乎慢 10 倍:O 正则表达式使用执行时间 24.0324853 总文件:0 总字节数:59713119 “旧式”执行时间 2.0694602总文件数:239 总字节数:59713119 “旧式”是指使用 $txt.line.IndexOf 来查找 的位置与 $txt.Line.Substring 提取,然后对用户相同跨度>
  • 该死,我无法格式化我的答案 :( 或者编辑器的 Chrome 有问题?!无论哪种方式,它的工作速度都比使用 .IndexOf 查找子字符串位置然后使用 Substring 提取 Ip/User 慢 10 倍:( 也无法将您的答案标记为正确 :S
  • @ChavdarChavdarov 添加了另一个带有select-string的示例
  • @ChavdarChavdarov 确保标记答案以帮助其他找到此线程的人
  • 谢谢,终于找到了“标记为答案”的位置:D 我认为大部分速度差异是由于逐行阅读:)
猜你喜欢
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 2012-05-09
  • 1970-01-01
  • 2013-10-14
相关资源
最近更新 更多