通过正则表达式过滤的文本中保留回车符

时间:2015-06-13 19:52:19

标签: regex powershell

我需要搜索日志文件夹并检索最新日志。然后我需要过滤每个日志,提取相关信息并保存到另一个文件。

问题是我用来过滤日志的正则表达式正在删除回车符和换行符,所以新文件只包含一堆混乱的文本。

$Reg = "(?ms)\*{6}\sBEGIN(.|\n){98}13.06.2015(.|\n){104}00000003.*(?!\*\*)+"
get-childitem "logfolder" -filter *.log |
  where-object {$_.LastAccessTime -gt [datetime]$Test.StartTime} | 
  foreach {
     $a=get-content $_;
     [regex]::matches($a,$reg) | foreach {$_.groups[0].value > "MyOutFile"}
  }

日志结构:

******* BEGIN MESSAGE *******

<Info line 1>
Date   18.03.2010 15:07:37   18.03.2010
<Info line 2>      
File Number:  00000003
<Info line 3>   

*Variable number of lines*
******* END MESSAGE *******

基本上捕获BEGINEND之间的所有内容,其中日期和文件编号是特定值。有没有人知道如何在不丢失换行符的情况下做到这一点?我也尝试使用Out-File | Select-String -Pattern $reg,但我在多行记录中使用Select-String时从未取得过成功。

3 个答案:

答案 0 :(得分:2)

想知道我是否可以更好地制作正则表达式,但是现在如果你使用这些正则表达式模式,你应该把你的文本文件作为单个字符串阅读,这有很大帮助。

text

或者如果您没有PowerShell 3.0

>>> import re
>>> p = re.search('[0-9]{1,3}\.[0-9]{2}', price)
>>> price = p.group(0)
>>> print price

答案 1 :(得分:2)

正如@Matt指出的那样,如果要进行多行匹配,则需要将整个文件作为单个字符串读取。否则,您的(多行)正则表达式将一个接一个地应用于单行。有几种方法可以将文件的内容作为单个字符串获取:

  • (Get-Content 'C:\path\to\file.txt') -join "`r`n"
  • Get-Content 'C:\path\to\file.txt' | Out-String
  • Get-Content 'C:\path\to\file.txt' -Raw(需要PowerShell v3或更新版本)
  • [IO.File]::ReadAllText('C:\path\to\file.txt')

另外,我稍微修改了正则表达式。大多数时间日志消息的长度可能不同,因此如果日志消息发生更改,则匹配的固定长度可能会失败。最好匹配字符串的不变部分,并将其余部分保留为可变长度匹配。而且我个人发现在几个步骤中进行这种内容提取要容易得多(使得更简单的正则表达式)。在您的情况下,我首先将日志条目彼此分开,然后过滤内容:

$date = [regex]::Escape('13.06.2015')
$fnum = '00000003'

$re1 = "(?ms)\*{7} BEGIN MESSAGE \*{7}\s*([\s\S]*?)\*{7} END MESSAGE \*{7}"
$re2 = "(?ms)[\s\S]*?Date\s+$date[\s\S]*?File Number:\s+$fnum[\s\S]*"

Get-ChildItem 'C:\log\folder' -Filter '*.log' | ? {
  $_.LastAccessTime -gt [DateTime]$Test.StartTime
} | % {
  Get-Content $_.FullName -Raw |
    Select-String -Pattern $re1 -AllMatches |
    select -Expand Matches |
    % {
      $_.Groups[1].Value |
        Select-String -Pattern $re2 |
        select -Expand Matches |
        select -Expand Groups |
        select -Expand Value
    }
} | Set-Content 'C:\path\to\output.txt'
顺便说一下,不要在循环中使用重定向运算符(>)。它会在每次迭代时覆盖输出文件的内容。如果必须写入循环内的文件,请使用append重定向运算符(>>)。但是,在性能方面,通常最好将写入输出文件放在管道的末尾(见上文)。

答案 2 :(得分:1)

我必须解决在完全不同的背景下消失换行的问题。当您执行文本文件的get-content时获得的是一组记录,其中每条记录都是一行文本。

我发现在转换后将换行符放回原位的唯一方法是使用自动变量$ OFS(输出字段分隔符)。默认值为space,但如果将其设置为回车换行符,则会在单独的行上获得单独的记录。

所以试试这个(可能会有效):

$OFS = "`r`n"