2012-08-28 34 views
5

Sự cố: Tôi có dữ liệu (chủ yếu ở định dạng CSV) được tạo trên cả Windows và * nix và được xử lý chủ yếu trên * nix. Windows sử dụng CRLF cho kết thúc dòng và Unix sử dụng LF. Đối với bất kỳ tập tin cụ thể tôi không biết liệu nó có cửa sổ hoặc kết thúc dòng * nix. Cho đến bây giờ, tôi đã viết một cái gì đó như thế này để xử lý chênh lệch:Phát hiện đúng dòng cuối của một tệp trong Perl?

while (<$fh>){ 
    tr/\r\n//d; 
    my @fields = split /,/, $_; 
    # ... 
} 

On * nix phần \ n tương đương với nhai, và thêm vào đó được thoát khỏi \ r (CR) nếu đó là một cửa sổ -tập tin được sản xuất.

Nhưng bây giờ tôi muốn văn bản :: CSV_XS b/c Tôi bắt đầu nhận được các tệp dữ liệu khác với dữ liệu được trích dẫn, có khả năng với ngắt dòng nhúng, v.v. Để có được mô-đun này đọc các tệp như vậy, Văn bản :: CSV_XS :: getline() yêu cầu bạn chỉ định các ký tự cuối dòng. (Tôi không thể đọc từng dòng như trên, tr/\ n \ r // d và phân tích cú pháp nó bằng Văn bản :: CSV b/c sẽ không xử lý được ngắt dòng được nhúng đúng cách). Làm cách nào để đúng cách phát hiện xem tệp tùy ý có sử dụng các cửa sổ hoặc dòng kết thúc kiểu * nix hay không, vì vậy tôi có thể cho biết Text :: CSV_XS :: eol() cách chomp()?

Tôi không thể tìm thấy một mô-đun trên CPAN chỉ đơn giản là phát hiện kết thúc dòng. Tôi không muốn đầu tiên chuyển đổi tất cả các datafile của tôi thông qua dos2unix, b/c các tập tin là rất lớn (hàng trăm gigabyte), và chi tiêu 10 + phút cho mỗi tập tin để đối phó với một cái gì đó rất đơn giản có vẻ ngớ ngẩn. Tôi nghĩ về việc viết một hàm đọc hàng trăm byte đầu tiên của một tệp và đếm LF so với CRLF, nhưng tôi từ chối tin rằng điều này không có giải pháp tốt hơn.

Bất kỳ trợ giúp nào?

Lưu ý: tất cả các tệp đều có phần cuối dòng cửa sổ hoặc đầu cuối * nix, nghĩa là chúng không được trộn lẫn trong một tệp.

Trả lời

9

Bạn chỉ có thể mở tệp bằng cách sử dụng :crlfPerlIO layer và sau đó yêu cầu Text::CSV_XS sử dụng \n làm ký tự kết thúc dòng. Điều này sẽ âm thầm ánh xạ bất kỳ cặp CR/LF nào tới nguồn cấp dữ liệu dòng đơn, nhưng đó có lẽ là những gì bạn muốn.

use Text::CSV_XS; 
my $csv = Text::CSV_XS->new({ binary => 1, eol => "\n" }); 

open($fh, '<:crlf', 'data.csv') or die $!; 

while (my $row = $csv->getline($fh)) { 
    # do something with $row 
} 
+0

Cảm ơn bạn, tôi chưa bao giờ biết về PerlIO trước đây. Đây chính xác là những gì tôi cần. – user1481

3

Đọc ở dòng đầu tiên của mỗi tệp, xem ký tự cuối cùng của một tệp. Nếu nó là \r, tệp đến từ Windows, nếu không, nó là * nix. Sau đó, seek để bắt đầu và bắt đầu xử lý.

Nếu có thể tệp có kết thúc dòng hỗn hợp (ví dụ: loại khác nhau cho dòng mới được nhúng), bạn chỉ có thể đoán.

1

Trong dòng lý thuyết không thể xác định được một cách đáng tin cậy: Tệp này là một dòng có dòng kết thúc DOS có nhúng \n s hoặc đây có phải là một loạt các dòng với một vài ký tự đi lạc ở cuối một số dòng không?

foo\n 
ba\r\n 

so

foo\nba\r\n 

Nếu phân tích thống kê không phải là một lựa chọn vì nó là quá thiếu chính xác và tốn kém (phải mất thời gian để quét các tập tin lớn như vậy), bạn phải thực sự biết gì mã hóa Là. Tốt nhất là chỉ định định dạng tệp chính xác nếu bạn có quyền kiểm soát các ứng dụng sản xuất hoặc sử dụng một số loại siêu dữ liệu để theo dõi nền tảng mà dữ liệu được tạo ra trên đó.

Trong Perl, nhân vật đại diện cho \n là miền địa phương phụ thuộc: \n/\012 trên máy * nix, \r/\015 trên cũ Mac và trình tự \r\n/\015\012 trên DOS-hậu duệ aka Windows. Vì vậy, để xử lý đáng tin cậy, bạn nên sử dụng các giá trị bát phân.

5

Kể từ Perl 5.10, bạn có thể sử dụng để kiểm tra kết thúc dòng chung,

s/\R//g; 

Nó sẽ làm việc trong mọi trường hợp, cả hai * nix và Windows.

1

Bạn có thể sử dụng biến số PERLIO. Điều này có lợi thế là không phải sửa đổi mã nguồn của các tập lệnh của bạn tùy thuộc vào nền tảng.

Nếu bạn đang làm việc với các tập tin văn bản hệ điều hành DOS, thiết lập các biến môi trường PERLIO-:unix:crlf:

$ PERLIO=:unix:crlf my-script.pl dos-text-file.txt 

Nếu bạn chủ yếu đối phó với các tập tin văn bản DOS (ví dụ trên Cygwin), bạn có thể đặt này trong thư mục .bashrc:

export PERLIO=:unix:crlf 

(. tôi nghĩ rằng giá trị phải là mặc định cho PERLIO trên Cygwin, nhưng dường như nó không phải)

Các vấn đề liên quan