PowerShell正規表現の苦労

Oct 16 2020

これは私の最初の投稿であり、他の投稿を読んだり検索したりすることで必要なものを見つけることができる傾向がありますが、これは私を打ち負かしました。Powershellで正規表現を使用して、テキストファイル内のデータを検索しようとしています。

サンプルテキストファイル:(サンプルテキストファイルには、その行の終わりまでスペースがあります)

 Impression            CONCLUSION:                                                                     
 Impression                        
            
 Impression            CONCLUSION:                                                                     
 Impression            SomeData

 Impression            CONCLUSION:                                                                     
 Impression            SomeOtherData

 Impression            CONCLUSION:                                                                     
 Impression                                         

結論のある行の後に2行目が空白になっている場所を探しています。

これが私の単純な試みの基礎でした:

Get-Content -Path "C:\temp\Log\Conclusion.txt" | Select-String -Pattern "CONCLUSION:\s*\r\n\s*Impression\s*\r\n\s*Impression" -Context 1, 1

\ r \ nのあるものは、結果を返さないことがわかりました。\ rと\ nの両方を単独で試し、コンテンツをRawとして取得しようとしましたが、ファイル全体が再度出力されます。助けていただければ幸いです、ありがとうございます。

更新:皆さんの回答に感謝します。結論の後に空の行を見つけようとしていたことを明記する必要がありました。Get-Content -Rawを使用して、初心者のためにカウントを取得することになりました。サンプルデータを少し変更して、impressionという単語を含む別の空白行を追加しました:名前/場所Impression結論:
Impression Impression

このコードは私にカウントを得ることができました:(別のフォーラム投稿からプル/変更されました、私はこれを思いついたことを信用していません)

$ search_string = "\ s結論:\ s \ r \ n \ s印象\ s \ r \ n \ s印象\ s \ r \ n \ s印象\ s \ r \ n" $ file_path = "C:\ temp \ Log \ Conclusion.txt "$string = (Get-Content -raw -Path $file_path | 選択文字列$search_string -AllMatches | % { $_.matches})。count

Rawを使用しない場合にのみ機能するデータをさらに印刷する方法をまだ検討中です。コンテキストを使用して結論の上の行を取得することを計画していましたが、rawはすべてを1行にまとめるため、機能しません。助けてくれてありがとう。\ r \ nを使用してRawを使用しないことについて、他にヒントがあれば教えてください。

回答

paddywan Oct 16 2020 at 20:50

これがPowerShellでどの程度うまく機能するかはわかりませんが、これを試してみてください。 (*CRLF)CONCLUSION:\sImpression\s\s

https://regex101.com/r/d6Pm2k/1

Brian Oct 16 2020 at 21:46

これが私の醜いブルートフォース攻撃です:

$blankRows = @() $targetRows = @()
$rowNum = 0 $foundRows = @()

$myFile = Get-Content $thisFile

Foreach($thisRow in $myFile){
    $rowNum++ if($thisRow -eq "Impression"){$blankRows += $rowNum}
    if ($thisRow -match 'CONCLUSION'){$targetRows += $rowNum} } Foreach($blrw in $blankRows){ if ($targetRows -contains ($blrw-1)){$foundRows += $blrw} } $foundRows
postanote Oct 17 2020 at 23:16

なぜこれをしないのですか?

# Create some sample data file
@'
Impression CONCLUSION:
Impression

Impression CONCLUSION:
Impression SomeData

Impression CONCLUSION:
Impression SomeOtherData

Impression CONCLUSION:
Impression
'@ | 
Out-File -FilePath 'D:\Temp\Imprestion.txt' -Force
Get-Content -Path 'D:\Temp\Imprestion.txt'
# Results
<#
Impression CONCLUSION:
Impression

Impression CONCLUSION:
Impression SomeData

Impression CONCLUSION:
Impression SomeOtherData

Impression CONCLUSION:
Impression
#>

# Import the sample data file as a CSV, use the space as a Delimiter
Import-Csv -Path 'D:\Temp\Imprestion.txt' -Delimiter ' ' -Header Property, Value
# Results
<#
Property   Value        
--------   -----        
Impression CONCLUSION:  
Impression              
Impression CONCLUSION:  
Impression SomeData     
Impression CONCLUSION:  
Impression SomeOtherData
Impression CONCLUSION:  
Impression              
#>

# Filter by the Value property
Import-Csv -Path 'D:\Temp\Imprestion.txt' -Delimiter ' ' -Header Property, Value | 
Where-Object -Property Value -EQ $null # Results <# Property Value -------- ----- Impression Impression #> # Using Select-String and a RegEx 'Not Match' Select-String -Path 'D:\Temp\Imprestion.txt' -Pattern '^((?!Impression [a-zA-Z]).)*$'
# Results
<#
D:\Temp\Imprestion.txt:2:Impression
D:\Temp\Imprestion.txt:3:
D:\Temp\Imprestion.txt:6:
D:\Temp\Imprestion.txt:9:
D:\Temp\Imprestion.txt:11:Impression
#>

# Using Select-String and RegEx match
Select-String -Path 'D:\Temp\Imprestion.txt' -Pattern '^Impression\s*$'
# Results
<#
D:\Temp\Imprestion.txt:2:Impression
D:\Temp\Imprestion.txt:11:Impression
#>

説明:

  • ^は文字列アンカーの始まりです。
  • $は文字列アンカーの終わりです。
  • \ sは空白文字クラスです。
  • の0回以上の繰り返しです。
KeithMiller Oct 17 2020 at 04:25

何をキャプチャしたいのか、完全に空白の行なのか、Impressionデータがない行なのか、まだ正確にはわかりません。

しかし、ドキュメントによると、Get-Contnet:

  • ファイルの場合、コンテンツは一度に1行ずつ読み取られ、オブジェクトのコレクションを返します。各オブジェクトはコンテンツの行を表します。

SO<newline>文字は、文字列配列の要素seperatorsとして「消費」されています。
試してみてください:

Get-Content -Path "C:\temp\Log\Conclusion.txt" | gm
(Get-Content -Path "C:\temp\Log\Conclusion.txt").Count

したがって、a<newline>を記述されたコードと一致させることは決してありません。

-Rawパラメータを使用して、ファイルを文字を含む1つの長い文字列として扱っ<newline>たり、配列を検索するためのロジックを書き直したりできます。


また、Select-stringのドキュメントには、ファイルを直接取得して、を必要とせずに1行ずつ処理できることが示されていますGet-Content。


更新

どの行を出力したいかはまだわかりませんが、ここにあなたが求めていると思うもののスケルトンサンプルがあります。私の仮定は次のとおりです。

  • 探している行は、「Impression」の後にテキストがない行です(これがリテラルかデータかを明確にしてください)
  • 一致するものが見つかると、前の行が出力ファイル用にキャプチャされます。
$File = Get-Content -Path "C:\temp\Log\Conclusion.txt" $OutLines   = @()
$EmptyMatch = '^Impression\s*$'
$i = 0 ForEach ( $line in $File ) { If ( $line -match $EmptyMatch ) { $OutLines += $File[ $i - 1 ]
    }
    $i++ } $OutLines | Set-Content 'c:\MyStuff\OutFile.txt'
Add