3

总而言之,我对powershell很陌生,希望有人能让我继续我认为的简单脚本。

我需要解析一个文本文件,从中捕获某些行,并将这些行保存为 csv 文件。

例如,每个警报都在其自己的文本文件中。每个文件都与此类似:

--文件开始---

姓名 John Smith
部门会计
代码 bas-2349,cav-3928,deg-3942
            iye-2830,tel-3890
网址 hxxp://blah.com
        hxxp://foo.com, hxxp://foo2.com
一些文字 I不关心
更多文本我不关心
评论
--------- “这是 我需要 捕获
的多行评论” 一些文本我不关心 更多文本我不关心 日期 2013年 3 月 12 日





---文件结束---

对于每个文本文件,如果我只想将名称、代码和 URL 写入 CSV 文件。有人可以帮我做这件事吗?

我更像是一个 PERL 人,所以我知道我可以编写一个正则表达式来捕获以 Name 开头的单行。但是,我完全不知道如何阅读“代码”行,因为它可能是一行,或者可能是 X 行,直到我遇到 Urls 字段。

任何帮助将不胜感激!

4

5 回答 5

0

如果文件不是太大而无法在内存中处理,简单的方法是将其作为字符串数组读取。(太大意味着什么取决于您的系统。任何低于千兆字节的东西都应该可以正常工作,而无需太多麻烦。)

读取文件后,设置头尾计数器以指向元素零。将尾指针逐行向前移动,直到找到日期行。您可以将数据与正则表达式匹配。现在您知道了单个记录的开始和结束。对于下一条记录,将 head counter 设置为 tail+1,tail 设置为 tail+2,然后再次开始扫描行。起泡、冲洗、重复直到到达阵列末端。

当记录匹配时,您可以使用正则表达式提取名称。代码和网址有点棘手。将代码行与正则表达式匹配。提取它和所有接下来的行,除非它们与代码模式不匹配。Urls 数据也是如此。如果文件总是在作为先前 URL 和代码的数据的行上具有空格填充,则您也可以使用 match whitespace count 和正则表达式来获取数据行。

于 2013-03-13T07:39:31.710 回答
0

也许这会对它产生影响:

foreach ($Line in gc file.txt) {
    switch -regex ($Line) {
        '^(Name|Dept|Codes|Urls)' {
            $Capture = $true
            break
        }
        '^[A-Za-z0-9_-]+' {
            $Capture = $false
            break
        }
    }
    if ($Capture) {
        $Line
    }
}

如果您希望最终结果为 CSV 文件,则可以使用Export-Csvcmdlet。

于 2013-03-13T07:50:29.843 回答
0

如果所有文件都具有相同的结构,您可以执行以下操作:

$srcdir  = "C:\Test"
$outfile = "$srcdir\out.csv"

$re = '^Name (.*(?:\r\n .*)*)\r\n' +
      'Dept .*(?:\r\n .*)*\r\n' +
      'Codes (.*(?:\r\n .*)*)\r\n' +
      'Urls (.*(?:\r\n .*)*)' +
      '[\s\S]*$'

Get-ChildItem $srcdir -Filter *.txt | % {
  [io.file]::ReadAllText($_.FullName)
} | Select-String $re | % {
  $f = $_.Matches | % { $_.Groups } | ? { $_.Index -gt 0 }
  New-Object -TypeName PSObject -Prop @{
      'Name'  = $f[0].Value;
      'Codes' = $f[1].Value;
      'Urls'  = $f[2].Value;
    }
} | Export-Csv $outfile -NoTypeInformation
于 2013-03-13T10:18:05.670 回答
0

文本解析通常意味着正则表达式。使用正则表达式,有时您需要锚知道何时停止匹配,这可以让您关心您原本不会关心的文本。如果您可以指定“我不关心的某些文本”的第一行,您可以使用它来“锚定”您的 URL 匹配,以便您知道何时停止匹配。

$regex = @'
(?ms)Name (.+)?
 Dept .+?
 Codes (.+)?
 Urls (.+)?
 Some text I dont care about.+
 Comments
 ---------
 (.+)?
 Some text I dont care about 
'@

$file = 'c:\somedir\somefile.txt'
[IO.File]::ReadAllText($file) -match $regex
if ([IO.File]::ReadAllText($file) -match $regex)
  {
   $Name = $matches[1]
   $Codes = $matches[2] -replace '\s+',','
   $Urls = $matches[3] -replace '\s+',','
   $comment = $matches[4] -replace '\s+',' '
  }

$Name
$Codes
$Urls
$comment
于 2013-03-13T10:18:17.630 回答
0

根据包含的事实c:\temp\file.txt

Name John Smith
Dept Accounting
Codes bas-2349,cav-3928,deg-3942
      iye-2830,tel-3890
Urls hxxp://blah.com
     hxxp://foo.com
     hxxp://foo2.com
Some text I dont care about
More text i dont care about
.
.
Date 3/12/2013

您可以使用这样的正则表达式:

$a = Get-Content C:\temp\file.txt
$b = [regex]::match($a, "^.*Codes (.*)Urls (.*)Some.*$", "Multiline")
$codes = $b.groups[1].value -replace '[ ]{2,}',','
$urls = $b.groups[2].value -replace '[ ]{2,}',','
于 2013-03-13T21:25:31.890 回答