Sử dụng Perl để đếm số lượng số khoa học trong một tệp


10

Làm thế nào tôi có thể đếm số lượng số khoa học trong một tập tin? Các tập tin cũng có một vài dòng tiêu đề cần được bỏ qua.

Một phần nội dung của tập tin nằm ở bên dưới.

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

Vì vậy, làm thế nào tôi có thể bỏ qua bốn dòng đầu tiên của ví dụ trên và đếm số lượng số khoa học trong tệp?

Câu trả lời:


14

Với mô-đun lõi Scalar::Util, bạn có thể làm:

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

Thêm về looks_like_numbercó thể xem trong perldoc perlapi.


looks_like_number
Tuyệt

7

Sử dụng GNU grep

Bạn có thể sử dụng grepđể làm điều này, sử dụng các phương tiện PCRE. Ngẫu nhiên cũng có thể sử dụng cùng một mẫu trong Perl:

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

Bạn cũng có thể sử dụng wc -wđể đếm các từ, tôi đang đếm các dòng ở trên, nhưng greptrả về một kết quả khớp duy nhất trên một dòng để nó không thực sự quan trọng trong kịch bản đó.

Sử dụng Perl

Đối với Perl, bạn có thể sử dụng một lớp lót này:

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

Người giới thiệu


@StephaneChazelas - cảm ơn bạn đã chỉnh sửa. Xin lỗi, tôi chỉ ở trên các hệ thống GNU nên luôn có xu hướng quên điểm này mọi lúc. Tôi sẽ cố gắng không phạm sai lầm.
slm

4

egrep sẽ làm việc:

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

CẬP NHẬT:

nếu một dòng tình cờ chứa cả một số và một số chuỗi khác, chúng ta có thể sử dụng awkđể giải quyết vấn đề:

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 )

Điều này sẽ cho kết quả không chính xác nếu một dòng tình cờ chứa cả một số và một số chuỗi khác. Câu trả lời ở trên sử dụng tùy chọn -o của grep để chỉ khớp đầu ra là chính xác hơn.
Johnny

Trước đây tôi không biết về -oPtùy chọn được đề cập trong câu trả lời slm, nhưng tôi đã khắc phục vấn đề của mình bằng cách sử dụng awk@Johnny
Nidal

3

Giả sử bạn chỉ có số khoa học sau dòng thứ 4, bạn có thể làm một cái gì đó như dưới đây.

tail -n +5 filename | wc - w

Đối với đầu vào bạn đã cung cấp, đầu ra là 33 sau khi chạy lệnh trên.


3

Nếu bạn chỉ cần đếm số lượng các trường được phân tách bằng khoảng trắng theo các dòng tiêu đề trong perl, tôi nghĩ bạn có thể làm

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

Nếu bạn thực sự chỉ cần đếm các số có định dạng khoa học thì một cách tiếp cận có thể là tìm kiếm và thay thế các số theo một biểu thức thích hợp và sau đó đếm số lần thay thế (biểu thức thay thế perl trả về số lần thay thế khi bạn liên kết nó với một biến )

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

2

Tất cả đều thuộc về những gì bạn thực sự muốn xem xét một số khoa học , những gì bạn có thể mong đợi đầu vào của mình chứa và nơi bạn có thể chấp nhận để tìm những số đó trong đầu vào.

Ví dụ: trong:

That's inferior to the LK2E2000 model.

Tôi có thể tìm thấy các số 0 hoặc 2 (inf và 2E2000) hoặc 3 (inf, 2E200, 0) (hoặc được đưa đến cực trị, tìm kiếm tất cả các chuỗi ký tự tạo thành một số hợp lệ: 17 (inf, 2, 2E2, 2E20, 2E200, 2E200, 2E2000, 2, 20, 200, 2000, 0, 00, 000, 0, 00, 0)).

Nếu bạn biết đầu vào của mình chỉ có các số trong X.XXXXXXXXE-XXX và rằng chúng là những từ của riêng chúng, có thể an toàn hơn nếu chỉ tìm trong đó toàn bộ các từ như:

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

Ý tưởng ở đó là lấy một từ trên mỗi dòng và khớp toàn bộ dòng ( -x) với mẫu bạn muốn. Để cho phép bất kỳ số ký hiệu khoa học nào (-1.2e + 1234 ... miễn là có ehoặc E), bạn có thể thay đổi mẫu thành:

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

Hoặc làm cho e...phần tùy chọn để cho phép tất cả các loại số dấu phẩy động thập phân:

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

Tất cả đều đưa ra cùng một câu trả lời cho đầu vào cụ thể của bạn, nhưng điều đó sẽ tạo ra sự khác biệt là nơi có đầu vào rời khỏi mẫu nghiêm ngặt được hiển thị trong mẫu của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.