Использование Perl для подсчета количества научных чисел в файле

10

Как я могу посчитать количество научных номеров в файле? Файл также имеет несколько строк заголовка, которые необходимо пропустить.

Часть содержимого файла приведена ниже.

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

Итак, как мне пропустить первые четыре строки приведенного выше примера и посчитать количество научных чисел в файле?

AFP
источник

Ответы:

14

С основным модулем Scalar::Utilвы можете сделать:

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

Подробнее о looks_like_numberможно увидеть в perldoc perlapi.

cuonglm
источник
+1 круто, я не знал оlooks_like_number
Steeldriver
7

Использование GNU grep

Вы можете использовать grepдля этого, используя средства PCRE. Кстати, тот же шаблон можно использовать и в Perl:

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

Вы также можете использовать wc -wдля подсчета слов, я считаю строки выше, но grepвозвращает одно совпадение на строке, так что это не имеет значения в этом сценарии.

Использование Perl

Для Perl вы можете использовать этот вкладыш:

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

Ссылки

SLM
источник
@StephaneChazelas - спасибо за редактирование. Извините, я только нахожусь на системах GNU, поэтому склонен все время забывать об этом. Я постараюсь не совершить эту ошибку.
СЛМ
4

egrep будет работать:

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

ОБНОВИТЬ:

если строка содержит число и некоторую другую строку, мы можем использовать ее awkдля решения проблемы:

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 )
Нидал
источник
Это дало бы неверные результаты, если бы строка содержала как число, так и некоторую другую строку. Ответ выше, который использует опцию -o для вывода только совпадений, является более правильным.
Джонни
Я не знал об -oPопции , указанной в ОДСЕ ответа раньше, но я исправил мою проблему с помощью awk@Johnny
очаговые
3

Предполагая, что у вас есть только научные цифры после 4-й строки, вы можете сделать что-то вроде ниже.

tail -n +5 filename | wc - w

Для ввода, который вы предоставили, вывод 33 после выполнения вышеуказанной команды.

Рамеш
источник
3

Если вам нужно просто посчитать количество полей с пробелами после строк заголовка в Perl, я думаю, вы могли бы просто сделать

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

Если вам действительно нужно считать только числа, отформатированные с научной точки зрения, то одним из подходов может быть поиск и замена чисел в соответствии с подходящим регулярным выражением, а затем подсчет количества замен (выражение подстановки perl возвращает число замен при привязке его к переменной )

perl -lane '$sum += s/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?//g if $. > 4; END{print $sum}' file
steeldriver
источник
2

Все сводится к тому, что вы на самом деле хотите считать научным числом , что вы можете ожидать, чтобы содержать ваши входные данные, и где вы можете согласиться найти эти числа во входных данных.

Например, в:

That's inferior to the LK2E2000 model.

Я могу найти 0 или 2 (inf и 2E2000) или 3 (inf, 2E200, 0) числа (или доведенные до крайности, ища все последовательности символов, которые образуют действительное число: 17 (inf, 2, 2E2, 2E20, 2E200, 2E200, 2E2000, 2, 20, 200, 2000, 0, 00, 000, 0, 00, 0)).

Если вы знаете, что ваши входные данные содержат только цифры в X.XXXXXXXXE-XXX, и что они написаны на своих собственных словах, может быть безопаснее искать именно это в целых словах, таких как:

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

Идея заключается в том, чтобы получить одно слово в строке и сопоставить всю строку ( -x) с шаблоном, который вы хотите. Чтобы разрешить любой научный номер записи (-1.2e + 1234 ... до тех пор, пока есть eили или E), вы можете изменить шаблон на:

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

Или сделайте e...часть необязательной, чтобы разрешить все виды десятичных чисел с плавающей запятой:

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

Это все дает один и тот же ответ для вашего конкретного ввода, но где это будет иметь значение, это где ввод, который отличается от строгого шаблона, показанного в вашем примере.

Стефан Шазелас
источник