Le espressioni regolari di PowerShell hanno problemi

Oct 16 2020

Questo è il mio primo post, tendo a trovare quello che mi serve leggendo e cercando altri post, ma questo mi ha sconfitto. Sto cercando di utilizzare un'espressione regolare in Powershell per cercare dati in un file di testo.

File di testo di esempio: (ci sono spazi nel file di testo di esempio fino alla fine di quella riga)

 Impression            CONCLUSION:                                                                     
 Impression                        
            
 Impression            CONCLUSION:                                                                     
 Impression            SomeData

 Impression            CONCLUSION:                                                                     
 Impression            SomeOtherData

 Impression            CONCLUSION:                                                                     
 Impression                                         

Sto cercando di trovare dove la seconda riga è vuota dopo la riga con la conclusione.

Questa è stata la base del mio semplice tentativo:

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

Ho scoperto che qualsiasi cosa con \ r \ n non restituisce alcun risultato. Ho provato entrambi \ r e \ n da soli, ho tentato di ottenere il contenuto come Raw, ma questo restituisce nuovamente l'intero file. L'aiuto è apprezzato, grazie.

Aggiornamento: grazie per le risposte di tutti, avrei dovuto specificare che stavo tentando di trovare righe dopo la conclusione che erano vuote. Ho finito per ottenere un conteggio per lavorare per i principianti utilizzando Get-Content -Raw. I miei dati di esempio sono cambiati leggermente per aggiungere un'altra riga vuota con la parola impressione: nome / posizione impressione CONCLUSIONE:
impressione impressione

Questo codice è stato in grado di farmi un conteggio: (estratto / modificato da un altro post del forum, non mi prendo il merito di averlo inventato)

$ search_string = "\ s CONCLUSIONE: \ s \ r \ n \ s Impression \ s \ r \ n \ s Impression \ s \ r \ n \ s Impression \ s \ r \ n" $ file_path = "C: \ temp \ Log \ Conclusion.txt "$string = (Get-Content -raw -Path $file_path | Select-String$search_string -AllMatches | % { $_.matches}). count

Sto ancora lavorando a un modo per stampare altri dati che funzionerebbero solo quando non si utilizza Raw, avevo pianificato di utilizzare il contesto per afferrare la riga sopra la conclusione, ma poiché raw riunisce tutto in una riga, ciò non funziona. Grazie ancora per l'aiuto, se qualcuno ha altri suggerimenti su come usare \ r \ ne non usare Raw, fammelo sapere.

Risposte

paddywan Oct 16 2020 at 20:50

Non sono sicuro di quanto funzionerà bene con PowerShell, ma provalo: (*CRLF)CONCLUSION:\sImpression\s\s

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

Brian Oct 16 2020 at 21:46

Ecco il mio brutto attacco di forza bruta:

$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

Perché non farlo semplicemente?

# 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
#>

Spiegazione:

  • ^ è l'inizio dell'ancora di stringa.
  • $ è la fine dell'ancora di stringa.
  • \ s è la classe di caratteri dello spazio vuoto.
  • è zero o più ripetizioni di.
KeithMiller Oct 17 2020 at 04:25

Non sono ancora sicuro di cosa vuoi catturare, le righe completamente vuote o quelle con Impressione nessun dato che segue.

Ma secondo la documentazione, Get-Contnet :

  • Per i file, il contenuto viene letto una riga alla volta e restituisce una raccolta di oggetti, ognuno dei quali rappresenta una riga di contenuto.

COSÌ i <newline>caratteri vengono "consumati" come separatori di elementi di un array di stringhe.
Provare:

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

quindi non abbinerai mai a <newline>con il codice come scritto.

È possibile utilizzare il -Rawparametro per trattare il file come una lunga stringa di <newline>caratteri o riscrivere la logica per la ricerca in un array.


Inoltre, la documentazione per Select-string mostra che può prendere un file direttamente ed elaborarlo riga per riga, senza bisogno di Get-Content.


Aggiornare

Non sono ancora sicuro di quale riga si desidera produrre, ma ecco un esempio scheletrico di ciò che penso tu stia chiedendo. Le mie ipotesi sono:

  • Le righe che stai cercando sono quelle senza testo dopo "Impressione" (chiarisci se questo è letterale o dati)
  • Quando viene trovata una corrispondenza, la riga precedente viene acquisita per il file di output.
$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