Regex 在PowerShell中优化正则表达式匹配

Regex 在PowerShell中优化正则表达式匹配,regex,powershell,optimization,Regex,Powershell,Optimization,我正在过滤一个大的web访问日志文件,并根据regex匹配创建十几个较小的日志文件。由于我对regex几乎没有经验,我希望能够找出如何优化模式以获得更好的性能 源的格式如下所示: 2015-06-14 00:00:06 38.75.53.205 - HTTP 10.250.35.69 80 GET /en/process/dsa/policy/wbss/wbss_current/wbss2013/Wbss13.pdf - 206 299 16722 0 HTTP (etc) 或 下面是我的一些

我正在过滤一个大的web访问日志文件,并根据regex匹配创建十几个较小的日志文件。由于我对regex几乎没有经验,我希望能够找出如何优化模式以获得更好的性能

源的格式如下所示:

2015-06-14 00:00:06 38.75.53.205 - HTTP 10.250.35.69 80 GET /en/process/dsa/policy/wbss/wbss_current/wbss2013/Wbss13.pdf - 206 299 16722 0 HTTP (etc)

下面是我的一些正则表达式模式。在得到后,它们都在每条线的同一区域内查看。这就是我现在拥有它们的方式:

dsq = "( /esd/sddev/| /creative/)"
dpq = "/dsa/policy/"
pop = "(^((?! /popq/ /caster/(dsa/(policy|qsc|qlation))|(esd/(fed|cdq|qaccount|sddev|creative|forums/rdev))).)*$)"
前两个匹配指定的模式,而“pop”应该匹配除指定模式之外的所有模式

这是可行的,但由于我的日志文件往往相当大(1GB或更大),我有12种不同的模式要匹配,我希望有一种方法可以提高这些模式的性能

至于用法,我有以下代码,其中
$profile
是上面列出的代码之一(它们在一个哈希表中,我分别循环它们):


谢谢大家的关注

这不是对正则表达式的改进,但是如果您正在对您拥有的每个配置文件运行
$sourcefile
传递,我可以提供一个小的解决方案

Get-Content $sourcefile -ReadCount 5000 | ForEach { 
    switch -regex ($_)  {
       $dsq {$chosenPath = "file1"; continue}
       $dpq {$chosenPath = "file2"; continue}
       $pop {$chosenPath = "file3"; continue}
       default {}
    }

    # If no path is set they we skip this step. 
    If($chosenPath){$_ | Add-Content $chosenPath}
}
-regex
开关用于
开关
。您可以为匹配项引用哈希表中的每个元素。如果找到了匹配项,那么我们将为该过程设置输出文件,并在存在其他匹配项的情况下停止处理
开关。比赛的顺序会如此重要。因为您声明匹配是相互排斥的,所以这不应该是一个问题

你可以用
为每个匹配添加内容
来重写这个,但我试图停止重复类似的代码。如果您确实删除了它并将其放回所有的
添加内容
中,您可以删除我添加的
$null
逻辑

正则表达式效率

对于最后一个,如果您只是尝试匹配除pop之外的所有内容,那么为什么不删除前瞻、贪婪限定符和锚,只使用
-notmatch

$pop = "/popq/ /caster/(dsa/(policy|qsc|qlation))|esd/(fed|cdq|qaccount|sddev|creative|forums/rdev))"
Get-Content $sourcefile -ReadCount 5000 | 
    ForEach { $_ -notmatch $pop | Add-Content targetfile }

作为旁注,我希望您需要第二个循环来分解5000个项目的数组

Get-Content $sourcefile -ReadCount 5000 | 
 ForEach { $_ | ForEach{ $_ -match $profile | Add-Content targetfile }}

我想知道正则表达式是不是一次在5000行上执行,而不是在你期望的一行上执行。。。。或者可能是打字错误。。。或者我疯了

我想StegMan的意思是,他的建议是把每一行都转换成PowerShell对象,这样你就可以对数据进行更有针对性的搜索。你是如何对文件执行这些正则表达式的,尤其是最后一个?这在这里非常重要。我想让你详细说明你希望最后一个正则表达式如何工作。前瞻和量词可能会得到改进。日志有数据结构吗?谢谢大家的反馈@StegMan,我不知道如何使用ConvertFrom字符串…提供的答案看起来是一个显著的改进,特别是消除了对每个配置文件分别读取
$sourcefile
的需要。按照我的理解,代码查看日志中的每一行,并将其与每个模式进行匹配。一旦找到匹配项,它就会将该匹配项输出到输出文件,并从第一个模式返回到日志中的下一行。我只是不确定它是否会在现有输出文件中添加更多匹配的行,还是会替换它们。@PredragVasić我一直关注您的评论,直到最后一句话。它将根据每次传递期间的匹配情况附加到输出文件中。至于
-ReadCount 5000
,根据我的结果,该行将逐行在5000行上执行正则表达式。这段代码的输出似乎是正确的,输出文件包含来自700k行以上的源的超过400k的匹配行。当我第一次使用不带
-ReadCount 5000
的代码时,它花了很长时间才运行。其他人建议将其添加到内存中,显然,它一次将5000行加载到内存中,使其速度更快,而不是每次执行匹配时都从文件中读取每一行。这就是我对它的解释,结果似乎证实了这一点。听起来很完美!我目前正在重写脚本,并将对其进行测试。我很想看到性能上的差异。我稍后再报告。再次感谢您的建议和解决方案!关于最后一个本质上是
-notmatch
,还有一点需要注意。如果我使用哈希表来存储配置文件名和regex模式对,那么如果没有一些额外的逻辑(检查最后的模式),我就不能使用
-nomatch
。然而,可能的情况如下。所有其他模式匹配日志中的特定行;最后一个实际获取所有与任何其他模式不匹配的行,并将它们发送到自己的输出文件。由于您的代码根据每个模式检查每一行,因此如果没有匹配项,我们可以简单地将该行发送到最后一个目标文件。
$pop = "/popq/ /caster/(dsa/(policy|qsc|qlation))|esd/(fed|cdq|qaccount|sddev|creative|forums/rdev))"
Get-Content $sourcefile -ReadCount 5000 | 
    ForEach { $_ -notmatch $pop | Add-Content targetfile }
Get-Content $sourcefile -ReadCount 5000 | 
 ForEach { $_ | ForEach{ $_ -match $profile | Add-Content targetfile }}