• ベストアンサー

ファイルから一行ずつ読み込むとき、@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] と $_ は同じだと思っていたのですが、なにか違うのでしょうか?

  • Perl
  • 回答数6
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
回答No.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 $

white-tiger
質問者

お礼

あっという間に検証用のコードまで・・・すごい・・・。ありがとうございます! なるほど、 ● cygwin perl の改行文字が \n ● windows の改行文字が \r\n なので、 $/ = "\r\n"; と最初に設定して、削除したい改行文字を設定すればいいのですね!

その他の回答 (5)

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.5

> しかし、chomp $_ のあとも変化がありません・・・。 chomp は改行文字を削除するものです。改行文字が含まれていない場合、何もしません。 > 下の方のところでもありましたが > cygwin の perl の問題でしょうか・・・。 私自身は Windows を使っていないのであくまで一般論ですが、data.txt の改行文字が CRLF で cygwin の Perl の改行文字が LF のみとなっている場合は、今回のような現象 が生じる可能性があるかもしれません。すなわち -nl によって除去されるのは LF のみ で $_ には末尾に CR が付き、-a によるフィールド分割では CR が空白文字類に含まれ るので除去される、といった具合です。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

「data.txt には改行が入っていないのですが」とはどのような意味でしょうか? さておき, od -xc data.txt の結果を見せてください.

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.3

文字列の末尾に1つの半角スペースまたはタブが付いているのは考えられると思います。 $_ へはそのまま格納されますが、@F への格納では空白類が捨てられます。$_ と $F[0] の文字列の長さを確認してはどうでしょうか。 $ perl -nla -e 'print length($_), ", ", length($F[0]);' data.txt

white-tiger
質問者

補足

data.txt には改行が入っていないのですが、、、 確かに length($_) の方が一つ多い値でした。 しかし、chomp $_ のあとも変化がありません・・・。 下の方のところでもありましたが cygwin の perl の問題でしょうか・・・。

回答No.2

かわらんなあ --- $ 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

white-tiger
質問者

補足

あれ、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)
回答No.1

$_ の最後に「改行」があると見た. chomp; すればいいような気がする. あと, Perl6 じゃないと思うので, たぶん本当は @F[0] じゃなくて $F[0] の方がよいと思う.

white-tiger
質問者

補足

perl 起動時の -l オプションが chomp だと思うのですがどうでしょうか。

関連するQ&A

  • Perl 先頭行に追加

    恐れ入ります。 Perlで、配列がカンマで区切られたデータを読み込み、 その先頭行にデータを挿入したいのですが、 中々うまくいきません。 データ(/data/xxx.txt)の中身は、 test,test2 bbb,bbb2 ccc,ccc2 という感じで、カンマで区切られて改行で並んでいます。 そこに新たに$dateと$contで受けたデータを先頭行に追加する感じです。 open(FILE,"<./data/xxx.txt"); while($temp = <FILE>){ @temp=split(/,/,$temp); push(@ddr,"$temp[0]","$temp[1]"); } seek(@ddr,0,0); unshift(@ddr,($date,$cont."\n")); open(FILE,">./data/xxx.txt"); $new=join(",",@ddr); print FILE $new; close(FILE); このように書いていますが、 print FILE @ddr とすると、配列が壊れた状態(全て繋がる)で先頭行には挿入されたのですが、カンマで区切って配列にして並べようとしたら、 test,test2 ,bbb,bbb2, ,,ccc,ccc2,, という感じで上手く並びません。 よろしくおねがいします。

    • ベストアンサー
    • Perl
  • ディレクトリ内のテキストファイルに対する同一処理

    よろしくお願いします。現在Linuxの環境でテキスト処理をしております。 ディレクトリ内にファイル名の異なった以下のような大量ファイルがあります。 a.txt 0,1,2,3,4,5,6,7 1,2,3,4,5,6,7,8 b.txt 2,3,4,5,6,7,8,9 3,4,5,6,7,8,9,10 これらのファイルをカンマでsplitし、左から2番目の数にだけ1を引き,下のディレクトリであるoutに出力させます。出力は以下のようになります。 ./out/a.txt 0,0,2,3,4,5,6,7 1,2,3,4,5,6,7,8 ./out/b.txt 2,2,4,5,6,7,8,9 3,4,5,6,7,8,9,10 そこで以下のようなPerlのプログラムを作成しました。 use strict; use warnings; my $dirname = '.'; opendir(DIR, $dirname) or die "$dirname: $!"; while (my $dir = readdir(DIR)) { next unless (-f $dir); next unless ($dir =~ /\.txt$/); print $dir, "\n"; open(FILE, $dir) or die "$dir: $!"; my @file = <FILE>; foreach $line (@file) { my ($a,$b,$c,$d,$e,$f,$g,$h) = split(/,/, $line);      my $b = $b - 1; close(FILE); } open(NEWFILE, "> ./out/$dir") or die "$dir: $!"; print NEWFILE @file; close(NEWFILE); } closedir(DIR); ですが、出力は完了するのですが、元のファイルから計算がされていません。どこがどう間違えているのかご指摘よろしくお願い申し上げます。

    • ベストアンサー
    • Perl
  • PHPのファイルの読み方のコード

    下記はpearlのファイルの読み込みです #!/usr/local/bin/perl print "Content-type: text/html\n"; print "\n"; require './jcode.pl'; if (!open(IN,"$userfile")) { &error("投稿データファイルを開けません"); } @DATA = <IN>; @DATA = reverse(@DATA); close(IN); foreach $line (@DATA){ ($f1,$f2,$f3) = split(/,/, $line); &jcode'convert(*line,'sjis'); push(@CS,$line); } foreach (1.. 100) { ($f1,$f2,$f3) = split(/,/, $CS[$_]); print "$f1\n"; } exit; ############################################## foreach (1.. 100) { ($f1,$f2,$f3) = split(/,/, $CS[$_]); print "$f1\n"; } この部分のPHPのコ-ド書き方をお願いします

    • ベストアンサー
    • PHP
  • PHPでcsvファイルデータ内の一行を修正したい

    PHP4.3とcsvカンマ区切りのファイルデーターによる簡易会員サイトをつくっています。 複数行にわたってカンマ区切りのデーターがあり、その中のある一行の配列を修正したいのです。 Perlだとpushを使って配列に入れファイルに書き込めばいいのですがPHPではどのようにすればいいのでしょうか? ちなみに以下のように試みているのですがだめなのです。join(): Bad arguments.のエラーがでます。 Perl的なやり方でやってみたのですが。。。 while(($line = fgets($fp))){ list($DATE,$ID,$POINT,$NAME,$EMAIL,$TEL,$PREF,$SEX,$AGE,$blood,$body,$length,$type,$why,$PASS,$PROF,$BOX,$DAY_LIMIT,$A_ID,$MILE_POINT,)= split(",",$line); if($EMAIL == $_POST{"EMAIL"} && $PASS == $_POST{"PASS"}){ $HIT=1; $NOWPOINT=$POINT+$buypoint; $newline= "$DATE,$ID,$NOWPOINT,$NAME,$EMAIL,$TEL,$PREF,$SEX,$AGE,$blood,$body,$length,$type,$why,$PASS,$PROF,$BOX,$DAY_LIMIT,$A_ID,$MILE_POINT,\n"; $NEWSTOCK=join("\n",$newline); } else{ $NEWSTOCK=join("",$line); } } どなたかご教授いただけましたら幸いです。

    • ベストアンサー
    • PHP
  • perl 計算結果をファイルへ出力したい

    perl やり始めたばかりです。宜しくお願いします。 入力ファイル data.txt があるとします。 data.txt は、 123 456 789 333 555 777 以上のようなテキストファイルといたします。このファイルを 以下の様に100分の1にして出力したい。 1.23 4.56 7.89 3.33 5.55 7.77 と言うことで、この場で教えていただきました。それが、以下です。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); foreach $line (@x){ chomp($line); @elms = split(' ',$line); foreach $data (@elms){ print $data/100," "; } print "\n"; } おかげ様でこれはこれで上手く動きました。そこで、出力値をファイルに 書き込みたいのです。 もちろん、以下の様な方法でファイルに 書き込めるのは判っております。 計算プログラム.pl > outfile.txt しかし、上のプログラムをベースにファイルに書き込めないかと色々と 試してはみましたが、どうも上手く行きません。 どなたか教えて頂けないでしょうか? 宜しくお願い申し上げます。

    • ベストアンサー
    • Perl
  • csvファイルでの,(カンマ)の取扱について

    csvファイルをperlで取扱っています。 ,(カンマ)が含まれるデータは""で括ってやれば行がずれることなく入るのは分かっているのですが、今度は取り出すときどのようにしていいのか分かりません。 各行毎に一連のデータが羅列されていますが、それの分割方法を教えてください。 たとえば、 $bに,(カンマ)入りの文字列が入っていた場合、 ($a, $b, $c) = split(/,/, $query); とすると本来$bに入って欲しいデータの,(カンマ)から後の部分が$cに格納されてしまいます。(そこから先が1つずれます) これをずれずに分割させるにはどのようにしたらいいでしょうか? ちなみに ($a, "$b", $c) = split(/,/, $query); と試しにやってみましたが、エラーになってしまいました。 実は長年の悩みで、データを格納する際に,(カンマ)を別のあり得ないような文字列に置き換えて、取り出したあと,(カンマ)に戻すというやり方でやっていたのですが、1つのデータファイルを複数のperlで取扱うようになり、対応が難しくなってきたので、これを機にきちんとした方法でデータを取扱いたいと思っています。

    • ベストアンサー
    • Perl
  • 複雑なcsv

    以下のような2つの入力データをデータベースに格納する作業を行っております.2つのデータは,"b"の値によって判別が可能です. 入力データ(スペースをカンマで表現しています): 1 a,b,c - [d,e,[f:g,h:i],[j,[k:m,n:o]]] (p) 2 a,b,c - d:e, f:g この2つのデータをなるべく簡単に処理するにはどのようにすればよろしいでしょうか.私が書いた(ている)コードでは,splitで地道に展開しているのですが,あまりにも要領が悪いかんじです. 簡単なコードを示していただけると嬉しいです.

    • ベストアンサー
    • PHP
  • phpでのソートについて

    phpのソートについて教えてください。 以下のようなカンマ区切りのログファイルlog.txtがあるとしまして、 100,200,a,b,c, 300,100,d,e,f, 500,60,g,h,i, 50,300,j,k,l, 1000,60,m,n,o, このデータから 1番目のデータ(数値)が2番目のデータ(数値)より大きいデーターのみを対象にして ※つまりは以下のみ対象 300,100,d,e,f, 500,60,g,h,i, 1000,60,m,n,o, ここから1番目のデータ(数値)から2番目のデータ(数値)を引いた数が大きい順に ソートしてファイルに保存させたいのですが、 200,d,e,f,(300-100なので200) 440,g,h,i,(500-60なので440) 940,m,n,o,(1000-60なので940) ↓ ※最終的にこの順番で新しいログファイルnewlog.txtへ保存させたい 940,m,n,o, 440,g,h,i, 200,d,e,f, これらの処理を効率よく1度で行う方法はございますでしょうか。 わかりにくい説明で申し訳ありません。 お忙しい中恐縮ですがご教授いただけましたら幸いです。 何卒宜しくお願い致します。

    • ベストアンサー
    • PHP
  • perlでcsvファイルを読む(ダブルコーテーション内カンマを無視したい)

    perlでCSVファイルを読み込むスクリプトを作っています。 以下のようなCSVファイルがあります。 ■CSVファイル 東京,よろしくお願いします。 大阪,はじめまして 九州,"5,000円でお願いします" カンマで区切り、以下のようにすると、"5,000円"の部分が2つに分かれてしまいます。 ($data1,$data2) = split(/,/,$all_data) 前後にダブルコーテーションがあった場合、中のカンマで区切らないような良い方法はないでしょうか? 環境: Perl 5.8.5

    • ベストアンサー
    • Perl
  • ディレクトリ内の全てのファイルの中身を操作したい

    ディレクトリ内に、例えば10個のテキストファイル a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt j.txt があり、その中身にそれぞれ 2 6 98 65 4 52 98 100 82 56 という数字が書かれているとします。 これらのファイルの中身の平均をawkを用いたコマンドで表示させたいのですが、自分なりに頑張ったのですが実行できませんでした。 (cat * | awk'{BEGIN{total += $0; i += 1}END{print total/i}' のような感じで) どうすれば実行できるのか、よろしければお教えください。

専門家に質問してみよう