5

問題: Windows と *nix の両方で生成され、ほとんど *nix で処理されたデータ (ほとんどが CSV 形式) があります。Windows は行末に CRLF を使用し、Unix は LF を使用します。特定のファイルについて、行末が Windows なのか *nix なのかはわかりません。今まで、違いを処理するために次のようなものを書いてきました。

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

*nix では、\n の部分は chomping と同等であり、Windows で生成されたファイルの場合はさらに \r (CR) を取り除きます。

しかし、今は Text::CSV_XS b/c が必要です。引用符で囲まれたデータ、改行が埋め込まれている可能性のある奇妙なデータ ファイルを取得し始めています。このモジュールでそのようなファイルを読み取れるようにするには、Text::CSV_XS: :getline() では、行末文字を指定する必要があります。(上記の tr/\n\r//d のように各行を読み取ることができず、埋め込まれた改行を適切に処理しない Text::CSV b/c で解析します)。任意のファイルが Windows または *nix スタイルの行末を使用しているかどうかを適切に検出して、Text::CSV_XS::eol() に chomp() の方法を伝えるにはどうすればよいですか

行末を検出するだけの CPAN のモジュールが見つかりませんでした。最初にすべてのデータファイルを dos2unix 経由で変換したくありません。b/c ファイルが巨大 (数百ギガバイト) であり、ファイルごとに 10 分以上を費やして単純なものを処理するのはばかげているようです。ファイルの最初の数百バイトを読み取り、LF と CRLF をカウントする関数を作成することを考えましたが、これより良い解決策がないと信じています。

何か助けはありますか?

注: すべてのファイルは、完全に windows-line 末尾または *nix 末尾のいずれかです。つまり、両方が 1 つのファイルに混在していません。

4

5 に答える 5

10

:crlf PerlIO レイヤーを使用してファイルを開き、Text::CSV_XSを行末文字として使用するように指示するだけ\nです。これにより、CR/LF ペアが暗黙的に単一の改行にマップされますが、おそらくそれが必要です。

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
}
于 2012-08-28T22:53:07.803 に答える
6

Perl 5.10 以降、これを使用して一般的な行末を確認できます。

s/\R//g;

*nix と Windows の両方で、すべてのケースで動作するはずです。

于 2012-08-28T22:42:08.033 に答える
3

各ファイルの最初の行を読み取り、最後から 2 番目の文字を調べます。である場合\r、ファイルは Windows からのものであり、そうでない場合は *nix です。次にseek、開始して処理を開始します。

ファイルの行末が混在している可能性がある場合 (たとえば、埋め込まれた改行の種類が異なる場合)、推測することしかできません。

于 2012-08-28T22:30:51.040 に答える
1

PERLIO変数を使用できます。これには、プラットフォームに応じてスクリプトのソース コードを変更する必要がないという利点があります。

DOS テキスト ファイルを扱っている場合は、環境変数PERLIO:unix:crlf次のように設定します。

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

に DOS テキスト ファイル (Cygwin など) を扱っている場合は、次のように記述します.bashrc

export PERLIO=:unix:crlf

PERLIO(その値はCygwinのデフォルトであるべきだと思いますが、明らかにそうではありません。)

于 2014-01-23T22:31:59.363 に答える
1

理論上、行末を確実に決定することはできません: このファイルは s が埋め込まれた DOS 行末を持つ単一の行ですか、それともいくつかの行の終わりにいくつかの\n迷子文字がある一連の行ですか?\r

foo\n
ba\r\n

foo\nba\r\n

統計分析は不正確で費用がかかる (このような巨大なファイルをスキャンするには時間がかかる) という理由でオプションにならない場合は、エンコーディングが何であるかを実際に知る必要があります。

作成するアプリケーションを制御できる場合は正確なファイル形式を指定するか、データが作成されたプラットフォームを追跡するために何らかのメタデータを使用することをお勧めします。

Perl では、文字\nが表す文字はロケールに依存します: \n/ \012*nix マシンでは\r/\015古い Mac およびシーケンスでは\r\n/ \015\012DOS の子孫、別名 Windows では。したがって、信頼性の高い処理を行うには、8 進数値を使用する必要があります。

于 2012-08-28T22:38:56.037 に答える