Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

regular expression code

I need to find match between two tab delimited files files like this:

File 1:

ID1  1  65383896    65383896    G   C  PCNXL3
ID1  2  56788990        55678900        T       A  ACT1 
ID1  1   56788990       55678900       T       A  PRO55

File 2

ID2 34    65383896   65383896       G   C  MET5
ID2  2   56788990       55678900       T       A  ACT1 
ID2  2   56788990       55678900       T       A  HLA

what I would like to do is to retrive the matching line between the two file. What I would like to match is everyting after the gene ID

So far I have written this code but unfortunately perl keeps giving me the error: use of "Use of uninitialized value in pattern match (m//)"

Could you please help me figure out where i am doing it wrong?

Thank you in advance!

use strict;

open (INA, $ARGV[0]) || die "cannot to open gene file";
open (INB, $ARGV[1]) || die "cannot to open coding_annotated.var files";

my @sample1 = <INA>;
my @sample2 = <INB>;

foreach my $line (@sample1) {
    my @tab = split (/\t/, $line);

    my $chr   = $tab[1];
    my $start = $tab[2];
    my $end   = $tab[3];
    my $ref   = $tab[4];
    my $alt   = $tab[5];
    my $name  = $tab[6];

    foreach my $item (@sample2){
        my @fields = split (/\t/,$item);

        if (   $fields[1] =~ m/$chr(.*)/
            && $fields[2] =~ m/$start(.*)/
            && $fields[4] =~ m/$ref(.*)/
            && $fields[5] =~ m/$alt(.*)/
            && $fields[6] =~ m/$name(.*)/
        ) {     
            print  $line, "\n", $item;
        }
    }
}
like image 999
Gaia Andreoletti Avatar asked Aug 12 '26 03:08

Gaia Andreoletti


1 Answers

On its surface your code seems to be fine (although I didn't debug it). If you don't have an error I cannot spot, could be that the input data has RE special character, which will confuse the regular expression engine when you put it as is (e.g. if any of the variable has the '$' character). Could also be that instead of tab you have spaces some where, in which case you'll indeed get an error, because your split will fail.

In any case, you'll be better off composing just one regular expression that contains all the fields. My code below is a little bit more Perl Idiomatic. I like using the implicit $_ which in my opinion makes the code more readable. I just tested it with your input files and it does the job.

use strict;

open (INA, $ARGV[0]) or die "cannot open file 1";
open (INB, $ARGV[1]) or die "cannot open file 2";

my @sample1 = <INA>;
my @sample2 = <INB>;


foreach (@sample1) {
    (my $id, my $chr, my $start, my $end, my $ref, my $alt, my $name) =
        m/^(ID\d+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)/;
    my $rex = "^ID\\d+\\s+$chr\\s+$start\\s+$end\\s+$ref\\s+$alt\\s+$name\\s+";
    #print "$rex\n";
    foreach (@sample2) {
        if( m/$rex/ ) {
            print "$id - $_";
        }
    }
}

Also, how regular is the input data? Do you have exactly one tab between the fields? If that is the case, there is no point to split the lines into 7 different fields - you only need two: the ID portion of the line, and the rest. The first regex would be

(my $id, my $restOfLine) = m/^(ID\d+)\s+(.*)$/;

And you are searching $restOfLine within the second file in a similar technique as above.

If your files are huge and performance is an issue, you should consider putting the first regular expressions (or strings) in a map. That will give you O(n*log(m)) where n and m are the number of lines in each file.

Finally, I have a similar challenge when I need to compare logs. The logs are supposed to be identical, with the exception of a time mark at the beginning of each line. But more importantly: most lines are the same and in order. If this is what you have, and it make sense for you, you can:

  1. First remove the IDxxx from each line: perl -pe "s/ID\d+ +//" file >cleanfile
  2. Then use BeyondCompare or Windiff to compare the files.
like image 149
Uri Avatar answered Aug 14 '26 17:08

Uri



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!