- ベストアンサー
ファイルから一行ずつ読み込むとき、@F[0] と $_ は違う?
データファイルを一行ずつ読み込んで、文字列を一文字ずつコンマ区切りにしたいと思っています。たとえば、 xyz → x,y,z としたいと思っています。 今、data.txt に abc defgh という2行が書いてあります。 perl -nla -e '@chars= split(//,@F[1]); print join(",",@chars);' data.txt とすると a,b,c d,e,f,g,h という出力が無事に得られました。 どうせ、data.txt は一列しか使っていないので、 @F[0] の代りに $_ を使ってみました。 perl -nle '@chars= split(//, $_); print join(",",@chars);' data.txt しかし、結果は a,b,c, d,e,f,g,h, のように、各行の最後に余計なコンマが付いてしまいます。 なぜでしょうか? 一列しかデータがないので、@F[0] と $_ は同じだと思っていたのですが、なにか違うのでしょうか?
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
ほぼ、既に答が出ているようですが、cygwinのperlでは改行コードを0x0A で、data.txtはdos形式の改行だからということのようですね。 以下のように入力セパレータが0x0Aで、dos形式のファイルをchompして も、0x0Dが残ることがわかります。 $ cat check_chomp.pl #!/usr/bin/perl use warnings; use strict; print "--- Now Return Code\n"; print_char_cord($/); my $file = shift || 'data.txt'; open my $fh, '<', $file or die "$file: $!"; while ( my $line = <$fh> ) { print "\n--- Before chomp\n"; print_char_cord($line); chomp $line; print "\n--- After chomp\n"; print_char_cord($line); } close $fh or die "$file: $!"; sub print_char_cord { my $str = shift; while ( $str =~ m/^(.)(.*)/s ) { printf( "%s = 0x%X\n", $1, ord $1 ); $str = $2; } print "\n"; } $ perl check_chomp.pl ~/tmp/data.txt --- Now Return Code = 0xA --- Before chomp a = 0x61 b = 0x62 c = 0x63 = 0xD = 0xA --- After chomp a = 0x61 b = 0x62 c = 0x63 = 0xD --- Before chomp d = 0x64 e = 0x65 f = 0x66 g = 0x67 h = 0x68 = 0xD = 0xA --- After chomp d = 0x64 e = 0x65 f = 0x66 g = 0x67 h = 0x68 = 0xD ワンライナーでchompしたいときは、例えば次のように$/を変えてやれば、 OKです。 $ perl -nle '@chars= split(//, $_); print join(",",@chars);' ~/tmp/data.txt a,b,c, d,e,f,g,h, $ perl -nle 'BEGIN{$/="\x0D\x0A"} @chars= split(//, $_); print join(",",@chars);' ~/tmp/data.txt a,b,c d,e,f,g,h $
その他の回答 (5)
- kumoz
- ベストアンサー率64% (120/185)
> しかし、chomp $_ のあとも変化がありません・・・。 chomp は改行文字を削除するものです。改行文字が含まれていない場合、何もしません。 > 下の方のところでもありましたが > cygwin の perl の問題でしょうか・・・。 私自身は Windows を使っていないのであくまで一般論ですが、data.txt の改行文字が CRLF で cygwin の Perl の改行文字が LF のみとなっている場合は、今回のような現象 が生じる可能性があるかもしれません。すなわち -nl によって除去されるのは LF のみ で $_ には末尾に CR が付き、-a によるフィールド分割では CR が空白文字類に含まれ るので除去される、といった具合です。
- Tacosan
- ベストアンサー率23% (3656/15482)
「data.txt には改行が入っていないのですが」とはどのような意味でしょうか? さておき, od -xc data.txt の結果を見せてください.
- kumoz
- ベストアンサー率64% (120/185)
文字列の末尾に1つの半角スペースまたはタブが付いているのは考えられると思います。 $_ へはそのまま格納されますが、@F への格納では空白類が捨てられます。$_ と $F[0] の文字列の長さを確認してはどうでしょうか。 $ perl -nla -e 'print length($_), ", ", length($F[0]);' data.txt
補足
data.txt には改行が入っていないのですが、、、 確かに length($_) の方が一つ多い値でした。 しかし、chomp $_ のあとも変化がありません・・・。 下の方のところでもありましたが cygwin の perl の問題でしょうか・・・。
- _--_1l1_1_
- ベストアンサー率67% (102/152)
かわらんなあ --- $ perl -v This is perl, v5.8.8 built for i386-linux-thread-multi $ cat /etc/redhat-release CentOS release 5.3 (Final) $ $ cat data.txt abc defgh $ perl -nle '@chars= split(//,$_); print join(",",@chars);' data.txt a,b,c d,e,f,g,h $ perl -nla -e '@chars= split(//,$F[0]); print join(",",@chars);' data.txt a,b,c d,e,f,g,h $ perl -nla -e '@chars= split(//,@F[0]); print join(",",@chars);' data.txt a,b,c d,e,f,g,h
補足
あれ、cygwinでやったのが悪いのでしょうか・・ $ perl -v This is perl, v5.8.7 built for cygwin-thread-multi-64int (with 1 registered patch, see perl -V for more detail)
- Tacosan
- ベストアンサー率23% (3656/15482)
$_ の最後に「改行」があると見た. chomp; すればいいような気がする. あと, Perl6 じゃないと思うので, たぶん本当は @F[0] じゃなくて $F[0] の方がよいと思う.
補足
perl 起動時の -l オプションが chomp だと思うのですがどうでしょうか。
お礼
あっという間に検証用のコードまで・・・すごい・・・。ありがとうございます! なるほど、 ● cygwin perl の改行文字が \n ● windows の改行文字が \r\n なので、 $/ = "\r\n"; と最初に設定して、削除したい改行文字を設定すればいいのですね!