Usando Perl para contar la cantidad de números científicos en un archivo

10

¿Cómo puedo contar la cantidad de números científicos en un archivo? El archivo también tiene algunas líneas de encabezado que deben omitirse.

Una parte del contenido del archivo se encuentra a continuación.

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

Entonces, ¿cómo puedo omitir las primeras cuatro líneas del ejemplo anterior y contar el número de números científicos en el archivo?

AFP
fuente

Respuestas:

14

Con el módulo central Scalar::Util, puede hacer:

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

Más sobre looks_like_numberpuede ver en perldoc perlapi.

Cuonglm
fuente
+1 genial, no lo sabíalooks_like_number
steeldriver
7

Usando GNU grep

Puede grephacer esto, utilizando las instalaciones de PCRE. Por cierto, también se puede usar el mismo patrón en Perl:

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

También puede usar wc -wpara contar palabras, estoy contando líneas arriba, pero grepdevuelve una sola coincidencia en una línea, por lo que realmente no importa en ese escenario.

Usando Perl

Para Perl, podría usar este revestimiento:

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

Referencias

slm
fuente
@StephaneChazelas: gracias por la edición. Lo siento, solo uso sistemas GNU, así que tiendo a olvidar este punto todo el tiempo. Intentaré no cometer ese error.
slm
4

egrep trabajará:

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

ACTUALIZAR:

Si una línea contiene tanto un número como alguna otra cadena, podemos usarla awkpara resolver el problema:

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
fuente
Esto daría resultados incorrectos si una línea tuviera tanto un número como alguna otra cadena. La respuesta anterior que usa la opción -p de grep para generar solo coincidencias es más correcta.
Johnny
No sabía sobre la -oPopción mencionada en la respuesta de slm antes, pero he solucionado mi problema usando awk@Johnny
Nidal
3

Suponiendo que solo tiene números científicos después de la cuarta línea, puede hacer algo como a continuación.

tail -n +5 filename | wc - w

Para la entrada que ha proporcionado, la salida es 33 después de ejecutar el comando anterior.

Ramesh
fuente
3

Si necesita simplemente contar el número de campos delimitados por espacios en blanco que siguen a las líneas de encabezado en perl, creo que podría hacer

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

Si realmente necesita contar solo números con formato científico, entonces un enfoque podría ser buscar y reemplazar números de acuerdo con una expresión regular adecuada y luego contar el número de reemplazos (la expresión de sustitución perl devuelve el número de reemplazos cuando lo vincula a una variable )

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

Todo se reduce a lo que realmente desea considerar un número científico , lo que puede esperar que contenga su entrada y dónde puede aceptar encontrar esos números en la entrada.

Por ejemplo, en:

That's inferior to the LK2E2000 model.

Puedo encontrar 0 o 2 (inf y 2E2000) o 3 (inf, 2E200, 0) números (o llevados al extremo, buscando todas las secuencias de caracteres que forman un número válido: 17 (inf, 2, 2E2, 2E20, 2E200, 2E200, 2E2000, 2, 20, 200, 2000, 0, 00, 000, 0, 00, 0)).

Si sabe que su entrada solo tiene números en X.XXXXXXXXE-XXX, y que están en sus propias palabras, puede ser más seguro buscar eso solo en palabras completas como:

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

La idea allí es obtener una palabra por línea y hacer coincidir la línea completa ( -x) con el patrón que desee. Para permitir cualquier número de notación científica (-1.2e + 1234 ... siempre que haya un eo E), puede cambiar el patrón a:

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

O haga que la e...parte sea opcional para permitir todo tipo de números decimales de coma flotante:

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

Todo eso da la misma respuesta para su entrada específica, pero donde eso marcaría la diferencia es donde hay una entrada que se aparta del patrón estricto que se muestra en su muestra.

Stéphane Chazelas
fuente