perlでパターンマッチを使ったifの条件が必ずTRUEになってしまいます。
以下は条件です。二つのファイルがあって、片方のファイルのある列の文字列と別のファイルのある列の文字列が一致したら一致した行の1列目を出力するというプログラムです。
perl v5.12.3
『oct_gene.csv』は以下のような2列のファイルで、2列目であるalphabetの群は空白で区切られています。文字コードはASCIIです。
1zinc finger protein of the cerebellum 3
0stathmin-like 2
.
.
.
.
『RNA.csv』は以下のような3列のファイルで、3列目のalphabet群は同じく空白で区切られています。文字コードはUTF-8です。
1NM_324891 sin3 associated polypeptide
2 NM_53344 Nanog homeobox
.
.
.
open (WRITE, ">RNAseq_Oct.csv");
open(FILE, "RNA.csv");
while($line = <FILE>){
chomp $line;
@fact = split /\t/, $line;
open(OCT, "oct_gene.csv");
while($octline = <OCT>){
chomp $octline;
@oct = split /\t/, $octline;
if($fact[2] =~ /$oct[1]/){
print WRITE $fact[2] . "\t" . $oct[1] ."\n";
last;
}
}
close (OCT);
}
close (FILE);
close (WRITE);
この中のif文がうまく働かず、whileで繰り返すまでもなく必ず if($fact[2] =~ /$oct[1]/) が成り立ってしまいます。
どなたか詳しい方、どうかご教示願います。
それではよろしくお願いします。
No.1ベストアンサー
- 回答日時:
あるべき動作仕様やデータフォーマットの詳細、動作環境などがわかりませんので、
スクリプトを動作させた場合に考えられる問題を列挙します。
● 各データファイルのフォーマットはタブ区切りになっていますか?
仕様として言及されていませんが、split /\t/ で処理している以上は
ファイルの列がタブ区切りになっていないとデータ列を正しく読み取れません。
その結果、$fact[2]と$oct[1]がいずれも未定義値になっている場合には
if($fact[2] =~ /$oct[1]/) { ... }
は常に真と判定されます。
$fact[2]と$oct[1]に正しい値が入ることを保証するために、
列数が異なる場合にはエラーとなるような例外処理が必要かもしれません。
@fact = split /\t/, $line;
if(@fact != 2) { die("Bad csv format at RNA.csv, line $.\n"); }
@oct = split /\t/, $octline;
if(@oct != 3) { die("Bad csv format at oct_gene.csv, line $.\n"); }
なお上記のケースでは、Perl5ではuse warningsプラグマを有効にしていれば
実行時に未定義値に関する警告を出してくれます。
use strictやmyによる変数宣言と合わせてチェック機能を有効活用することを
強くお勧めします。
●各データファイルの改行コードは実行環境の改行コードと一致していますか?
Perlを実行するプラットフォームOSとデータファイルの改行コードが
一致していない場合にもデータ読み込み時の破損が起きる可能性があります。
例として、UNIX/Linux系プラットフォーム(改行コード=LF)のPerlにおいて
Windows環境で作られたテキストファイル(改行コード=CR+LF)を読ませた場合、
chompでは末尾のLFのみが削られ、CRが残ってしまってデータが化けることになります。
この場合、Perl5.8以降であれば、3引数のopen()やbinmode()を使って
open(FILE, ":crlf", "RNA.csv");
または
open(OCT, "oct_gene.csv");
binmode(OCT, ":crlf");
とすることで入力時にテキスト中のCR+LFの改行をLFに統一することができます。
Mac(改行コード=CR)で実行する場合も同様の注意が必要になる場合があります。
Windowsでも、Cygwin環境で実行した場合はUNIX系と同じ挙動になるはずです。
バッドノウハウとして、chompを複数回実行するという裏技?もありますが、
場当たり的対処方法なのでお勧めしません。入力フォーマットの方を厳格にすべきです。
● 文字列の比較方法は意図したものになっていますか?
「alphabetの群は空白で区切られています」とあるにもかかわらず、
空白を一切考慮しないロジックになっているのが気になります。
上記のサンプルでは、「Nanog homeobox」に対しては「Nano」「g h」「home」「box」なども
マッチすることになります。
これが意図する仕様かどうか確認した上で、もし必要であれば比較元と
対象文字列のそれぞれについて、空白でsplitしてから個別比較する処理を追加してください。
また、/$oct[1]/とした場合、$oct[1]は一般文字列ではなく正規表現として解釈されます。
単純に文字列を含んでいるかをチェックしたいのなら、\Q~\Eを使って
if($fact[2] =~ /\Q$oct[1]\E/) {
とするか、あるいは正規表現を使わずに
if(index($fact[2], $oct[1]) >= 0) {# 文字列を含まない場合は-1が返る
でチェックしなければいけません。
でないと$oct[1]に正規表現のメタ文字が含まれている場合に意図しない結果になります。
$oct[1] = 'a.c' のときに 'abc' にもマッチしてしまうということです。
● 比較対象およびファイル出力する内容の、列の選択は正しいですか?
配列の添え字は1ではなく0から始まることに注意してください。
print WRITE $fact[2] . "\t" . $oct[1] ."\n";
で出力されるのは、
「RNA.csvの3列目とoct_gene.csvの2列目をタブ記号で連結したもの」
です。提示仕様にある「一致した行の1列目を出力する」とは異なるように
読み取れます。1行目ならわかるんですが・・。
回答ありがとうございます。問題は解決しました。入力の行列が完璧でなくところどころに項目が存在していなかったのでパターンマッチするところで未定義値が設定されていたのが原因でした。
また、色々な可能性に対する提案がありとても役に立ちました。今回のこと以外でも参考になりそうな部分が多いので非常に有り難いです。
No.3
- 回答日時:
「whileで繰り返すまでもなく必ず if($fact[2] =~ /$oct[1]/) が成り立ってしまいます」って~ときの,
各変数の値はどうなっているんですか?No.2
- 回答日時:
> 『oct_gene.csv』は以下のような2列のファイルで、2列目であるalphabetの群は空白で区切られています。
文字コードはASCIIです。> 『RNA.csv』は以下のような3列のファイルで、3列目のalphabet群は同じく空白で区切られています。
とありますが、
@fact = split /\t/, $line;
@oct = split /\t/, $octline;
これではタブで区切ってます。
@fact = split / /, $line;
@oct = split / /, $octline;
とかじゃないですかね。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) pythonのこのエラーがわかりません 3 2022/11/16 14:54
- Excel(エクセル) エクセルのVBAについて とあるサイトのコードを参考に、CSVの文字化けを直すVBAを作成しているの 7 2022/11/04 14:15
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- Visual Basic(VBA) フォルダの場所を可変にしたいです(マクロ) 4 2023/05/11 10:00
- Visual Basic(VBA) エクセルVBAについて 8 2022/07/13 22:41
- Visual Basic(VBA) 複数csvを横に追加していくマクロについて 2 2023/04/25 09:19
- その他(プログラミング・Web制作) python 気象データの取得 2 2023/06/20 23:54
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- Visual Basic(VBA) 集めたシートのシート名を変更したい。 下記のコードでサブフォルダにあるファイルのSheet3を集めて 6 2022/08/23 10:38
- その他(プログラミング・Web制作) Fortranでの出力ファイル 2 2023/03/21 21:25
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CSVデータの編集の際の重複チェ...
-
Perlで特定行から特定行までを...
-
perlでcsvファイルを読む(ダブ...
-
Perlでの重複要素カウントにつ...
-
awkスクリプトでダブルクォーテ...
-
window.open でのファイル指定方法
-
ListBoxのデータを高速でファイ...
-
C言語で特定の行を抽出する方法...
-
ReadLineでの読み出し行を指定する
-
VBAでCSVファイルを途中行まで...
-
パスから最後のディレクトリだ...
-
ヒアドキュメントの書き方
-
Edge スクレイピング
-
ExcelをCSV書き出す場合のシー...
-
close()で例外が投げられる理由
-
配列の中に重複文字列があるか...
-
オープンしたファイルで行の連結
-
utf-8のCSVをshift_jisに変換し...
-
python renameについて
-
openした後、closeしないでプロ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Perlで特定行から特定行までを...
-
perlでcsvファイルを読む(ダブ...
-
BBCode削除&改行をサニタイジ...
-
Perlで空白行を削除
-
Perlの初心者です。2重ループ...
-
MATLAB std::exceptionエラー
-
ファイルの3行目までを出力したい
-
perlでファイルの比較
-
pythonでの実績データの処理プ...
-
cgiのログの書き方
-
先頭の単語が一致した時のデー...
-
書き込み時に勝手にクリアさせ...
-
エラーチェック、ファイルに特...
-
Argument "\\\\n" isn't numeri...
-
CSVファイルのデータの行数を取...
-
perl:パターンマッチを使ったif...
-
Pythonでegrep機能をつかいたい
-
batファイルでrenameができませ...
-
awkスクリプトでダブルクォーテ...
-
VBAでCSVファイルの特定行を書...
おすすめ情報