Thao tác định dạng khoa học mà không cần


8

Tôi đang cố gắng thao tác một tập tin chứa các số trong ký hiệu khoa học, nhưng không có eký hiệu, tức 1.2e+3là được viết là 1.2+3.

Cách dễ nhất tôi nghĩ làm awklà thay thế +bằng e+, sử dụng gsubhàm và thực hiện phép tính của tôi trong tệp mới. Điều tương tự cũng xảy ra đối với trường hợp trừ. Vì vậy, một sửa chữa đơn giản có thể được thực hiện bằng cách sử dụng lệnh sau đây

awk '{gsub("+", "e+", $1); print $1, $2, $3, $4, $5}' file_in

và làm tương tự trong tất cả các cột.

Tuy nhiên, tập tin cũng chứa các số âm làm cho mọi thứ phức tạp hơn một chút. Một tập tin mẫu có thể được nhìn thấy dưới đây

 1.056000+0 5.000000-1 2.454400-3 2.914800-2 8.141500-6
 2.043430+1 5.000000-1 2.750500-3 2.698100-2-2.034300-4
 3.829842+1 5.000000-1 1.969923-2 2.211364-2 9.499900-6
 4.168521+1 5.000000-1 1.601262-2 3.030919-2-3.372000-6
 6.661784+1 5.000000-1 5.250575-2 3.443669-2 2.585500-5
 7.278104+1 5.000000-1 2.137055-2 2.601701-2 8.999800-5
 9.077287+1 5.000000-1 1.320498-2 2.961020-2-1.011600-5
 9.248130+1 5.000000-1 3.069610-3 2.786329-2-6.317000-5
 1.049935+2 5.000000-1 4.218794-2 3.321955-2-5.097000-6
 1.216283+2 5.000000-1 1.432105-2 3.077165-2 4.300300-5

Bất kỳ ý tưởng về cách thao tác và tính toán với một tập tin như vậy?


2
Bạn muốn thực hiện các phép tính với định dạng như thế 2.698100e-2-2.034300e-4 như thế nào?
ctac_

3
Điều này có vẻ như có thể được phân tích cú pháp dưới dạng dữ liệu cột có chiều rộng cố định . Khoảng trắng rõ ràng giữa các cột chỉ là một tạo tác của định dạng số hiển thị các giá trị dương với khoảng trắng ở đầu thay vì dấu cộng.
Ilmari Karonen

Câu trả lời:


14

Đầu ra này có đúng không?

 1.056000e+0 5.000000e-1 2.454400e-3 2.914800e-2 8.141500e-6
 2.043430e+1 5.000000e-1 2.750500e-3 2.698100e-2-2.034300e-4
 3.829842e+1 5.000000e-1 1.969923e-2 2.211364e-2 9.499900e-6
 4.168521e+1 5.000000e-1 1.601262e-2 3.030919e-2-3.372000e-6
 6.661784e+1 5.000000e-1 5.250575e-2 3.443669e-2 2.585500e-5
 7.278104e+1 5.000000e-1 2.137055e-2 2.601701e-2 8.999800e-5
 9.077287e+1 5.000000e-1 1.320498e-2 2.961020e-2-1.011600e-5
 9.248130e+1 5.000000e-1 3.069610e-3 2.786329e-2-6.317000e-5
 1.049935e+2 5.000000e-1 4.218794e-2 3.321955e-2-5.097000e-6
 1.216283e+2 5.000000e-1 1.432105e-2 3.077165e-2 4.300300e-5

Mã số:

perl -lne 's/(\.\d+)(\+|\-)/\1e\2/g; print' sample

Giải trình:

  • -lne chăm sóc kết thúc dòng, xử lý từng dòng đầu vào, thực thi mã theo sau

  • s/(\.\d+)(\+|\-)/\1e\2/g:

    • thay thế ( s)
    • (.\d+)(\+|\-) tìm hai nhóm (một dấu chấm và số) và (cộng hoặc trừ)
    • \1e\2thay thế chúng bằng nhóm thứ nhất erồi đến nhóm thứ hai
    • g trên toàn cầu - không dừng lại ở sự thay thế đầu tiên trong mỗi dòng, nhưng xử lý tất cả các lần truy cập có thể
  • print in dòng

  • sample tập tin đầu vào

Cái này thêm không gian nếu nó thiếu. Trong thực tế, nó đặt không gian giữa các con số bất kể. I E. nếu có hai khoảng trắng trong một số trường hợp, sẽ chỉ có một khoảng trống ở đầu ra.

perl -lne 's/(\.\d+)(\+|\-)(\d+)(\s*)/\1e\2\3 /g; print' sample

Hầu hết nó tương tự như cái trước. Điều mới là (\d+)nhóm nr 3 và (\s*)nhóm nr 4. *ở đây có nghĩa là tùy chọn. Trong sự thay thế không \4được sử dụng. Có một không gian thay thế.

Đầu ra là thế này:

 1.056000e+0 5.000000e-1 2.454400e-3 2.914800e-2 8.141500e-6 
 2.043430e+1 5.000000e-1 2.750500e-3 2.698100e-2 -2.034300e-4 
 3.829842e+1 5.000000e-1 1.969923e-2 2.211364e-2 9.499900e-6 
 4.168521e+1 5.000000e-1 1.601262e-2 3.030919e-2 -3.372000e-6 
 6.661784e+1 5.000000e-1 5.250575e-2 3.443669e-2 2.585500e-5 
 7.278104e+1 5.000000e-1 2.137055e-2 2.601701e-2 8.999800e-5 
 9.077287e+1 5.000000e-1 1.320498e-2 2.961020e-2 -1.011600e-5 
 9.248130e+1 5.000000e-1 3.069610e-3 2.786329e-2 -6.317000e-5 
 1.049935e+2 5.000000e-1 4.218794e-2 3.321955e-2 -5.097000e-6 
 1.216283e+2 5.000000e-1 1.432105e-2 3.077165e-2 4.300300e-5 

Cảm ơn bạn rất nhiều cho câu trả lời! Vâng, có vẻ đúng !! Bạn có thể giải thích những gì bạn đã làm, để tham khảo trong tương lai?
Thanos

Cũng có thể tách cột cuối cùng ($ 5 $) khỏi cột trước đó bằng một khoảng trắng?
Thanos

Bạn thật hoàn hảo! Cảm ơn bạn rất nhiều vì đã giúp đỡ của bạn!
Thanos

@Thanos Xem bản cập nhật. Và thông báo tôi đã thêm một dấu gạch chéo ngược trước .trong nhóm đầu tiên. Chính xác. Không có dấu gạch chéo ngược này, dấu chấm sẽ không có nghĩa là dấu chấm.

2

Bạn cũng có thể sử dụng sed, ví dụ:

<infile sed -E 's/([0-9])([+-])([0-9])/\1e\2\3/g' | awk '{ print $1 + 0 }'

Tuy nhiên, điều này không tính đến việc các cột trong danh sách của OP đôi khi không được tách rời. Đây là một cách giải quyết với độ chính xác phù hợp:

<infile sed -E 's/.{11}/& /g'       |
sed -E 's/([0-9])([+-])/\1e\2/g'    |
gawk '{ print $1 + 0 }' OFMT='%.7g'

Đầu ra:

1.056
20.4343
38.29842
41.68521
66.61784
72.78104
90.77287
92.4813
104.9935
121.6283

Điều này loại bỏ độ phân giải khỏi các con số và tôi không chắc nó sẽ hoạt động khi giá trị âm nằm cạnh một giá trị khác giống như ví dụ trong câu hỏi2.698100-2-2.034300-4
ống

@pipe: Bạn nói đúng, tôi đã bỏ lỡ chi tiết đó. Tôi đã thêm một cách giải quyết bằng cách thêm không gian. Wrt. độ chính xác, tôi đã sử dụng OFMTbiến để đặt độ chính xác của awk giống với độ chính xác của đầu vào
Thor
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.