2012-08-28 5 views
5

問題:私はWindowsと* nixの両方で作成され、主に* nixで処理されたデータを(ほとんどCSV形式で)持っています。 Windowsは行末にCRLFを使用し、UNIXはLFを使用します。特定のファイルについては、ウィンドウや* nix行の終わりがあるかどうかわかりません。 * nixの上Perlでファイルの行末を正しく検出しますか?

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

\ nの部分がムシャムシャに相当し、さらに、それは窓があります場合は、\ rを(CR)を取り除く:今まで、私は違いを処理するために、このような何かを書いてきました生成されたファイル。

しかし、今私はテキスト:: 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を数える関数を書くことを考えましたが、これはもっと良い解決策がないと信じることを拒否します。

助けが必要ですか?

注:すべてのファイルは、完全にウィンドウラインの終了点または* nixの終了点を持っています。つまり、両方が1つのファイルに混在しているわけではありません。

答えて

9

:crlfPerlIO layerを使用してファイルを開き、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 
} 
+0

ありがとうございます、以前はPerlIOについて知りませんでした。これはまさに私が必要としていたものです。 – user1481

3

各ファイルの最初の行を読み、その最後の1文字を見てください。 \rの場合、ファイルはWindowsから取得されます。そうでない場合は、* nixです。次に、seekを開始して処理を開始します。

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

1

理論では、行末を確実に決定できません:このファイルは、DOS行の末尾に埋め込み\nの1行ですか、これはいくつかの行の末尾に少し迷いのある\r文字の行です。

foo\nba\r\n 

foo\n 
ba\r\n 

それはあまりにも不正確かつ高価であるため、統計的分析は(それは、このような巨大なファイルをスキャンする時間がかかります)オプションではない場合、あなたは実際に何エンコーディングを知っている必要がありますです。

生産アプリケーションを制御している場合や、データが生成されたプラットフォームを追跡するために何らかのメタデータを使用する場合は、正確なファイル形式を指定することが最善の方法です。 Perlで

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

5

5.10以来、あなたは、

s/\R//g; 

それはすべてのケースで動作するはずです、* nixのとWindowsの両方を一般の行末をチェックするためにこれを使用することができます。

1

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

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

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

あなたがDOSのテキストファイル(たとえば、Cygwinの上)を扱うなら、あなたが置くことができますあなたの.bashrcでこの:

export PERLIO=:unix:crlf 

(私はその値がCygwinの上PERLIOのデフォルトであるべきだと思うが、どうやらそれはありません。)

関連する問題