Use of uninitialized value in perl - regex

So I have this code:
use warnings;
use strict;
my #arr = ("stuff (06:13)", "more stuff (02:59)", "extra stuff (00:00)");
my #new_arr = map { /\((\d+:\d+)\)/ ; $1 } #arr;
my ( $sum, $hrs, $mins );
$sum = 0;
for my $t (#new_arr) {
my ( $h, $m ) = split m/:/, $t;
my $hm = $h * 3600;
my $tm = $m * 60;
$sum = $sum + $hm + $tm;
}
$mins = sprintf( "%02d", ( $sum % 3600 ) / 60 );
$hrs = int( $sum / 3600 );
print "$hrs:$mins\n";
and I got uninitialized value error
Use of uninitialized value $t in split at DR/Hello World/test.pl line 14.
Use of uninitialized value $h in multiplication (*) at DR/test.pl line 16.
Use of uninitialized value $m in multiplication (*) at DR/test.pl line 17.
so how can I fix that?

stuff (3+06:13) doesn't match /\((\d+:\d+)\)/, so $1 is left untouched, so $1 contains undef, so undef ends up in #arr.
It's unwise to use $1 without making sure the pattern matches. Either adjust the pattern to make sure it always matches,
/\(([\d+]+:\d+)\)/
Or filter out the results that don't match.
my #new_arr = map { /\((\d+:\d+)\)/ ? $1 : () } #arr;
-or-
my #new_arr = map { /\((\d+:\d+)\)/ } #arr;
You have a similar problem with map { /\((\d+\++)/ ; $1 }.

You're missing a capture in two of your regexes.
Your first one:
my #new_arr = map { /\((\d+:\d+)\)/ ; $1 } #arr;
Misses a capture in the first instance:
$VAR2 = [
undef,
'02:59',
'00:00'
];
Which can be corrected (see below).
Your second capture also fails to capture anything:
my #x = map {/\((\d+\++)/ ; $1 } #arr;
See:
$VAR3 = [
'3+',
undef,
undef
];
This is because your asking it to find a digit \d followed by a literal + one or more times, which only occurs in $arr[0]. Below i've adjusted to capture 0 if no capture is found:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my #arr = ("stuff (3+06:13)", "more stuff (02:59)", "extra stuff (00:00)");
my #new_arr = map { /\(.*?(\d+:\d+)\)/ ; $1 } #arr;
my #x = map {/\((\d+\+)|(0)/ ; $1 // $2 } #arr;
my ( $sum, $hrs, $mins );
$sum = 0;
for my $t (#new_arr) {
my ( $h, $m ) = split m/:/, $t;
my $hm = $h * 3600;
my $tm = $m * 60;
$sum = $sum + $hm + $tm;
}
$mins = sprintf( "%02d", ( $sum % 3600 ) / 60 );
$hrs = int( $sum / 3600 );
print "$hrs:$mins\n";
print Dumper (\#arr, \#new_arr, \#x);
$VAR1 = [
'stuff (3+06:13)',
'more stuff (02:59)',
'extra stuff (00:00)'
];
$VAR2 = [
'06:13',
'02:59',
'00:00'
];
$VAR3 = [
'3+',
'0',
'0'
];
Output:
9:12

Related

Getting first two strings between slashes

I have a string, alpha/beta/charlie/delta
I'm trying to extract out the string alpha/beta including the forward slash.
I'm able to accomplish this with split and joining the first and second result, but I feel like a regex might be better suited.
Depending on how many slashes there are as well will determine how many strings I need to grab, e.g. if there's 4 slashes get the first two strings, if there's 5, then grab first three. Again, my problem is extracting the slash with the string.
As Mathias already noticed - Split+Join is a perfectly valid solution:
$StringArray = #(
'alpha/beta/charlie/delta',
'alpha/beta/charlie/delta/omega'
'alpha/beta/charlie/gamma/delta/omega'
)
foreach ($String in $StringArray) {
$StringSplit = $String -split '/'
($StringSplit | Select-Object -First ($StringSplit.Count - 2) ) -join '/'
}
A little long, but I did it without regex:
$string = 'alpha/beta/charlie/delta/gamma'
# Count number of '/'
$count = 0
for( $i = 0; $i -lt $string.Length; $i++ ) {
if( $string[ $i ] -eq '/' ) {
$count = $count + 1
}
}
# Depending on the number of '/' you can create a mathematical equation, or simply do an if-else ladder.
# In this case, if count of '/' = 3, get first 2 strings, if count = 4, get first 3 strings.
function parse-strings {
Param (
$number_of_slashes,
$string
)
$all_slash = $number_of_slashes
$to_get = $number_of_slashes - 1
$counter = 0
for( $j = 0; $j -lt $string.Length; $j++ ) {
if( $string[ $j ] -eq '/' ) {
$counter = $counter + 1
}
if( $counter -eq $to_get ) {
( $string[ 0 .. ( $j - 1 ) ] -join "" )
break
}
}
}
parse-strings -number_of_slashes $count -string $string
You can try the .split() .net method where you define in parentheses where to split (on which character).
Then use the join operator “-join” to join your elements from the array
For your matter of concern use it like this:
$string = 'alpha/beta/charlie/delta/gamma'
$string = $string.split('/')
$string = "$($string[0])" + "/" + "$($string[1])"
$string
And so on...

Character match count between strings in Perl

I have a string (say string 1) that needs to be matched to another string (string2). Both the strings will have the same length and are case in-sensitive.
I want to print the number of character matches between both the strings.
E.g.: String 1: stranger
String 2: strangem
Match count = 7
I tried this:
$string1 = "stranger";
$string2 = "strangem";
my $count = $string1 =~ m/string2/ig;
print "$count\n";
How can I fix this?
Exclusive or, then count the null characters (where the strings were the same):
my $string1 = "stranger";
my $string2 = "strangem";
my $count = ( lc $string1 ^ lc $string2 ) =~ tr/\0//;
print "$count\n";
I missed the "case in-sensitive" bit.
You can use substr for that:
#!/usr/bin/perl
use warnings;
use strict;
my $string1=lc('stranger');
my $string2=lc('strangem');
my $count=0;
for (0..length($string1)-1) {
$count++ if substr($string1,$_,1) eq substr($string2,$_,1);
}
print $count; #prints 7
Or you can use split to get all characters as an array, and loop:
#!/usr/bin/perl
use warnings;
use strict;
my $string1=lc('stranger');
my $string2=lc('strangem');
my $count=0;
my #chars1=split//,$string1;
my #chars2=split//,$string2;
for (0..$#chars1) {
$count++ if $chars1[$_] eq $chars2[$_];
}
print $count; #prints 7
(fc gives more accurate results than lc, but I went for backwards compatibility.)
Not tested
sub cm
{
my #a = shift;
my #b = shift;
# First match prefix of string:
my $n = 0;
while ($n < $#a && $n < $#b && $a[$n] eq $b[$n]) {
++$n;
}
# Then skip one char on either side, and recurse.
if ($n < $#a && $n < $#b) {
# Match rest by skipping one place:
my $n2best = 0;
my $n2a = cm(splice(#a, $n), splice(#b, $n + 1));
$n2best = $n2a;
my $n2b = cm(splice(#a, $n + 1), splice(#b, $n));
$n2best = $n2b if $n2b > $n2best;
my $n2c = cm(splice(#a, $n + 1), splice(#b, $n + 1));
$n2best = $n2c if $n2c > $n2best;
$n += $n2best;
}
return $n;
}
sub count_matches
{
my $a = shift;
my $b = shift;
my #a_chars = split //, $a;
my #b_chars = split //, $b;
return cm(#a_chars, #b_chars);
}
print count_matches('stranger', 'strangem')

How can I make a histogram of occurences of specific patterns in a FASTA file?

I have written a Perl script for the following bioinformatics question, but unfortunately there is a problem with the output.
Question
1) From a file of 40,000 unique sequences, unique meaning the sequence id numbers, extract the following pattern
$gpat = [G]{3,5}; $npat = [A-Z]{1,25};<br>
$pattern = $gpat.$npat.$gpat.$npat.$gpat.$npat.$gpat;
2) For each sequence, find if $pattern occurs between the values of
0-100
100-200
200-300
...
900-1000
1000
If a certain sequence is <1000 characters long, even then the division must be maintained i.e. 0-100,100-200 etc.
The Issue
The main issue I am having is with counting the number of times $pattern occurs for each sequence subdivision and then adding its count for all the sequences.
For example, for sequence 1, say $pattern occurs 5 times at a length >1000. For sequence 2, say $pattern occurs 3 times at length>1000. Then total count should be 5+3 =8.
Instead, my result is coming like : (5+4+3+2+1) + (3+2+1) = 21 i.e. a cumulative total.
I am facing the same issue with the count for the first 10 subdivisions of 100 characters each.
I would be grateful if a correct code could be provided for this calculation.
The code I have written is as under. It is heavily derived from Borodin's answer to one of my previous questions here : Perl: Search a pattern across array elements
His answer is here: https://stackoverflow.com/a/11206399/1468737
The Code :
use strict;
use warnings;
my $gpat = '[G]{3,5}';
my $npat = '[A-Z]{1,25}';
my $pattern = $gpat.$npat.$gpat.$npat.$gpat.$npat.$gpat;
my $regex = qr/$pattern/i;
open my $fh, '<', 'small.fa' or die $!;
my ($id, $seq);
my #totals = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #intialize the #total arrays...
#..it should contain 10 parts for 10 divisions upto 1000bp
my #thousandcounts =(0); #counting total occurrences of $pattern at >1000 length
while (<$fh>) {
chomp;
if (/^>(\w+)/) {
process_seq($seq) if $id;
$id = $1;
$seq = '';
print "$id\n";
}
elsif ($id) {
$seq .= $_;
process_seq($seq) if eof;
}
}
print "Totals : #totals\n";
print "Thousand Counts total : #thousandcounts\n";
##**SUBROUTINE**
sub process_seq {
my $sequence = shift #_;
my $subseq = substr $sequence,0,1000;
my $length = length $subseq;
print $length,"\n";
if ($length eq 1000) {
my #offsets = map {sprintf '%.0f', $length * $_/ 10} 1..10;
print "Offsets of 10 divisions: #offsets\n";
my #counts = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
my #count = (0);
while ($sequence =~ /$regex/g) {
my $place = $-[0];
print $place,"\n\n";
if ($place <=1000){
for my $i (0..9) {
next if $place >= $offsets[$i];
$counts[$i]++;
last;
}
}
print "Counts : #counts\n\n";
$totals[$_] += $counts[$_] for 0..9;
if ($place >1000){
for my $i(0){
$count[$i]++;
last;
}
} print "Count greater than 1000 : #count\n\n";
$thousandcounts[$_] += $count[$_] for 0;
}
}
#This region of code is for those sequences whose total length is less than 1000
#It is working great ! No issues here
elsif ($length != 1000) {
my $substr = join ' ', unpack '(A100)*', $sequence;
my #offsets = map {sprintf '%.0f', $length * $_/ ($length/100)} 1..10;
print "Offsets of 10 divisions: #offsets\n";
my #counts = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0,);
while ($sequence =~ /$regex/g) {
my $place = $-[0];
print "Place : $place","\n\n";
for my $i (0..9) {
next if $place >= $offsets[$i];
$counts[$i]++; .
last;
}
}
print "Counts : #counts\n\n";
$totals[$_] += $counts[$_] for 0..9;
}
}#subroutine ends
I am also attaching a small segment of the file I am working with. This one is titled small.fa and I have been experimenting with this file only before moving onto to the bigger file containing >40,000 sequences.
>NR_037701 1
aggagctatgaatattaatgaaagtggtcctgatgcatgcatattaaaca
tgcatcttacatatgacacatgttcaccttggggtggagacttaatattt
aaatattgcaatcaggccctatacatcaaaaggtctattcaggacatgaa
ggcactcaagtatgcaatctctgtaaacccgctagaaccagtcatggtcg
gtgggctccttaccaggagaaaattaccgaaatcactcttgtccaatcaa
agctgtagttatggctggtggagttcagttagtcagcatctggtggagct
gcaagtgttttagtattgtttatttagaggccagtgcttatttagctgct
agagaaaaggaaaacttgtggcagttagaacatagtttattcttttaagt
gtagggctgcatgacttaacccttgtttggcatggccttaggtcctgttt
gtaatttggtatcttgttgccacaaagagtgtgtttggtcagtcttatga
cctctattttgacattaatgctggttggttgtgtctaaaccataaaaggg
aggggagtataatgaggtgtgtctgacctcttgtcctgtcatggctggga
actcagtttctaaggtttttctggggtcctctttgccaagagcgtttcta
ttcagttggtggaggggacttaggattttatttttagtttgcagccaggg
tcagtacatttcagtcacccccgcccagccctcctgatcctcctgtcatt
cctcacatcctgtcattgtcagagattttacagatatagagctgaatcat
ttcctgccatctcttttaacacacaggcctcccagatctttctaacccag
gacctacttggaaaggcatgctgggtctcttccacagactttaagctctc
cctacaccagaatttaggtgagtgctttgaggacatgaagctattcctcc
caccaccagtagccttgggctggcccacgccaactgtggagctggagcgg
gagggaggagtacagacatggaattttaattctgtaatccagggcttcag
ttatgtacaacatccatgccatttgatgattccaccactccttttccatc
tcccagaagcctgctttttaatgcccgcttaatattatcagagccgagcc
tggaatcaaactgcctctttcaaaacctgccactatatcctggctttgtg
acctcagccaagttgcttgactattctcagtctcagtttctgcacctgtc
aaatagggtttatgttaacctaactttcagggctgtcaggattaaatgag
catgaaccacataaaatgtttggtgtatagtaagtgtacagtaaatactt
ccattatcagtccctgcaattctatttttcttccttctctacacagcccc
tgtctggctttaaaatgtcctgccctgctttttatgagtggataccccca
gccctatgtggattagcaagttaagtaatgacactcagagacagttccat
ctttgtccataacttgctctgtgatccagtgtgcatcactcaaacagact
atctcttttctcctacaaaacagacagctgcctctcagataatgttgggg
gcataggaggaatgggaagcccgctaagagaacagaagtcaaaaacagtt
gggttctagatgggaggaggtgtgcgtgcacatgtatgtttgtgtttcag
gtcttggaatctcagcaggtcagtcacattgcagtgtgtcgcttcacctg
gctccctcttttaaagattttccttccctctttccaactccctgggtcct
ggatcctccaacagtgtcagggttagatgccttttatgggccacttgcat
tagtgtcctgatagaggcttaatcactgctcagaaactgccttctgccca
ctggcaaagggaggcaggggaaatacatgattctaattaatggtccaggc
agagaggacactcagaatttcaggactgaagagtatacatgtgtgtgatg
gtaaatgggcaaaaatcatcccttggcttctcatgcataatgcatgggca
cacagactcaaaccctctctcacacacatacacatatacattgttattcc
acacacaaggcataatcccagtgtccagtgcacatgcatacacgcacaca
ttcccttcctaggccactgtattgctttcctagggcatcttcttataaga
caccagtcgtataaggagcccaccccactcatctgagcttatcaaccaat
tacattaggaaagactgtatttcctagtaaggtcacattcagtagtactg
agggttgggacttcaacacagctttttgggggatcataattcaacccatg
acagccactgagattattatatctccagagaataaatgtgtggagttaaa
aggaagatacatgtggtacaaggggtggtaaggcaagggtaaaaggggag
ggaggggattgaactagacacagacacatgagcaggactttggggagtgt
gttttatatctgtcagatgcctagaacagcacctgaaatatgggactcaa
tcattttagtccccttctttctataagtgtgtgtgtgcggatatgtgtgc
tagatgttcttgctgtgttaggaggtgataaacatttgtccatgttatat
aggtggaaagggtcagactactaaattgtgaagacatcatctgtctgcat
ttattgagaatgtgaatatgaaacaagctgcaagtattctataaatgttc
actgttattagatattgtatgtctttgtgtccttttattcatgaattctt
gcacattatgaagaaagagtccatgtggtcagtgtcttacccggtgtagg
gtaaatgcacctgatagcaataacttaagcacacctttataatgacccta
tatggcagatgctcctgaatgtgtgtttcgagctagaaaatccgggagtg
gccaatcggagattcgtttcttatctataatagacatctgagcccctggc
ccatcccatgaaacccaggctgtagagaggattgaggccttaagttttgg
gttaaatgacagttgccaggtgtcgctcattagggaaaggggttaagtga
aaatgctgtataaactgcatgatgtttgcaggcagttgtggttttcctgc
ccagcctgccaccaccgggccatgcggatatgttgtccagcccaacacca
caggaccatttctgtatgtaagacaattctatccagcccgccacctctgg
actccctcccctgtatgtaagccctcaataaaaccccacgtctcttttgc
tggcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaa
>NR_002714 1
gttatacatctctaccattacctagcctgaaaagccacctcagattcagc
caacaagtaagtgggcattacaggagaagggtacctttcacaagggctgt
aatctaaaatcttggggaagatacagcgtcatctgtccaagaggtgtcag
cagtaacgaagcctcagtagaagccaaagttattttggattactgagcct
gtatagtttccagattctcaagagaaatatatgggaatgtagatatctca
gaggaccttcctgctgtcaggaattcagaggaggaaataaggaaggtaat
aggtgctctgctctcattctctcaaaccctcttccctgtgttttcctata
gagattgctgatttgctccttaagcaagagattcactgctgctcagcatg
gctcagaccaactcatgcttcatgctgatctcctgcctgatgttcctgtc
tctgagccaaggtgagattgttttccccacacatacctcccacaacccca
gccctgaagccctcactctatcctcatgcatatgagttcacttgagaaaa
agcagagtcaagttcaggggttgttttgtgttgttcagtgatatttattg
ctgatctcatcccattcaaaaacatcctgacctccctaaggagttagaga
tggaacttagcataaccctttatcagtgaccactgcagttggcattggtt
tgtcatattaacactactcatgatgggggtgttgaggatgtctgtttgta
gacagtcattagtggaatggggaactgaggggagctttgtgtgtagagaa
actggacaggcttgagaaagaagcctcagtccttcaaggaagaaaaagcc
ataagtaaaagggacaatggggacacttttcatgagcctattcattgtgt
gctcttgtcttgagcaaagacatcttgagagcctataggtaagatgcaga
agggcagaagtgaccaatcgcttcgtgacctataggatccttctattcct
ataaagaatcctcagaagctcctacctcatattttagcctttaccttgcc
ctgagggtctttcttaattgtctctcttttcccaggacaggaggcccatg
ctgagttgcccaaggcccagatcagctgcccagaaggcaccagtgcctaa
ggctcccactgctactactttaatgaagagcatgagacctgggtttatgc
agatgtgagtgaggagagcagtgtgggaagggaggctcacgaagggaggg
gaagctgccactctccagtgtgttcagtggctgatatgagatgagactaa
tcccctccctatccaatcatcagcccaaaactttccaatctactttatcc
catcattcagcacagagatgctggtggtcagtgacagcatcatcagggac
atttctgtgctgtcctttttctgttacatcctctgggagggctcaatatg
tctcccacactttcctccttcactgagtgctccattttcttctccaacag
ctctactgccagaacatgaattcaggtaacctggtgtctgtgctcaccca
ggctgagggtgcctttgtggcttcgctgattaaagagagtggcaccaagg
atagcaatgtctggattggcctccatgacccccaccggatcagtctgctg
catcttctacctcctgattatcaggttccagagggtctgatgtctggcac
ctcaagcatcagtttttactatattatgataaaagcaacctctctataaa
tcatataatgtaaaggatatcaaggttctccataggttcttcgagataag
cttaaagctgaatttcctgtgtgtttcaggcattcacagataaactcatt
ctctgtacttctagggtagcatctttatgtatctattatgtacctcttat
ctattgtgttatcatctctgttatagaagagccttctgtagaccatatag
aaaaagattatagaggaggagaatctactgctggcaattgggaaccgcaa
ggtatactaaataatatatcaacaactaatggccatctaatgctatgctg
gatatgaacttttggggcctcaggaaagaaaaaccaggaactagtttcaa
taatgaggtgtcatggttccctgtggcaaatttagaacgcttatcgtttg
gcaggacacagagaggtaggtgaacattccaggaaagaagcagcttagag
aaaatgtggaggaaataatatgacacttagagaaaaaggaaggtttattc
ttgtcttatgtcttgacctgtttctgagtgcgaacacaaaccaggtgttt
ctgtctctttctgagtcacgtctgcccctgttctggcccttccccatcta
gaactgccattatcagtggagtagtgggtccctggtctcctacaaatcct
gggacattggatccccaagctgtgccaatactgcctactgtgctagcctg
acttcaagctcaggtgaggggcacagaatccacacacttattgccatcct
ctcctatttatctctgaggatcgaccggggactgggatagaggaagggtg
agctcctcattcaggaaatagaggagtgtttcctctttatttttgctgag
tcctgcagccaggagggtaatacactctgatcccctcagtctgaatcttc
tcattgtcttataggattcaagaaatggaaggatgattcttgtaaggaga
agttctcctttgtttgcaagttcaaatactggaggcaattgtaaaatgga
cgtctagaattggtctaccagttactatggagtaaaagaattaaactgga
ccatctctctccatatcaatctggaccatctctcctctgctaaatttgca
tgactgatctttagtatctttacctacctcaatttctggagccctaaaca
ataaaaataaacatgtttcccccat
>NR_003569 1
ctgggacccacgacgacagaaggcgccgatggccgcgcctgctgagccct
gcgcggggcagggggtctggaaccagacagagcctgaacctgccgccacc
agcctgctgagcctgtgcttcctgagaacagcaggggtctgggtaccccc
catgtacctctgggtccttggtcccatctacctcctcttcatccaccacc
atggccggggctacctccggatgttccccactcttcaaagccaagatggt
gcttggattcgccctcatagtcctgtgtacctccagcgtggctgtcgctc
tttggaaaatccaacagggaacgcctgaggccccagaattcctcattcat
cctactgtgtggctcaccacgatgagcttcgcagtgttcctgattcacac
caagaggaaaaagggagtccagtcatctggagtgctgtttggttactggc
ttctctgctttgtcttgccagctaccaacgctgcccagcaggcctccgga
gcgggcttccagagcgaccctgtccgccacctgtccacctacctatgcct
gtctctggtggtggcacagtttgtgctgtcctgcctggcggatcaacccc
ccttcttccctgaagacccccagcagtctaacccctgtccagagactggg
gcagccttcccctccaaagccacgttctggtgggtttctggcctggtctg
gaggggatacaggaggccactgagaccaaaagacctctggtcgcttggga
gagaaaactcctcagaagaacttgtttcccggcttgaaaaggagtggatg
aggaaccgcagtgcagcccgggggcacaacaaggcaatagcatttaaaag
gaaaggcggcagtggcatggaggctccagagactgagcccttcctacggc
aagaagggagccagtggcgcccactgctgaaggccatctggcaggtgttc
cattctaccttcctcctggggaccctcagcctcgtcatcagtgatgtctt
caggttcactgtccccaagctgctcagccttttcctggagtttattggtg
atcccaagcctccagcctggaagggctacctcctcgccgtgctgatgttc
ctctcggcctgcctgcaaacgctgtttgagcagcagaacatgtacaggct
caaggtgctgtagatgaggctgcggtcggccatcactggcctggtgtaca
gaaaggcatccacagcatatctgaagaaatattcagaagttaactaatct
cagatgatttcagcaggagtaaagaagagaaacagactcagaaatgccat
tacaacagttaattatgtcaaatttatcaccctgattgatcacgcagcat
taacctcaagaacgccaagccaagtttttttgacaaatgtgagccaaggt
ttccgaaaaactagcagatatgactgtgacttacaaaatggaaaaagtaa
acgagaaacacaatttgatatgatttaataaaagatttgtttccaccact
tctcctgggaacctcagcacattttctttccactgacagttattatctct
acctttattgaacaaagacacccggaacacagctgctgaggatcagtaaa
gaaaatcattcttttattaataagactgttattagcaggaaaaaaaaatc
catgtttgggagtttgcactgaagttacaggccattttgaagaaatatgg
ctgactagtgccaacattatttcaggcaatttcatgatcaaatgtcttat
taggttgtttaaaatttttatagagattgtaaatcagaactattttctat
ttgccctaaatatttagatgctacagggaaagcagatcaaattaaagggt
actgtgcacatttttttactgggaactcccagggatataaatcatttcgc
ctgcagcatggaattcttcagtacacatgcttgtggaaacattccacgct
ccgccagcacgctcattaaagtgatgatttgggttgcaacaacagtgcca
agtacttcctgtgttcaactggggaccatgtggcaagacccaaagcttcc
ccagagatcctatgggaataagttttttgagccaccatattccattattt
cagcctaaaataacaccatgggacaagaatcagaagacagaggagcagac
aaatgtgtgtagacatgctggaaggaatctttctttttagaaacagggtc
aatatctattaaactttaagatgtgtatctcttgacctggcagtttctgt
atttgagttttaacctactgatatacccatgcatgtgaataaagtatctt
cctgcatgtaacaggatatttaatgtaaccttgattatagttgcaaatgc
tgggaaacgatccaaatgtctttcaatatggcactgattaaataaattat
ggcacagtctcacaatgaaaaacaaatgtagccattaaacagaatgaaat
gggtctagctaaattgaaataggactacctctaagatatgttgttaaaaa
gaaaaaaaagaaagtgcagaggaacaagtatgataccattttgtattttt
taacatatgcaagcgtgattgtgcccacacagaatacctttgaaaataaa
ctcagtatttgcctcagtggataaaaacaagaaccagccttattttcact
gttatatcttttggtgccactttttgaactttttaccatatgtgcatatg
taactttctaaataaattttgtaaaaaaaaaaaaaaaaaa
>NR_002817 2
aactcggtctccactgcactgctggccagacgagggatgttattttgggc
agtgcatctggacttggttcaagtggcaccagccaaatccctgccttact
gacctctcccctggaggagcaggagcagtgctcaaggccgccctgggagg
gctgagaggcaggctctggactggggacacagggatagctgagccccagc
tgggggtggaagctgagccagggacagtcacagaggaacaagatcaagat
gcgctttaactgagaagcccccaaggcagaggctgagaatcagaagacat
ttcagcagacatctacaaatctgaaggacaaaacatggttcaagcatctg
ggcacaggcggtccacccgtggctccaaaatggtctcctggtccgtgata
gcaaagatccaggaaatatggtgcgaggaagatgagaggaagatggcgcg
agagttcctggccgagttcatgagcacatatgtcatgatggagtggctga
ccgggatgctccagctgtgtctcttcgccatcgtggaccaggagaacaac
ccagcactgccaggaacacacgcactggtgataggcatcctcgtggtcat
catcagggtgtaccatggcatgaacacaggatatgccatcaatccgtccc
gggacctgccccccccccccgcatcttcaccttcattgctggttggggca
aactggtcttcaggtactgcccctgcccaggcccattcctttgagatttt
ctgtggggcccctgtgtgttgaggtgtggggggtgatgtgaggggcagca
caggagggtcctgcagagcccccaggtggcctggggagcaggagtgagtc
ccaacatttccccaggccagtagagatacagatcctgcacctgcactgag
tgtcaaccctgtccctgagtcgggctgaggctgaccagggccccgggttg
ggggtgtttcctgggttagcctgaggatgactcctctgctcaaccagtct
tggcccgaggtggatgagggtgctgtcctgggcatcagccccctcagccg
gcctctgcctcttgcctgcagcgatggggagaacttgtggtgggtgccag
tggtggcaccacttctgggtgcctctctaggtggcatcatctacctggtc
ttcattggctccaccatcccacgggagcccctgaaattggaggactctgt
ggcatatgaagaccacgggataaccgtattgcccaagatgggatctcatg
aacccatgatctctccccttaccctcatctccgtgagccctgccaacaga
tcttcagtccaccctgccccacccttacatgaatccatggccctagagca
cttctaagcagagattatttgtgatcccatcccttccccaataaagagaa
gcttgtcccacagcagtacccccacttcctgggggcctcctgtggttggg
cttccctcctgggttcttccaggagctctagggctatgtcttagcccaag
gtgtagaggtgaggcacctcaagtctttcatgccctgggaactggggtgc
cccagggggagaatggggaagagctgacctgcgccctcagtaggaacaag
gtaagatgaaagaatgacagaaacagaatgagggattttcaggcaagggg
gaaggaagggcagttttggtgaaaggactgtagctgactggtggggggct
ggctttggaaatactttgaggggatcctgagactggactctagactctcc
cctggttgttcccttccccgagttctggccggttcttggaccagacaagg
catggcccaagaaggtagatcagaattttttagcctttttttcattagtg
ccttccctagtataattccagattttttttcttaatcacatgaaatttta
ataccacagatatactatacatctgtttatgttctgtatatgttctgtgc
tttatacgtaaaaaagagtaagattttttttcacctccccttttaagaat
cagttttaattcccttgagaatgcttgttatagattgaaggctggtaagg
ggttgggctcctctttcttcttcctggtgccagagtgctcccacatgaag
gaataggaaaggaagatgcaaagagggaaatccttcgaacacatgaagac
acaggaagaggcctcttagggctccaagggctccagggaagcagctgcag
aggttgggtggggtgaggggccaggatccactgaccctggggccaggcag
gaatcactctgttgcctggggctcagaaggcagtatcacccatggttcct
gtcattgctcatgtattttgcctttcaacaattattgtgcacctactgtg
tgcaggccctgcctggacactggggatgcgcagtggatgcactgggctct
gcctttgagggttgcagtttaatgggtgacaggtaattataaggaagaag
gtgagtgcagagtgggaggcttggaggctgtggggcttggggtgggggag
ctcacatccagcctctgggccaaggccaggaggcttcccagagcaggaga
cagagcagggtattgtggtggggggtgtcctttttggggctgggatctgc
actttacagtttgaggggatgggcagaggaggctgggcttcattctggag
gtggggacatggtgaggtgaggtttagaaagcacacctgagccgcagtgt
gtaggatgctggaaatggtggagatgggcctgcgaagagagtgctgggaa
gtgatgacccaggagcagcagccgggcacctaacaatgggtcagcaccgt
gggcgtggagacaaaggccgggattgatcaatacccgagaagtacaatgt
acaggacttgggctccatttggatggagtgggtgagggaggagtcagaaa
tggcttccgatttccagcttgggcctggggattggagatgtccccactga
gagtagggcacaagtgaggaaatggtttggagaggaagatgataagttac
atcatggatgtgctgagtctgagttgcctatgggacttggaatggggggt
ggcaaaaggtgtgtgatcttgagcaagatattcaactcttctgggccttg
gtcttctcatttgtaaaacggtgataagaatattacttcccatttgtgtt
gctgtgaatattaaatgcgctaccacatgt
Thank you for taking the time to go through my problem.
Any help and input would be deeply appreciated.
Thank you for taking the time to go through my problem!
This is pretty much the same as your previous problem except that the intervals are independent of the length of the sequence and so can be defined just once instead of changing them for every sequence.
This program is a modification of my previous solution. As I described, it starts with a fixed set of values in #offsets from 100 to 1000 in steps of 100, and the final range > 1000 is terminated at 2E9 or 2 billion. This is close to the maximum positive 32-bit integer and serves to catch all offsets above 1000. I assume you won't be dealing with sequences any bigger than this?
The #totals and #counts arrays are initialised to zeroes with the same number of elements as the #offsets array.
Otherwise the functionality is much as before.
use strict;
use warnings;
use List::MoreUtils 'firstval';
my $gpat = '[G]{3,5}';
my $npat = '[A-Z]{1,25}';
my $pattern = $gpat.$npat.$gpat.$npat.$gpat.$npat.$gpat;
my $regex = qr/$pattern/i;
open my $fh, '<', 'small.fa' or die $!;
my #offsets = map $_*100, 1 .. 10;
push #offsets, 2E9;
my #totals = (0) x #offsets;
my ($id, $seq);
while (<$fh>) {
chomp;
if (/^>(\w+)/) {
process_seq($seq) if $id;
$id = $1;
$seq = '';
print "$id\n";
}
elsif ($id) {
$seq .= $_;
process_seq($seq) if eof;
}
}
print "Total: #totals\n";
sub process_seq {
my $sequence = shift;
my #counts = (0) x #offsets;
while ($sequence =~ /$regex/g) {
my $place = $-[0];
my $i = firstval { $place < $offsets[$_] } keys #offsets;
$counts[$i]++;
}
print "Counts: #counts\n\n";
$totals[$_] += $counts[$_] for keys #totals;
}
output
Running this program against your new data file small.fa produces
Total: 1 1 0 0 0 0 0 1 0 1 10
But using the data from the previous question, sample.fa is much more interesting
Total: 5 4 1 0 0 2 2 1 0 0 1
The following seems to work. While playing around, I put the data you posted in the __DATA__ section at the end of the script. To use it with a real data file, you'll need to open it, and pass the file handle to run.
#!/usr/bin/env perl
use strict; use warnings;
use Data::Dumper;
use List::MoreUtils qw( first_index );
if (#ARGV) {
my ($input_file) = #ARGV;
open my $input, '<', $input_file
or die "Cannot open '$input_file': $!";
run($input);
close $input
or die "Cannot close '$input_file': $!";
}
else {
run(\*DATA);
}
sub run {
my ($fh, $start_pat, $stop_pat) = #_;
# These are your patterns. I changed $npat because I don't
# think, e.g., q is a valid character in your input.
my $gpat = '[g]{3,5}';
my $npat = '[acgt]{1,25}';
my $wanted = qr/$gpat$npat$gpat$npat$gpat$npat$gpat/;
# These just tell us where a sequence begins and ends.
my $start = qr/\A>([A-Za-z_0-9]+)/;
my $stop = qr/[^acgt]/;
# Set up the bins and labels for the histogram.
my #bins = map 100 * $_, 1 .. 10;
my #labels = map sprintf('%d - %d', $_ - 100, $_), #bins;
# Initialize the histogram with all zero counts.
my %hist = map { $_ => 0 } #labels;
my $id;
while (my $line = <$fh>) {
# Whenever you see a new sequence, read it completely
# and pass it to build_histogram.
if (($id) = ($line =~ $start)) {
print "Start sequence: '$id':\n";
my $seq_ref;
($line, $seq_ref) = read_sequence($fh, $stop);
my $hist = build_histogram(
$seq_ref,
$wanted,
\#bins,
\#labels,
);
# Add the counts from this sequence to the overall
# histogram.
for my $key ( keys %$hist ) {
$hist{ $key } += $hist->{$key};
}
# exit loop if read_sequence stopped because of EOF.
last unless defined $line;
# else see if the line that stopped input is the start
# of a new sequence.
redo;
}
}
print Dumper \%hist;
}
sub build_histogram {
my ($seq_ref, $wanted, $bins, $labels) = #_;
my %hist;
while ($$seq_ref =~ /$wanted/g) {
# Whenever we find segment which matches what we want,
# store the position,
my $pos = $-[0];
# and find the bin where it fits.
my $idx = first_index { $_ > $pos } #$bins;
# if you do not have List::MoreUtils, you should install it
# however, the grep can be used instead of first_index
# my ($idx) = grep { $bins->[$_] > $pos } 0 .. $#$bins;
# $idx = -1 unless defined $idx;
# if it did not fit in the bins, then the position must
# be greater than the upper limit of the last bin, put
# it in "> than upper limit of last bin".
my $key = ($idx == -1 ? "> $bins->[-1]" : $labels->[$idx]);
$hist{ $key } += 1;
}
# we're done matching, return the histogram for this sequence
return \%hist;
}
sub read_sequence {
my ($fh, $stop) = #_;
my ($line, $seq);
while ($line = <$fh>) {
$line =~ s/\s+\z//;
last if $line =~ $stop;
$seq .= $line;
}
return ($line, \$seq);
}
__DATA__
-- Either paste your data here, or pass the name
-- of your input file on the command line
Output:
Start sequence: 'NR_037701':
Start sequence: 'NR_002714':
Start sequence: 'NR_003569':
Start sequence: 'NR_002817':
$VAR1 = {
'700 - 800' => 0,
'> 1000' => 10,
'200 - 300' => 1,
'900 - 1000' => 1,
'800 - 900' => 1,
'500 - 600' => 0,
'0 - 100' => 0,
'100 - 200' => 1,
'300 - 400' => 0,
'400 - 500' => 0,
'600 - 700' => 0
};
Also, you should take Chris Charley's advice and use Bio::SeqIO to read sequences rather than my homebrewed read_sequence function. I was just too lazy to install BioPerl just for the purpose of answering this question.
Generally, in Perl you can count the occurrence of a pattern by:
$_ = $input;
my $c = 0;
$c++ while s/pattern//s;
I was finally able to figure out where I was going wrong with my code. It turned out to be a looping problem. The following code works perfectly. I have marked it in comments the places where I made the modification.
#!/usr/bin/perl -w
use strict;
use warnings;
my $gpat = '[G]{3,5}';
my $npat = '[A-Z]{1,25}';
my $pattern = $gpat . $npat . $gpat . $npat . $gpat . $npat . $gpat;
my $regex = qr/$pattern/i;
open OUT, ">Quadindividual.refMrna.fa" or die;
open my $fh, '<', 'refMrna.fa' or die $!;
my ( $id, $seq ); # can be written as my $id; my $seq;
my #totals = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ); #intialize the #total arrays.
my #thousandcounts = (0);
while (<$fh>) {
chomp;
if (/^>(\w+)/) {
process_seq($seq) if $id;
$id = $1;
$seq = '';
print "$id\n";
print OUT "$id\n";
}
elsif ($id) {
$seq .= $_;
process_seq($seq) if eof;
}
}
print "Totals : #totals\n";
print OUT "Totals : #totals \n";
print "Thousand Counts total : #thousandcounts\n";
print OUT "Thousand Counts total : #thousandcounts\n";
sub process_seq {
my $sequence = shift #_;
my $subseq = substr $sequence, 0, 1000;
my $length = length $subseq;
print $length, "\n";
my #offsets = map { sprintf '%.0f', $length * $_ / 10 } 1 .. 10;
print "Offsets of 10 divisions: #offsets\n";
my #counts = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, );
my #count = (0);
# *MODIFICATION*
# This if loop was intialized from my #offsets above earlier
if ( $length eq 1000 ) {
while ( $sequence =~ /$regex/g ) {
my $place = $-[0];
print $place, "\n\n";
if ( $place <= 1000 ) {
for my $i ( 0 .. 9 ) {
next if $place >= $offsets[$i];
$counts[$i]++;
last;
}
}
if ( $place > 1000 ) {
for my $i (0) {
$count[$i]++;
last;
}
}
} #*MODIFICATION*
#The following commands were also subsequently shifted to ..
#...properly compute the total
print "Counts : #counts\n\n";
$totals[$_] += $counts[$_] for 0 .. 9;
print "Count : #count\n\n";
$thousandcounts[$_] += $count[$_] for 0;
}
elsif ( $length != 1000 ) {
my $substr = join ' ', unpack '(A100)*', $sequence;
my #offsets =
map { sprintf '%.0f', $length * $_ / ( $length / 100 ) } 1 .. 10;
print "Offsets of 10 divisions: #offsets\n";
my #counts = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, );
while ( $sequence =~ /$regex/g ) {
my $place = $-[0];
print "Place : $place", "\n\n";
for my $i ( 0 .. 9 ) {
next if $place >= $offsets[$i];
$counts[$i]++;
last;
}
}
print "Counts : #counts\n\n";
$totals[$_] += $counts[$_] for 0 .. 9;
}
} #subroutine ends

How to replace one or more strings within a string in Perl

$args[0] is a reference to a string containing one or more times. I am shifting each time by a variable number of seconds, but then I need to find a way to store (replace) the changed times back into the original string. Any help is appreciated. Here is roughly what I am working with:
my $TIMEREGEX = qr/(\d{2}:\d{2}:\d{2}\.\d{3}|\d{2}:\d{2}:\d{2})/x;
if ( my #sTime = ${$args[0]} =~ /$TIMEREGEX/g )
{
warn "\ttime(s) found #sTime\n" if $main::opt{d};
for my $i ( 0..$#sTime )
{
$sTime[$i] =~ /(\d{2}):(\d{2}):(\d{2})(\.(\d{3}))?/;
my $epoch_time = ( $1 * 3600 ) + ( $2 * 60 ) + $3;
$epoch_time += $epoch_shift;
my #f;
$f[0] = $epoch_time % 86400 / 3600; # hours
$f[1] = $epoch_time % 3600 / 60; # minutes
$f[2] = $epoch_time % 60; # seconds
my $save = $sTime[$i];
$sTime[$i] = sprintf ( "%02d:%02d:%02d", $f[0], $f[1], $f[2] );
$sTime[$i] .= $4 if defined ( $4 );
warn "\tTimeShift $save => $sTime[$i]\n" if $main::opt{d};
### some other stuff
}
# ${$args[0]} = "$1$t[0]$4$t[1]$7$t[2]$10";
### save the changes to ${$args[0]} !
}
Use the substitution operator.
use 5.010; # or better for 'say' and '//'
use strictures;
use Time::Piece qw();
my #args; my $epoch_shift = 500;
${$args[0]} = 'foo18:00:00.123bar18:00:00baz18:00:00quux';
${$args[0]} =~
s{
(\d{2}:\d{2}:\d{2}) # capture hh:mm:ss
(\.\d{3})? # optionally capture
# decimal dot and milliseconds
}
{
(
$epoch_shift
+ Time::Piece->strptime($1, '%T')
)->strftime('%T').($2 // '')
}egx;
say ${$args[0]};
# foo18:08:20.123bar18:08:20baz18:08:20quux

Perl regex syntax generation

This is a follow up to the question posted here: Perl Regex syntax
The results from that discussion yielded this script:
#!/usr/bin/env perl
use strict;
use warnings;
my #lines = <DATA>;
my $current_label = '';
my #ordered_labels;
my %data;
for my $line (#lines) {
if ( $line =~ /^\/(.*)$/ ) { # starts with slash
$current_label = $1;
push #ordered_labels, $current_label;
next;
}
if ( length $current_label ) {
if ( $line =~ /^(\d) "(.*)"$/ ) {
$data{$current_label}{$1} = $2;
next;
}
}
}
for my $label ( #ordered_labels ) {
print "$label <- as.factor($label\n";
print " , levels= c(";
print join(',',map { $_ } sort keys %{$data{$label}} );
print ")\n";
print " , labels= c(";
print join(',',
map { '"' . $data{$label}{$_} . '"' }
sort keys %{$data{$label}} );
print ")\n";
print " )\n";
}
__DATA__
...A bunch of nonsense I do not care about...
...
Value Labels
/gender
1 "M"
2 "F"
/purpose
1 "business"
2 "vacation"
3 "tiddlywinks"
execute .
Essentially, I need to build the Perl to accommodate a syntax shorthand found in the SPSS file. For adjacent columns, SPSS allows one to type something like:
VALUE LABELS
/agree1 to agree5
1 "Strongly disagree"
2 "Disagree"
3 "Neutral"
4 "Agree"
5 "Strongly agree"
As the script currently exists, it will generate this:
agree1 to agree5 <- factor(agree1 to agree5
, levels= c(1,2,3,4,5,6)
, labels= c("Strongly disagree","Disagree","Neutral","Agree","Strongly agree","N/A")
)
and I need it to produce something like this:
agree1 <- factor(agree1
, levels= c(1,2,3,4,5,6)
, labels= c("Strongly disagree","Disagree","Neutral","Agree","Strongly agree","N/A")
)
agree2 <- factor(agree2
, levels= c(1,2,3,4,5,6)
, labels= c("Strongly disagree","Disagree","Neutral","Agree","Strongly agree","N/A")
)
…
use strict;
use warnings;
main();
sub main {
my #lines = <DATA>;
my $vlabels = get_value_labels(#lines);
write_output_delim($vlabels);
}
# Extract the value label information from SPSS syntax.
sub get_value_labels {
my (#vlabels, $i, $j);
for my $line (#_){
if ( $line =~ /^\/(.+)/ ){
my #vars = parse_var_range($1);
$i = #vlabels;
$j = $i + #vars - 1;
push #vlabels, { var => $_, codes => [] } for #vars;
}
elsif ( $line =~ /^\s* (\d) \s+ "(.*)"$/x ){
push #{$vlabels[$_]{codes}}, [$1, $2] for $i .. $j;
}
}
return \#vlabels;
}
# A helper function to handle variable ranges: "agree1 to agree3".
sub parse_var_range {
my $vr = shift;
my #vars = split /\s+ to \s+/x, $vr;
return $vr unless #vars > 1;
my ($stem) = $vars[0] =~ /(.+?)\d+$/;
my #n = map { /(\d+)$/ } #vars;
return map { "$stem" . $_ } $n[0] .. $n[1];
}
sub write_output_delim {
my $vlabels = shift;
for my $vlab (#$vlabels){
print $vlab->{var}, "\n";
print join("\t", '', #$_), "\n" for #{$vlab->{codes}}
}
}
sub write_output_factors {
# You get the idea...
}
__DATA__
/gender
1 "M"
2 "F"
/purpose
1 "business"
2 "vacation"
3 "tiddlywinks"
/agree1 to agree3
1 "Disagree"
2 "Neutral"
3 "Agree"