perl初心者です。
地名1.csv 地名2.csv の2つのファイルがあったとします。
==地名1.csv==
a,b,札幌,c,d,
e,f,沖縄,f,r,
t,u,東京,w,e,
r,u,千葉,e,q,
l,o,金沢,e,c,
p,l,高知,w,w,
==地名2.csv==
沖縄,千葉
高知,千葉
ここで、地名2.csvの1行に書かれた地名に挟まれた行を地名1.csvから
ごっそりと抜き出したのです。。
具体的には、実行すると、
e,f,沖縄,f,r,
t,u,東京,w,e,
r,u,千葉,e,q,
r,u,千葉,e,q,
l,o,金沢,e,c,
p,l,高知,w,w,
が抽出され、それが別ファイルに書き込めたら一番なのです。
地名2.csvを見ての通り、地名2.csvの地名の順番は
地名1.csvの順番と逆なこともあるので、
if文で条件分岐をすればいいのだと思うのですが、
ここがうまく書けません。。
どなたかお知恵を貸していただけないでしょうか。
どうぞどうぞよろしくお願い致します。
No.11ベストアンサー
- 回答日時:
文字コードをutf-8であることをきちんと指定するようにしました。
また、地名2.csvの県名が地名1.csvにないとき、そこで打ち切らず、処理を続行するようにしました。
エラー時の文字化けも発生しないようにしました。こちらをまるまる入れ替えてください。
---------------------------------------------------------
use strict;
use utf8;
use Encode;
binmode(STDOUT, ":utf8");
#Usage表示
if (scalar(@ARGV) != 3){
printf("%s 地名1.csv 地名2.csv 出力ファイル名\n",$0);
exit 10;
}
my $fname1 = $ARGV[0];
my $fname2 = $ARGV[1];
my $fname3 = $ARGV[2];
our @lines = ();
our %names = ();
#ファイルを読み込み、内部テーブルへ展開
&readfile($fname1);
#出力ファイルオープン
open(OFH,">:encoding(:utf-8)",$fname3) || die "$fname3 オープンエラー<$!>";
#ファイルを読み込み、範囲内を出力
&readfile2($fname2);
#出力ファイルクローズ
close(OFH);
#ファイルを読み込み、内部テーブルへ展開
sub readfile
{
my $fname = shift(@_);
$fname = $fname;
open FH,"<:encoding(:utf-8)",$fname || die "$fname オープンエラー<$!>";
my $i = 0;
while(<FH>){
my @elm = split(/,/,$_);
$names{$elm[2]} = $i;
push(@lines,$_);
$i++;
}
close(FH);
}
#ファイルを読み込み、範囲内を出力
sub readfile2
{
my $fname = shift(@_);
$fname = $fname;
open FH,"<:encoding(:utf-8)",$fname || die "$fname オープンエラー<$!>";
my $i = 0;
while(<FH>){
$i++;
chomp($_);
my @elm = split(/,/,$_);
if (exists $names{$elm[0]}){
}else{
printf("%d行 %s 地名1.csv になし\n",$i,$elm[0]);
print $_,"\n";
next;
}
if (exists $names{$elm[1]}){
}else{
printf("%d行 %s 地名1.csv になし\n",$i,$elm[1]);
print $_,"\n";
next;
}
my $st = $names{$elm[0]};
my $en = $names{$elm[1]};
&outfile($st,$en);
}
close(FH);
}
#出力ファイルへ出力
sub outfile
{
my $st = shift(@_);
my $en = shift(@_);
#順番が逆ならひっくり返す
if ($st > $en){
my $tmp = $st;
$st = $en;
$en = $tmp;
}
for (my $i = $st; $i <= $en; $i++){
print OFH $lines[$i];
}
}
-----------------------------------------------------
以下実行結果です。
地名1.csv
a,b,札幌,c,d,
e,f,沖縄,f,r,
t,u,東京,w,e,
r,u,千葉,e,q,
l,o,金沢,e,c,
p,l,高知,w,w,
地名2.csv
沖縄,千葉
高知,千葉
高知2,千葉2
高知2,千葉3
$ perl sample.pl timei1.csv timei2.csv out.csv
3行 高知2 地名1.csv になし
高知2,千葉2
4行 高知2 地名1.csv になし
高知2,千葉3
出力結果
$cat out.csv
e,f,沖縄,f,r,
t,u,東京,w,e,
r,u,千葉,e,q,
r,u,千葉,e,q,
l,o,金沢,e,c,
p,l,高知,w,w,
No.12
- 回答日時:
ちょっと気になったのは #7 のところのやり取りで
Use of uninitialized value $elm[2] in hash element at sample.pl line 40, <FH> line 1.
というエラーが出たところですかね. このエラーメッセージは「sample.pl の 40行目」で「$elm[2] という初期化されていない変数を使った」と言っているのですが, #5 にあるプログラムで $elm[2] を使っているのは
$names{$elm[2]} = $i;
の 1行のみであり, しかもこれは「40行目」ではありません. つまり, このときに使ったプログラムは #5 にあるものとは (perl が見たときに) 違うものであると結論付けることができます. ついでにいうとこの行は「地名1.csv」を読み込んでいるループの中にありますから, 「『地名1.csv』の読み込みで問題が起きている」という可能性があります.
とりあえず, いきなり巨大なデータに対して処理するんじゃなくって, 質問文にあるくらいのデータで試してみてどうなるかを確かめたらどうでしょうかね. ただし, あなたの使ったプログラムが (上に書いたように) #5 にあるものとはかなり違っている可能性があるので,
・どのような入力データに対して
・どのようなプログラムを動かしてみたときに
・どのような出力が得られたのか
をきちんと書くようにしてください.
あ, Windows のメモ帳だと必ず BOM が付きます.
地名1は桁数は6000位、地名2は500程度あるデータなのですが、
中身は大きくは変わらない感じです。
でも、ここまで沢山のお時間とお力添えを頂き、こう書くのかという目から鱗の部分もたくさんありました。
本当にありがとうございます。
私も、もっともっと勉強します。
BOMについては初めて知ったことでした(^^;
No.10
- 回答日時:
>・BOM
>ついているかもしれません。。メモ帖で開いて別名保存で確認した所、元ファイルとバイト数が同じでした。
>でも、BOMを抜く方法がググってもすぐに出来なさそうなので、ちょっと一旦休憩します(すみませ>>ん、、)これを抜けばできそうでしょうか。
ゆっくり、休んでください。
たぶん、うまくいくと思います。
只、こちらでも、本当に、地名2.csvの県名が地名1.csvにないとき、
エラーメッセージが、1行 i≫?a?§e°・a?°が地名1.csvになし のように
文字化けして表示されるので、確認してみます。
No.9
- 回答日時:
スクリプトの2行目(use strict;)に
use utf8;
追加して、再度実行していただけますか。
それで、状況が変わりませんでしょうか?
又、念のため確認ですが、地名1.csv、 地名2.csvは
BOMはついてないですよね。(ファイルの先頭3バイトにあり文字コードの並びを指定するバイナリデータ)
・use utf8を付与した所、
Wide character in print at test8.pl line 63, <FH> line 1.
1行 i≫?a?§e°・a?°が地名1.csvになし
というエラーが表示されたため、ないほうが良かった感があります。
・BOM
ついているかもしれません。。メモ帖で開いて別名保存で確認した所、元ファイルとバイト数が同じでした。
でも、BOMを抜く方法がググってもすぐに出来なさそうなので、ちょっと一旦休憩します(すみません、、)これを抜けばできそうでしょうか。
No.8
- 回答日時:
>TeraPadでUTF-8に変換し、上書きまして、再度実行しましたが、
>==
>Use of uninitialized value $elm[2] in hash element at sample.pl line 40, <FH> line 1.
>¦(延々10000行)
>Use of uninitialized value $elm[2] in hash element at sample.pl line 40, <FH> line 10000.
>1行 **が地名1.csvになし
>==
>と表示され、カラの出力ファイルが出来ました(涙)
うーむ。いずれかのファイルの文字コードがおかしいように思えます。
more スクリプトファイル
more 地名1.csv
more 地名2.csv
をteratermで実行し、上記3ファイルがきれいに表示されるか確認していただけませんでしょうか。
teratermのterminalの漢字コードは、utf-8にして確認してください。
地名2.csvは行数が多いので、最初がOKなら途中で打ち切っても構いません。
親切にありがとうございます。
全てのファイルをmoreで見てみましたが、文字化け等ありません。
また、teratermで設定>全般>言語「UTF-8」となっています。。。
No.7
- 回答日時:
>文字コードは65001:Unicode(UTF-8)です。
こちらでも、utf-8の環境で確認しました。
スクリプト(sample.pl)の文字コード UTF-8
地名1.csvの文字コード UTF-8
地名2.csvの文字コード UTF-8
teratermのterminal(receive,transmit)の文字コード UTF-8
で確認しました。
正常に動作します。
提示されたファイルで実行すると出力ファイルは、
$ cat out.csv
e,f,沖縄,f,r,
t,u,東京,w,e,
r,u,千葉,e,q,
r,u,千葉,e,q,
l,o,金沢,e,c,
p,l,高知,w,w,
のようになります。
念のため、確認ですが、OSの文字コードもUTF-8で間違いないでしょうか?
あっ!!地名2.csvの方が932:日本語(シフトJIS)でした(汗)
TeraPadでUTF-8に変換し、上書きまして、再度実行しましたが、
==
Use of uninitialized value $elm[2] in hash element at sample.pl line 40, <FH> line 1.
¦(延々10000行)
Use of uninitialized value $elm[2] in hash element at sample.pl line 40, <FH> line 10000.
1行 **が地名1.csvになし
==
と表示され、カラの出力ファイルが出来ました(涙)
No.6
- 回答日時:
>と、文字化け表示し、1行目のリストが読み込めなかったようです。
。>windowsでteratermを利用してプログラミングしていますが、
>元々のファイルのエンコードをどうにかする必要があるのでしょうか。
>重ね重ね申し訳ありませんが、ご都合つけばお助け願えませんでしょうか。
念のため、
ファイルが存在するOSと
ファイルの文字コード(漢字コード)
を教えていただけますでしょうか?
No.5
- 回答日時:
No4です。
>それがベストです!
ベスト案で作成しました。以下のスクリプトを作成してください。(sample.plとします)
---------------------------------------------------
use strict;
#Usage表示
if (scalar(@ARGV) != 3){
printf("%s 地名1.csv 地名2.csv 出力ファイル名\n",$0);
exit 10;
}
my $fname1 = $ARGV[0];
my $fname2 = $ARGV[1];
my $fname3 = $ARGV[2];
our @lines = ();
our %names = ();
#ファイルを読み込み、内部テーブルへ展開
&readfile($fname1);
#出力ファイルオープン
open(OFH,">",$fname3) || die "$fname3 オープンエラー<$!>";
#ファイルを読み込み、範囲内を出力
&readfile2($fname2);
#出力ファイルクローズ
close(OFH);
#ファイルを読み込み、内部テーブルへ展開
sub readfile
{
my $fname = shift(@_);
$fname = $fname;
open(FH,$fname) || die "$fname オープンエラー<$!>";
my $i = 0;
while(<FH>){
my @elm = split(/,/,$_);
$names{$elm[2]} = $i;
push(@lines,$_);
$i++;
}
close(FH);
}
#ファイルを読み込み、範囲内を出力
sub readfile2
{
my $fname = shift(@_);
$fname = $fname;
open(FH,$fname) || die "$fname オープンエラー<$!>";
my $i = 1;
while(<FH>){
chomp($_);
my @elm = split(/,/,$_);
if (exists $names{$elm[0]}){
}else{
printf("%d行 %sが地名1.csvになし\n",$i,$elm[0]);
print $_;
return;
}
if (exists $names{$elm[1]}){
}else{
printf("%d行 %sが地名1.csvになし\n",$i,$elm[1]);
print $_;
return;
}
my $st = $names{$elm[0]};
my $en = $names{$elm[1]};
&outfile($st,$en);
$i++;
}
close(FH);
}
#出力ファイルへ出力
sub outfile
{
my $st = shift(@_);
my $en = shift(@_);
#順番が逆ならひっくり返す
if ($st > $en){
my $tmp = $st;
$st = $en;
$en = $tmp;
}
for (my $i = $st; $i <= $en; $i++){
print OFH $lines[$i];
}
}
-------------------------------------------
perl sample.pl 地名1.csv 地名2.csv 出力ファイル
と入力すると、
出力ファイルに結果が出力されます。
私が1週間以上かけてやりきれなかったことがこんなすぐ回答頂けるとは、、心の底から感動しました(苦笑)
やってみたのですが、実行自体はうまくいき、ただ結果が、
==
1行 rcが地名1.csvになし
rc,ォ
==
と、文字化け表示し、1行目のリストが読み込めなかったようです。。
windowsでteratermを利用してプログラミングしていますが、
元々のファイルのエンコードをどうにかする必要があるのでしょうか。
重ね重ね申し訳ありませんが、ご都合つけばお助け願えませんでしょうか。
#Perlはまだ初歩の参考書を見ての座学中で、本の内容が実務に転用できず困っています、、、
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) エクセルのVBAについて とあるサイトのコードを参考に、CSVの文字化けを直すVBAを作成しているの 7 2022/11/04 14:15
- Visual Basic(VBA) VBA初心者です。電話番号の数字の前に0を表示させたいです。 2 2022/12/14 03:58
- Access(アクセス) CSVファイルの「0落ち」にVBA 6 2023/02/02 15:27
- Visual Basic(VBA) VBAで特定の場所にあるCSVファイル(複数)から特定場所を抜き出してExcelに転記したいです。 11 2023/05/23 16:29
- Access(アクセス) access,vbaでフォルダ内のファイルをテーブルにインポート、ファイル名もフィールドに追加したい 1 2022/08/31 11:11
- Visual Basic(VBA) 複数のcsvファイルをExcelに一括変換したい 2 2023/03/03 12:44
- Visual Basic(VBA) エクセルVBAについて 8 2022/07/13 22:41
- PHP 値の取り出し方について教えて下さい。 1 2023/03/31 13:30
- Excel(エクセル) csvに別のExcelの文章を差し込む 2 2023/04/01 16:06
- Excel(エクセル) PowerQueryに詳しい方教えてください(Office365) 1 2022/07/24 21:11
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBAでCSVファイルの特定行を書...
-
ReadLineでの読み出し行を指定する
-
VBAで巨大なファイルの途中から...
-
ExcelをCSV書き出す場合のシー...
-
VBAでCSVファイルを途中行まで...
-
エクセルVBA コードが同じでも...
-
openした後、closeしないでプロ...
-
ADOによるCSVファイルからのデ...
-
拡張子 ”log” と ” dat” の違い
-
perlにて2つのファイル比較
-
MATLAB グローバル変数の宣言
-
VB6.0でDB接続する際に切断時の...
-
アクセスカウンターでデータが...
-
window.open でのファイル指定方法
-
awkスクリプトでダブルクォーテ...
-
htaccessで特定のディレクトリ...
-
fopenでディレクトリ内の全ファ...
-
ファイル出力の改行コードをLFに
-
エクセルVBAで素数だけを出力す...
-
fgets で値が取得できない
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBAでCSVファイルを途中行まで...
-
VBAで巨大なファイルの途中から...
-
ExcelをCSV書き出す場合のシー...
-
VBAでCSVファイルの特定行を書...
-
openした後、closeしないでプロ...
-
ReadLineでの読み出し行を指定する
-
エクセルVBA コードが同じでも...
-
csvファイル改行コードの置換に...
-
Perlの変数に文字数制限(容量...
-
perlにて2つのファイル比較
-
C言語でのファイルのデータ更...
-
JavaでCSVファイルを高速に読む...
-
VB6.0でDB接続する際に切断時の...
-
MATLAB グローバル変数の宣言
-
alarmのタイムアウト後の処理で...
-
DBMとテキストファイルのどちら...
-
perlで、後ろの行を読んで、前...
-
拡張子 ”log” と ” dat” の違い
-
5行おきに5行ずつ抽出するに...
-
テキストデータから指定した1...
おすすめ情報