2009-08-11 7 views
4

J'ai un fichier délimité par des tabulations. Je voudrais un script PowerShell qui compte le nombre d'onglets dans chaque ligne. Je suis venu avec ceci:Oneliner compte le nombre d'onglets dans chaque ligne d'un fichier

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

il donne 3, qui est le nombre de lignes dans le fichier.

des pointeurs à ce que je fais mal? Je voudrais qu'il imprime un seul nombre pour chaque ligne dans le fichier.

Répondre

6

Un couple émet des problèmes avec votre code, mais tous tournent autour de la gestion de groupe/gestion de groupe/boucles imbriquées.

gc test.txt | % { ($_ | select-string `t -all).matches | measure | select count } 
  • Après avoir lu le fichier texte en lignes, vous devez envelopper le reste du pipeline dans un scriptblock. Sinon, les applets de commande en aval ne peuvent pas distinguer les éléments issus de la ligne "en cours". Le pipeline PS consiste à traiter les objets un à un - il n'y a pas de concept de tableaux imbriqués ou d'état d'itérateur ou autre chose - énumération aveugle.
  • Vous devez spécifier -AllMatches, sinon select-string s'arrêtera dès qu'il trouvera la première correspondance sur chaque ligne. Vous devez ensuite obtenir la propriété Matches de son jeu de résultats nominal pour obtenir le "resultset interne" de cette correspondance intra-ligne.
+0

+1. Belle explication pourquoi son code original n'a pas fonctionné. Probablement plus qu'une simple solution :-) (aussi je l'aurais fait mais je n'ai jamais utilisé Select-String :-)) – Joey

+0

Je ne comprends toujours pas quand utiliser le scriptblock. J'ai aussi remarqué que les deux solutions utilisent gc au lieu de consommer le fichier avec $ {fichier.txt} est-ce juste une question de style? – JasonHorner

+0

Lors de l'utilisation de '$ {...}', vous devez placer le chemin absolu complet entre les accolades, tandis que 'Get-Content' permet d'utiliser des chemins relatifs. En ce qui me concerne, je n'ai pas de fichiers utilisateurs dans 'C: \', donc ce serait toujours quelque chose comme '$ {C: \ Users \ me \ ...}' qui est lourd (ok, je créé un lecteur 'Home:' mais je n'aime pas les chemins absolus :-). De plus, 'Get-Content' vous donne une exception quand il ne trouve pas quelque chose, ce qui est parfois utile pour déboguer des échecs bizarres :-) – Joey

5

Première tentative, pas très sophistiqué:

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

En utilisant le fait ici, que lorsque je divise la chaîne en caractères de tabulation, je vais un tableau avec un élément de plus que il y a des onglets la ligne.

Une autre approche, le fractionnement en évitant les lignes:

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

Les chaînes peuvent être jetés à char[] (également il y a la méthode ToCharArray()), alors je suis en utilisant le fait que les opérateurs de comparaison fonctionnent différemment sur les collections, en retournant tous les éléments correspondants, au lieu d'un booléen. Donc, la comparaison retourne un tableau contenant tous les onglets de la ligne d'origine à partir de laquelle j'ai juste besoin d'obtenir le nombre d'éléments.

+0

Convertir en char [], puis en utilisant -eq pour dérouler automatiquement le tableau est intelligent. +1 –

+0

Essayer le golf de golf avec Powershell a ses mérites :-) – Joey

+0

C'est probablement la "meilleure" réponse mais l'autre poste a mieux répondu à ma question d'origine Merci pour votre aide – JasonHorner

2

Une autre option:

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

Et encore une autre option si vous exécutez V2.

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