アプリ版:「スタンプのみでお礼する」機能のリリースについて

データファイルを一行ずつ読み込んで、文字列を一文字ずつコンマ区切りにしたいと思っています。たとえば、
  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] と $_ は同じだと思っていたのですが、なにか違うのでしょうか?

A 回答 (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
$
    • good
    • 0
この回答へのお礼

あっという間に検証用のコードまで・・・すごい・・・。ありがとうございます!

なるほど、

● cygwin perl の改行文字が \n
● windows の改行文字が \r\n

なので、

$/ = "\r\n";

と最初に設定して、削除したい改行文字を設定すればいいのですね!

お礼日時:2009/07/09 22:54

> しかし、chomp $_ のあとも変化がありません・・・。



chomp は改行文字を削除するものです。改行文字が含まれていない場合、何もしません。

> 下の方のところでもありましたが
> cygwin の perl の問題でしょうか・・・。

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

「data.txt には改行が入っていないのですが」とはどのような意味でしょうか?


さておき, od -xc data.txt の結果を見せてください.
    • good
    • 0

文字列の末尾に1つの半角スペースまたはタブが付いているのは考えられると思います。


$_ へはそのまま格納されますが、@F への格納では空白類が捨てられます。$_ と $F[0]
の文字列の長さを確認してはどうでしょうか。

$ perl -nla -e 'print length($_), ", ", length($F[0]);' data.txt

この回答への補足

data.txt には改行が入っていないのですが、、、
確かに length($_) の方が一つ多い値でした。

しかし、chomp $_ のあとも変化がありません・・・。

下の方のところでもありましたが
cygwin の perl の問題でしょうか・・・。

補足日時:2009/07/09 09:22
    • good
    • 0

かわらんなあ


---
$ 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)

補足日時:2009/07/09 04:36
    • good
    • 0

$_ の最後に「改行」があると見た.


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

この回答への補足

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

補足日時:2009/07/09 04:38
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!