Використання 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

Отже, як я можу пропустити перші чотири рядки прикладу вище та порахувати кількість наукових чисел у файлі?

Відповіді:


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.


+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

Список літератури


@StephaneChazelas - дякую за редагування. Вибачте, що я лише коли-небудь перебуваю в системах GNU, тому, як правило, весь час забуваю цей пункт. Я спробую не помилитися.
slm

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 )

Це дало б невірні результати, якби у рядку було як число, так і деякий інший рядок. Відповідь вище, що використовує опцію grep's -o для виведення лише збігів, є правильнішою.
Джонні

Я раніше не знав про -oPваріант, про який згадували у відповіді slm, але я awkвирішив свою проблему за допомогою @Johnny
Nidal

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

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.X.XXXXXXXE-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]+)?

Все це дає однакову відповідь для вашого конкретного вкладу, але там, де це змінило б, є те, де є вхід, який відходить від суворого шаблону, показаного у вашій вибірці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.