2009-08-11 5 views
4

Ich habe eine Datei, die tabulatorgetrennt ist. Ich möchte ein Powershell-Skript, das die Anzahl der Registerkarten in jeder Zeile zählt. Ich kam mit diesem:Oneliner zum Zählen der Anzahl der Registerkarten in jeder Zeile einer Datei

${C:\tabfile.txt} |% {$_} | Select-String \t | Measure-Object | fl count 

es ergibt 3, die die Anzahl der Zeilen in der Datei ist.

irgendwelche Hinweise auf was ich falsch mache? Ich möchte, dass eine einzelne Nummer für jede Zeile in der Datei gedruckt wird.

Antwort

6

Ein paar Probleme mit Ihrem Code, aber alle drehen sich um Gruppierung/Array-Verwaltung/verschachtelte Schleifen.

gc test.txt | % { ($_ | select-string `t -all).matches | measure | select count } 
  • Nachdem die Textdatei in Zeilen lesen, müssen Sie den Rest der Pipeline in eine Skript wickeln. Andernfalls können Downstream-Cmdlets nicht unterscheiden, welche Elemente aus der "aktuellen" Zeile stammen. In der PS-Pipeline geht es nur darum, sich nacheinander um Objekte zu kümmern - es gibt kein Konzept verschachtelter Arrays oder Iterator-Zustände oder irgendetwas anderes - Blind Enumeration.
  • Sie müssen -AllMatches angeben, andernfalls wird die Auswahl-Zeichenfolge gestoppt, sobald die erste Übereinstimmung in jeder Zeile gefunden wird. Sie müssen dann die Übereinstimmungseigenschaft von ihrem nominalen Resultset abrufen, um das "innere Resultset" dieses Intra-Line-Matchings zu erhalten.
+0

+1. Schöne Erklärung, warum sein ursprünglicher Code nicht funktioniert hat. Wahrscheinlich hilft mehr als nur eine Lösung :-) (ich hätte es auch gemacht, aber ich habe nie Select-String benutzt :-)) – Joey

+0

Ich bin immer noch verwirrt, wenn ich den Scriptblock benutze. Ich habe auch bemerkt, dass beide Lösungen GC verwenden, anstatt die Datei mit $ {file.txt} zu konsumieren, ist das nur eine Frage des Stils? – JasonHorner

+0

Wenn Sie '$ {...}' verwenden, müssen Sie den vollständigen absoluten Pfad zwischen den Klammern setzen, während 'Get-Content' die Verwendung relativer Pfade erlaubt. Was mich betrifft, habe ich keine Benutzerdateien in 'C: \' herumliegen, also wäre es immer etwas wie '$ {C: \ Users \ me \ ...}' was umständlich ist (ok, ich Ich habe ein 'Home:' Laufwerk erstellt, aber trotzdem mag ich keine absoluten Pfade :-). Auch 'Get-Content' gibt Ihnen eine Ausnahme, wenn es etwas nicht finden kann, was manchmal nützlich ist, um seltsame Fehler zu debuggen :-) – Joey

5

Erster Versuch, nicht sehr anspruchsvoll:

gc .\tabfile.txt | % { ($_ -split "`t").Count - 1 } 

die Tatsache, hier verwendet wird, dass, wenn ich die Zeichenfolge in Tabulatoren geteilt, ich werde ein Array mit einem weiteren Einzelteil erhalten, als es Registerkarten die Linie.

Ein weiterer Ansatz, die Vermeidung Aufspaltung der Linien:

gc .\tabfile.txt | % { ([char[]] $_ -eq "`t").Count } 

Strings char[] gegossen werden kann (auch dort ist die ToCharArray()-Methode), dann verwende ich die Tatsache, dass Vergleichsoperatoren auf Sammlungen anders arbeiten, durch Rücksendung alle übereinstimmenden Elemente anstelle eines Booleschen. Der Vergleich gibt also ein Array zurück, das alle Registerkarten der ursprünglichen Zeile enthält, aus der ich nur die Anzahl der Elemente abfragen muss.

+0

Umwandlung in char [] und dann -eq zum automatischen Ausrollen des Arrays ist clever. +1 –

+0

Probieren Code Golf mit Powershell hat seine Vorzüge :-) – Joey

+0

Dies ist wahrscheinlich die "bessere" Antwort, aber der andere Beitrag beantwortet meine ursprüngliche Frage besser. Vielen Dank für Ihre Hilfe – JasonHorner

2

Eine weitere Option:

$content = Get-Content file.txt | Out-String 
[regex]::matches($content,"\t").count 
4

Und noch eine weitere Option, wenn Sie V2 ausgeführt werden.

select-string \t c:\tabfile.txt -All | 
    %{"$($_.matches.count) tabs on $($_.LineNumber)"} 
Verwandte Themen