Utiliser Perl pour compter le nombre de nombres scientifiques dans un fichier

10

Comment puis-je compter le nombre de numéros scientifiques dans un fichier? Le fichier contient également quelques lignes d'en-tête qui doivent être ignorées.

Une partie du contenu du fichier se trouve ci-dessous.

FileHeaderLine1
FileHeaderLine2
FileHeaderLine3
FileHeaderLine4
2.91999996E-001 2.97030300E-001 3.02060604E-001 3.07090908E-001 3.12121212E-001 3.17151517E-001
3.22181821E-001 3.27212125E-001 3.32242429E-001 3.37272733E-001 3.42303038E-001 3.47333342E-001
3.52363646E-001 3.57393950E-001 3.62424254E-001 3.67454559E-001 3.72484863E-001 3.77515137E-001
3.82545441E-001 3.87575746E-001 3.92606050E-001 3.97636354E-001 4.02666658E-001 4.07696962E-001
4.12727267E-001 4.17757571E-001 4.22787875E-001 4.27818179E-001 4.32848483E-001 4.37878788E-001
4.42909092E-001 4.47939396E-001 4.52969700E-001

Alors, comment puis-je ignorer les quatre premières lignes de l'exemple ci-dessus et compter le nombre de nombres scientifiques dans le fichier?

AFP
la source

Réponses:

14

Avec le module de base Scalar::Util, vous pouvez faire:

$ perl -MScalar::Util=looks_like_number -anle '
    $count += grep { looks_like_number($_) } @F;
    END { print $count }
' file
33

Plus d'informations sur looks_like_numberpeuvent voir dans perldoc perlapi.

cuonglm
la source
+1 cool, je ne savais paslooks_like_number
steeldriver
7

Utiliser GNU grep

Vous pouvez utiliser greppour ce faire, en utilisant les fonctionnalités PCRE. Par ailleurs, le même modèle peut également être utilisé en Perl:

$ grep -oP '\d+E[-+]?\d+' file.txt  | wc -l
33

Vous pouvez également utiliser wc -wpour compter les mots, je compte les lignes ci-dessus, mais le grepretourne une seule correspondance sur une ligne, donc cela n'a pas vraiment d'importance dans ce scénario.

Utiliser Perl

Pour Perl, vous pouvez utiliser cette doublure:

$ perl -lane '$c += grep /\d+E[-+]?\d+/, @F; END { print $c; }' file.txt 
33

Références

slm
la source
@StephaneChazelas - merci pour la modification. Désolé, je ne suis que sur des systèmes GNU, alors j'ai tendance à oublier ce point tout le temps. Je vais essayer de ne pas faire cette erreur.
slm
4

egrep marchera:

egrep "[0-9].[0-9]E-[0-9]" YourFile | wc -w

METTRE À JOUR:

si une ligne contenait à la fois un nombre et une autre chaîne, nous pouvons utiliser awkpour résoudre le problème:

awk -F' ' '{for(i=1;i<=NF;i++)if(!(i%1))$i=$i "\n"}1' YourFile | egrep "[0-9].[0-9]E-[0-9]" | wc -w ( or wc -l )
Nidal
la source
Cela donnerait des résultats incorrects si une ligne contenait à la fois un nombre et une autre chaîne. La réponse ci-dessus qui utilise l'option -o de grep pour afficher uniquement les correspondances est plus correcte.
Johnny
Je ne connaissais pas l' -oPoption mentionnée dans la réponse slm auparavant, mais j'ai résolu mon problème en utilisant awk@Johnny
Nidal
3

En supposant que vous n'avez que des chiffres scientifiques après la 4e ligne, vous pouvez faire quelque chose comme ci-dessous.

tail -n +5 filename | wc - w

Pour l'entrée que vous avez fournie, la sortie est 33 après l'exécution de la commande ci-dessus.

Ramesh
la source
3

Si vous avez simplement besoin de compter le nombre de champs délimités par des espaces suivant les lignes d'en-tête en perl, je pense que vous pourriez simplement faire

perl -lane '$sum += $#F+1 if $. > 4; END{print $sum}' file

Si vous avez vraiment besoin de compter uniquement des nombres au format scientifique, une approche pourrait être de rechercher et de remplacer des nombres selon une expression rationnelle appropriée , puis de compter le nombre de remplacements (l'expression de substitution perl renvoie le nombre de remplacements lorsque vous le liez à une variable )

perl -lane '$sum += s/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?//g if $. > 4; END{print $sum}' file
tournevis
la source
2

Tout dépend de ce que vous voulez réellement considérer comme un numéro scientifique , de ce que vous pouvez vous attendre à ce que votre entrée contienne et où vous pouvez accepter de trouver ces nombres dans l'entrée.

Par exemple, dans:

That's inferior to the LK2E2000 model.

Je peux trouver 0 ou 2 (inf et 2E2000) ou 3 (inf, 2E200, 0) nombres (ou poussés à l'extrême, en recherchant toutes les séquences de caractères qui forment un nombre valide: 17 (inf, 2, 2E2, 2E20, 2E200, 2E200, 2E2000, 2, 20, 200, 2000, 0, 00, 000, 0, 00, 0)).

Si vous savez que votre entrée ne contient que des chiffres dans le X.XXXXXXXXE-XXX et qu'ils sont sur des mots qui leur sont propres, il peut être plus sûr de chercher juste cela dans des mots entiers comme:

tr -s '[[:blank:]]' '[\n*]' | LC_ALL=C grep -xEc '[0-9]\.[0-9]{8}E-[0-9]{3}'

L'idée est d'obtenir un mot par ligne et de faire correspondre la ligne entière ( -x) avec le motif souhaité. Pour autoriser n'importe quel numéro de notation scientify (-1.2e + 1234 ... tant qu'il y a un eou E), vous pouvez changer le modèle en:

[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9])[eE][-+]?[0-9]+

Ou rendez la e...partie facultative pour autoriser toutes sortes de nombres décimaux à virgule flottante:

[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9])([eE][-+]?[0-9]+)?

Tout cela donne la même réponse pour votre entrée spécifique, mais là où cela ferait une différence, c'est là où il y a une entrée qui s'écarte du modèle strict montré dans votre échantillon.

Stéphane Chazelas
la source