Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Powered Descent
Jul 13, 2008

We haven't had that spirit here since 1969.

My huge thanks to all of you for the insights -- I've now stopped doubting my own sanity and I'm back to doubting everyone else's. :)

I'll keep on coding, and I'll definitely look up Perl Best Practices and Modern Perl. And continue to curse the universe when I run across a piece of code that looks something like $'\\_&'":_#{'"@(`$)};

Adbot
ADBOT LOVES YOU

Peanutmonger
Dec 6, 2002
Without default variables, this idiom would be much noisier:
Perl code:
while(<>) {
  chomp;
  if(/some pattern/) {
    ...
  } elsif(/another pattern/) {
    ...
  } else {
    warn "couldn't parse line: $_";
  }
}

het
Nov 14, 2002

A dark black past
is my most valued
possession

Peanutmonger posted:

Without default variables, this idiom would be much noisier:
Perl code:
while(<>) {
  chomp;
  if(/some pattern/) {
    ...
  } elsif(/another pattern/) {
    ...
  } else {
    warn "couldn't parse line: $_";
  }
}
Honestly I'd just name a variable for that, I don't think it hurts readability and it obviates any problems you might run into when the logic gets more complicated than that. It's fine for one-liners, and maybe ad-hoc scripts you just write up on the fly, but beyond that it would bug me.

welcome to hell
Jun 9, 2006
It also changes the global value of $_, so if another part of the code tries to take similar shortcuts you'll run into problems. for/map/grep at least localize $_, so they don't suffer as much from this issue.

Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?
The main thing to keep in mind when reading Perl Best Practices (and to be fair it's mentioned in the preface) is that the book's contents are not to be taken as the gospel truth. As welcome to hell said, about half of what it recommends you should avoid outright (inside-out objects, anyone?).

Also, Higher-Order Perl is probably one of the better Perl books ever written, and is available for free from the author, so check that out too.

ephphatha
Dec 18, 2009




welcome to hell posted:

It also changes the global value of $_, so if another part of the code tries to take similar shortcuts you'll run into problems. for/map/grep at least localize $_, so they don't suffer as much from this issue.

Edit: And now I see you mentioned for loops. And when I run nested while (<>) loops it does trample the $_ variable.

code:
#! /usr/bin/perl -w

use strict;

while (<>) {
  print "Preloop: $_";
  while (<>) {
    print "Inner: $_";
    last;
  }
  print "Postloop: $_";
}

exit;
$ ./test.pl test.pl
Preloop: #! /usr/bin/perl -w
Inner:
Postloop:
Preloop: use strict;
Inner:
Postloop:
Preloop: while (<>) {
Inner: print "Preloop: $_";
Postloop: print "Preloop: $_";
Preloop: while (<>) {
Inner: print "Inner: $_";
Postloop: print "Inner: $_";
Preloop: last;
Inner: }
Postloop: }
Preloop: print "Postloop: $_";
Inner: }
Postloop: }
Preloop:
Inner: exit;
Postloop: exit;
Preloop:
Use of uninitialized value $_ in concatenation (.) or string at ./test.pl line 11, <> line 15.
Postloop:

ephphatha fucked around with this message at 02:51 on Jun 26, 2013

Rohaq
Aug 11, 2006

Ephphatha posted:

Edit: And now I see you mentioned for loops. And when I run nested while (<>) loops it does trample the $_ variable.
Eugh, one of the reasons I avoid using $_. Much better to define a variable and know that when you refer to it, you know exactly what you're getting, especially if you want maintainable code.

Precambrian Video Games
Aug 19, 2002



code:
use strict;

my $first = multi_array();
my @values = @$first;
print "First is " . $first . " with values @values\n";

($first,undef) = multi_array();
@values = @$first;
print "First is " . $first . " with values @values\n";

my $second;
($first,$second) = multi_array();
@values = @$first;
my @svalues = @$second;
print "First, second " . $first . " " . $second . " with values @values @svalues\n";

sub multi_array
{
	my @a = (1,2);
	my @b = (3,4);
	my @c = (5,6);
	
	return(\@a,\@b,\@c);
}
This gives output:

code:
First is ARRAY(0x248d598) with values 5 6
First is ARRAY(0x2480218) with values 1 2
First, second ARRAY(0x248d400) ARRAY(0x248d418) with values 1 2 3 4
I would have expected the first line to print 1 2 instead of 5 6, so did I do something stupid here? Do I really have to set the second rval to undef if I'm not interested in it?

Anaconda Rifle
Mar 23, 2007

Yam Slacker

eXXon posted:

code:
use strict;

my $first = multi_array();
my @values = @$first;
print "First is " . $first . " with values @values\n";

($first,undef) = multi_array();
@values = @$first;
print "First is " . $first . " with values @values\n";

my $second;
($first,$second) = multi_array();
@values = @$first;
my @svalues = @$second;
print "First, second " . $first . " " . $second . " with values @values @svalues\n";

sub multi_array
{
	my @a = (1,2);
	my @b = (3,4);
	my @c = (5,6);
	
	return(\@a,\@b,\@c);
}
This gives output:

code:
First is ARRAY(0x248d598) with values 5 6
First is ARRAY(0x2480218) with values 1 2
First, second ARRAY(0x248d400) ARRAY(0x248d418) with values 1 2 3 4
I would have expected the first line to print 1 2 instead of 5 6, so did I do something stupid here? Do I really have to set the second rval to undef if I'm not interested in it?

code:
my $first = multi_array();
is being called in scalar context. In scalar context the comma operator evaluates the thing on the left, throws it away and moves right (http://perldoc.perl.org/perlop.html#Comma-Operator).

code:
($first,undef) = multi_array();
is being called in list context where it does what you expect it to do.

Precambrian Video Games
Aug 19, 2002



Oh, so it suffices to write my ($first) = multi_array();?

Anaconda Rifle
Mar 23, 2007

Yam Slacker

eXXon posted:

Oh, so it suffices to write my ($first) = multi_array();?

Yup. Try it out.

uG
Apr 23, 2003

by Ralp

eXXon posted:

code:
use strict;

my $first = multi_array();
my @values = @$first;
print "First is " . $first . " with values @values\n";

($first,undef) = multi_array();
@values = @$first;
print "First is " . $first . " with values @values\n";

my $second;
($first,$second) = multi_array();
@values = @$first;
my @svalues = @$second;
print "First, second " . $first . " " . $second . " with values @values @svalues\n";



sub multi_array
{
	my @a = (1,2);
	my @b = (3,4);
	my @c = (5,6);
	
	return(\@a,\@b,\@c);
}
This gives output:

code:
First is ARRAY(0x248d598) with values 5 6
First is ARRAY(0x2480218) with values 1 2
First, second ARRAY(0x248d400) ARRAY(0x248d418) with values 1 2 3 4
I would have expected the first line to print 1 2 instead of 5 6, so did I do something stupid here? Do I really have to set the second rval to undef if I'm not interested in it?

Here is a less redundant version of your code. It doesn't answer your (already answered) question but when you avoid doing redundant stuff and silly things like assigning values to undef things become easier to understand.

code:
use strict;
use warnings;

my $values = multi_array();

print "First is " . $values->[0] . " with values " . join(' ', @{$values->[0]}) . "\n";
print "Second is " . $values->[1] . " with values " . join(' ', @{$values->[1]}) . "\n";
print "First, second is " . $values->[0] . " " . $values->[1] . " with values " . join(' ', @{$values->[0]}) . " " . join(' ', @{$values->[1]}) . "\n";


1;


sub multi_array
{
	my @a = (1,2);
	my @b = (3,4);
	my @c = (5,6);
	
	return [\@a,\@b,\@c];
}

__END__

uG fucked around with this message at 18:53 on Sep 15, 2013

toadee
Aug 16, 2003

North American Turtle Boy Love Association

Anyone here have experience using the Perl Net::SNMP::Agent modules to write NetSNMP agent handlers?

I am having issues returning a table via an snmp walk. Essentially I want to reply to an SNMP query with some data I have in an MySQL db (about 250 rows with 15 values in each row).

So, the structure, from what I can gather from other tables of SNMP Data Ive compared to, should be like rootOID.ROW.VALUE, returned as all rows for value 0 first, then value 1 second, etc etc.

What happens is when I get the query in, the script returns rootOID.0.0 through rootOID.250.0, then sets the next OID to rootOID.0.1, yet the SNMPwalk never seems to continue.

Relevant code:

code:
sub snmp_handler {
    my ( $handler, $registration_info, $request_info, $requests ) = @_;
    my $request;
    my $row     = 0;
    my $val     = 0;
    my $rootOID = '1.3.6.1.4.1.8072.9999.9999.1111';
    my $nextoid;
 
    for ( $request = $requests ; $request ; $request = $request->next() ) {
        my $oid = $request->getOID();
        writeLog("Working OID $oid\n");
        my ( undef, undef, $rownew, $valnew ) =
          split( /\./, $oid );    #undefs are base OID and 1111 identifier
        $row = $rownew if $rownew =~ /\d/;
        $val = $valnew if $valnew =~ /\d/;
        if ( $request_info->getMode() == MODE_GET ) {
            writeLog("\tWorking GET request\n");
            writeLog("\tGET OID is $oid\n\tRow is $row\n\tVal is $val\n");
 
            my $value = $stats[ $row ]->[ $val ];
            writeLog("\tSetting value $value based on row $row and value $val\n");
            if ( $value =~ /\D/ ) {
                $request->setValue( ASN_OCTET_STR, $value );
 
            }
            else {
                $request->setValue( ASN_INTEGER, $value );
 
            }
        }
        elsif ( $request_info->getMode() == MODE_GETNEXT ) {
            $request->setRepeat(5); # just tried this to see if it had any effect on digging through more of the values, it didn't
            if ( ( $row <= $maxrow ) && ( $val <= $maxval ) ) {
                writeLog("Working GETNEXT request\n");
 
                my $value = $stats[$row]->[$val];
                writeLog("\tGot value $value for row $row, val $val\n");
                $row++;
                if ( $row > $maxrow ) {
                    $val++;
                    $row = 0;
                }
                $nextoid = $rootOID . '.' . $row . '.' . $val;
                writeLog("\tNext oid is $nextoid\n");
                $request->setOID( new NetSNMP::OID("$nextoid") );
                if ( $value =~ /./ ) {
                    if ( $value =~ /\D/ ) {
                        writeLog("\tValue $value is a string!\n");
                        $request->setValue( ASN_OCTET_STR, $value );
                    }
                    elsif ( $value =~ /\d+\.\d+\.\d+\.\d+$/ ) {
                        writeLog("\tValue $value is an IP!\n");
                        $request->setValue( ASN_IPADDRESS, $value );
                    }
                    elsif ( $value =~ /^[0-9]+$/ ) {
                        writeLog("\tValue $value is an Integer!\n");
                        $request->setValue( ASN_INTEGER, $value );
                    }
                    else {
                        writeLog("\tValue $value is something else!\n");
                        $request->setValue( ASN_OCTET_STR, $value );
                    }
                }
            }
        }
        elsif ( $request_info->getMode() == MODE_GETBULK ) {
            writeLog(
"OH BROTHER WE GOTS A BULK REQUEST BATTON DOWN THE HACHES AN SECURE YER BRITCHES\n"
            );
        }
        else {
            my $unknown = $request_info->getMode();
            writeLog("What in tarnation is a dang $unknown?\n");
        }
    }
}
The issue here may be more SNMP or NetSNMP specifically related than perl related, but I don't think there's an SNMP programming megathread.

Another option I have (and may need to go with), is that I can compile C modules into NetSNMP as custom handlers, and there is a whole bunch of stuff in the NetSNMP .h's pertaining to registering and delivering tables. Why those aren't in the Perl API I don't know but it looks like if I can manage to get out of my own way hacking together some C code it would be theoretically easier.

uG
Apr 23, 2003

by Ralp
Where does this 'walk' take place in the code? You are also using NetSNMP::Agent, not Net::SNMP::Agent or Net::SNMP from what I can see. What values can we pass to your function and what are the expected results?

toadee
Aug 16, 2003

North American Turtle Boy Love Association

The snmpwalk takes place externally, snmpwalk being a commandline utility to issue to a sever providing snmp responses.

The snmpwalk sends a GETNEXT request to an snmp server, the server replies with the next valid OID in a sequence based on that one, along with the value of the response for the OID the next request was sent for. An example:

I issue 'snmpwalk somesnmpserver 1.2.3'
SNMP server says 'ok, 1.2.3's first valid oid is 1.2.3.0.0, I will send the requestor the value of 1.2.3.0.0, and then let them know the next OID is 1.2.3.1.0', at which point the snmpwalker will send another GETNEXT request for 1.2.3.1.0, get a value for it along with the next valid OID in the sequence, and so on.

What is passed into the handler is from NetSNMP::Agent, which is $handler, $registration_info, $request_info, and $requests. What we're mainly dealing with is $request_info (an object containing things like what type of request this is, ie. a simple GET, a GETNEXT, GETBULK, etc), and $requests, an arrayref of request objects. The request objects contain the OID the requestor is asking for a value for, and then we also then modify these request objects with what we wish to return, the NetSNMP daemon running on the machine handles delivering that back to the requestor. We access that by just saying $request->setValue( TYPE, $value ), and we can set the nextOID in the case of a getnext request with $request->setOID( NetSNMP::OID object );

Anyhow, it's and odd and awkward thing to ask for help on here because aside from being sloppy, lazy and not as professional as others' code might be, it's doing what I am asking and intending it to do, and I think the problem lies in how I'm attempting to implement an SNMP table. I guess it was mainly on the hope that someone else here has used perl to do such an implementation via NetSNMP::Agent, because I have googled every combo of 'Perl Net::SNMP agent table' and related phrases I can think of and found NOTHING.

Also, the S in SNMP is the biggest loving joke of a lie ever.

uG
Apr 23, 2003

by Ralp
Have you looked at Net::SNMP?
http://search.cpan.org/~dtown/Net-SNMP-v6.0.1/lib/Net/SNMP.pm#get_table()_-_retrieve_a_table_from_the_remote_agent

I'm not familiar with SNMP at all, but I would be amazed if there isn't already something to do what you want.

http://cpansearch.perl.org/src/DTOWN/Net-SNMP-5.2.0/examples/table.pl

toadee
Aug 16, 2003

North American Turtle Boy Love Association

That's the reverse of what Im doing, Net::SNMP is used for making an SNMP request to an SNMP handler on a remote server, NetSNMP::Agent is for extending your server's SNMP implementation with a handler you write in Perl. The code I'm writing there is for answering SNMP requests sent to a daemon, not requesting SNMP info from a remote device.

homercles
Feb 14, 2010

I wrote a pure-perl SNMP agent a few years ago for regression testing at my job, boss gave the ok to sling some code your way. I use some Perl decoding code found in mrtg that seems to have fallen out from its official place on the internet, however. I'll send you a PM and maybe upload this stuff in a more formalised sense to CPAN.

Pollyanna
Mar 5, 2005

Milk's on them.


Okay, I really need some help understanding how regular expressions work.

I have this script: http://pastebin.com/Y0ZjfkD3

And it gets a string from a text file. It's a sequence of nucleotides. I'm trying to write some code that notifies the user if there are characters other than A, T, C, or G in the string (which there should be). I tried doing it like this:

Perl code:
                print "There are non-ATCG characters in the file." if ($data =~ /[^AGTC]/);
What this ends up doing is printing "There are non-ATCG characters in the file." over and over again for (I assume) each character in the string, when it should only be once. (This might make more sense if you look at the entire script.) Additionally, I have a problem where it says "Invalid file name." regardless of what I input, even if that file exists in the same directory as the script. What's going on here?

Do I understand how to use regex correctly? Or am I approaching this the wrong way?

Rohaq
Aug 11, 2006
The
Perl code:
while (<MYFILE>) 
loop isn't reading the entire file in one go, it's reading in line by line, here's an example using STDIN rather than a file handle to help you understand:

http://ideone.com/FdwtF1

I'd suggest using the following instead, including a handy basic line count so you can pinpoint the location, and I corrected uc(data) to uc($data):

Perl code:
my $line_num = 0;

while (<MYFILE>) {
        $line_num++;
        chomp;

        $data = "$_";
 
        # Now we got a big ol string.
 
        # Set this string to uppercase.
 
        $data = uc($data);
 
        # Check to see if non-ATCG characters are in the file.
 
        if ($data =~ /[^AGTC]/) {
                print "There are non-ATCG characters in the file on line number $line_num";
                last;
        }
 
        # Find the first occurrence of ATG.
}
EDIT:- Also, you can compress this down a little; you're reading a file in, so you should have a string already, I don't think you need to convert it into another variable, or uppercase it before the regex comparison:

Perl code:
my $line_num = 0;

while (<MYFILE>) {
    $line_num++;
    chomp;

    if ( uc($_) =~ /[^AGTC]/ ) {
        print "There are non-ATCG characters in the file on line number $line_num";
        last;
    }
}
Alternatively, just make the regex case-insensitive:
Perl code:
my $line_num = 0;

while (<MYFILE>) {
    $line_num++;
    chomp;

    if ( $_ =~ /[^AGTC]/i ) {
        print "There are non-ATCG characters in the file on line number $line_num";
        last;
    }
}

Rohaq fucked around with this message at 01:07 on Nov 13, 2013

Pollyanna
Mar 5, 2005

Milk's on them.


That's more or less what I'm trying to do, thanks. The whole thing about AGTC is that there's characters like N, n, *, and - in it. Anyway, adding last; makes the whole thing stop on the first line with non-AGTC characters. :shepface: Does Perl not have a "break" keyword or...?

Anaconda Rifle
Mar 23, 2007

Yam Slacker

Pollyanna posted:

That's more or less what I'm trying to do, thanks. The whole thing about AGTC is that there's characters like N, n, *, and - in it. Anyway, adding last; makes the whole thing stop on the first line with non-AGTC characters. :shepface: Does Perl not have a "break" keyword or...?

Break from what? The "last" shown to you by Rohaq will break from the loop. "exit" will break from the program.

Pollyanna
Mar 5, 2005

Milk's on them.


Anaconda Rifle posted:

Break from what? The "last" shown to you by Rohaq will break from the loop. "exit" will break from the program.

That's odd, cause with the "last;" there I get:

code:
Input name of file with file extension.
>ELv.fasta
There are non-ATCG characters in the file on line 1.
and that's where the program ends.

ephphatha
Dec 18, 2009




That's because it's finding a non-AGTC character on the first line, printing that warning message, then breaking out of the loop. Check the first line of your file, do you have any whitespace characters between sequences on the same line? Can you show us an example line and tell us which characters you expect to see and what an example of bad data is?

Edit: If your files are in fasta format then you need to ignore the first line as it contains a description of the sequence.

ephphatha fucked around with this message at 03:08 on Nov 13, 2013

Pollyanna
Mar 5, 2005

Milk's on them.


This is the typical structure of a FASTA file:

code:
>gi|5524211|gb|AAD44166.1| cytochrome b [Elephas maximus maximus]
LCLYTHIGRNIYYGSYLYSETWNTGIMLLLITMATAFMGYVLPWGQMSFWGATVITNLFSAIPYIGTNLV
EWIWGGFSVDKATLNRFFAFHFILPFTMVALAGVHLTFLHETGSNNPLGLTSDSDKIPFHPYYTIKDFLG
LLILILLLLLLALLSPDMLGDPDNHMPADPLNTPLHIKPEWYFLFAYAILRSVPNKLGGVLALFLSIVIL
GLMPFLHTSKHRSMMLRPLSQALFWTLTMDLLTLTWIGSQPVEYPYTIIGQMASILYFSIILAFLPIAGX
IENY
They're sequences of either nucleotides or amino acids. In my case, they're nucleotides.

Basically, what I want to do is eliminate the first line and join the rest together. From there, find the first occurrence of ATG and then from then on each three characters are considered a single unit called a "codon". (This is to prevent frame shifting.) These codons are then compared to a hash table for translation until any four of the "stop" codons are found, at which point the program prints the translation so far and terminates.

This should result in this:

code:
ggGGCTTgaAGAttGaTcTCCtCCcctGGGgccaAgGGGGacGCCAAACTtCGGAcGTAN
CCNNNcNCctGGGTACGCGGCNCAGCtGNNNGaCGctTNTTCGaGTgCCCCNNNNTTcAA
GCNNtAGgaAACGGGTCaaaaAGCCCNAAAAtcCGCgCGGGtTGCACGcaTCCAAGCAgA
GAaCTNCCCCCCCGTANNNNaNgggggNNNCtNNNNNNNGCgAATTCCcccgaTCACTAC
CCGCCaaaaaNGaGGANTcaTTAGCCCGGGCccccTAAcccctCaGGTAAGAAACtTttg
AAAAaNCCATTAACTTCCCCcCGAAAgATGgagTTGGTTatttcattgATTGTTgagtca
TGAgggNNNtTAgTCTTGGCGGcTCCCCCtNNNCACtGANNGTTTgCccCCtgCAcNCGA
AGAANgNggCGCNNcGGCgctcGTCcaTAAGGNCtttgTGCtcCCCAAccNaAGgaCgGg
CTTAttCAGAGagtccGGGGaaccccTTcgtGGataAAATaCTCCtAAAcCAANNAAaNN
aaCCNAGGtAccGCgGNNCAcATTNGGATTTCCTCgCGGGTgANGCNCCGTCAgACaGAC
AAccTTTACACaAccCaaCCGAgAAgggAAAAtAcCGTGtGTTTTtGTTTTgGGGNGNNN
NNNGgtCNNNcgGcCANNTAccAGgTCGCAcTTtGtttNcANGGNNNNNNNGTTTttTAA
ttCTTNNCTtTGAAG
becoming this:

code:
MELVISLIVES
I already know how to read a file and place it into a variable, and to find the first occurrence of "ATG" in a string. What I'm wondering is how to skip a line when reading a text file, how to join lines together, and how to insert a space after every three characters. If I know that, I should be able to finish the program.

ephphatha
Dec 18, 2009




The <> operator reads from the specified file until it finds a newline character (or EOF), returning everything it's read so far including the newline. So if you want to skip the first line, either call <MYFILE> before the while loop, or better yet check if the line starts with the '>' character (and if so skip it by calling 'next;') since all fasta files seem to use that as a marker.

The chomp command is needed because <> returns the line with the newline character on the end. Chomp drops the trailing newline from the provided string (if the string does not end with a newline it's a no-op), modifying the string in place.

At this point you can append the chomped line to another variable and let the loop run again, it'll fetch another line, drop the newline character, you append it to the same buffer variable, and repeat. At the end of the loop you will have a single line of text you can process.

You can then use the index function to find the first occurrence of the substring 'ATG' in the string, and use the return value from that function in the substr function to grab the remainder of the string.

You can then use split to break the string up into a list of 3 letter strings (by providing the pattern /[[:alpha:]]{3}/) and then feed the list into join with ' ' as the expression to end up with a single string with space delimited three letter sequences.

However, for your purposes you may not want to even join the list back into a single string at that point, it might be easier to iterate over the list and use each three letter sequence in your lookup.

ephphatha fucked around with this message at 01:02 on Nov 14, 2013

prefect
Sep 11, 2001

No one, Woodhouse.
No one.




Dead Man’s Band
Use File::Slurp if you want to suck up a whole file in one go. It simplifies things.

Pollyanna
Mar 5, 2005

Milk's on them.


Cool! Thanks guys, I'm almost done. There's one more question I have: how do I return the value of a hash? Like, in Python you would go translation = hash[string], but I don't see a version of that for Perl.

prefect
Sep 11, 2001

No one, Woodhouse.
No one.




Dead Man’s Band

Pollyanna posted:

Cool! Thanks guys, I'm almost done. There's one more question I have: how do I return the value of a hash? Like, in Python you would go translation = hash[string], but I don't see a version of that for Perl.

code:
$translation = $hash{$string};
Is that what you're looking for? It'll assign the value associated with the $string key to $translation.

Pollyanna
Mar 5, 2005

Milk's on them.


Dammit, that makes sense. :downs: Thanks.

Another problem: the "last" keyword doesn't work the way I think it does. In this snippet:

code:
	TRANSLATING: foreach $codon (@codonarray) {

			if ($codon =~ (/"TAG"/i || /"TAA"/i || /"TGA"/i)) {
				print $translation;
				last TRANSLATING;
			} else {
				$acid = $xlate::AAbyTLA{$xlate::DNAtoAA{uc($codon)}}[1];
				print "$acid\n";
				$translation .= $acid;
			}
		}
I want it to print $translation and then exit completely when it finds a codon that's TAG, TGA, or TAA. However, when I run this, it still prints the STOP codon and for some reason the codon right after that, and THEN dies. :confused: Why?

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
last() works fine, your logic just isn't sound and your use of regexes is just plain broken. Here's a version of the code that should work right. :)

code:
	my $translation;
	
	TRANSLATING: foreach $codon (@codonarray) {
			$acid = $xlate::AAbyTLA{$xlate::DNAtoAA{uc($codon)}}[1];
			print "$acid\n";
			$translation .= $acid;
			next if $codon !~ /"TAG"/i and $codon !~ /"TAA"/i and $codon !~ /"TGA"/i;

			print $translation;
			last TRANSLATING;
		}
I suspect the quotes may also be wrong. Also be aware that due to printing each $acid, and then the concatenation of all $acid contents in $translation, you'll get all your codons printed twice, once with linebreaks after each, once in a single block.

Lastly, you'd serve yourself well by downloading Modern Perl and giving it a read. It will only take you an evening: http://modernperlbooks.com/books/modern_perl/

After that you could also read some more stuff from http://perl-tutorial.org but reading Modern Perl is important.

Pollyanna
Mar 5, 2005

Milk's on them.


Mithaldu posted:

last() works fine, your logic just isn't sound and your use of regexes is just plain broken. Here's a version of the code that should work right. :)

code:
	my $translation;
	
	TRANSLATING: foreach $codon (@codonarray) {
			$acid = $xlate::AAbyTLA{$xlate::DNAtoAA{uc($codon)}}[1];
			print "$acid\n";
			$translation .= $acid;
			next if $codon !~ /"TAG"/i and $codon !~ /"TAA"/i and $codon !~ /"TGA"/i;

			print $translation;
			last TRANSLATING;
		}
I suspect the quotes may also be wrong. Also be aware that due to printing each $acid, and then the concatenation of all $acid contents in $translation, you'll get all your codons printed twice, once with linebreaks after each, once in a single block.

Lastly, you'd serve yourself well by downloading Modern Perl and giving it a read. It will only take you an evening: http://modernperlbooks.com/books/modern_perl/

After that you could also read some more stuff from http://perl-tutorial.org but reading Modern Perl is important.

Unfortunately, I don't think that works. The code continues to translate every acid past any of the stop codons and $translation never gets printed. I think the next if statement prevents the last two lines in TRANSLATING from executing if a stop codon is found. What is it supposed to do? If it's supposed to move onto the next codon, then I think the regex is incorrect somehow.

Also, what do you mean by my quotes being wrong?

I'll read Modern Perl tonight, thanks. This'll make learning the language less of a headache.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

Pollyanna posted:

Also, what do you mean by my quotes being wrong?

The quotes inside the regexes. They should only be there if there are quotes in the strings in @codonarray.

Also, to make this easier, can you describe your stop condition in english?

Rohaq
Aug 11, 2006

prefect posted:

Use File::Slurp if you want to suck up a whole file in one go. It simplifies things.
Wouldn't File::Slurp read the entire file into memory? That's great if you've got small files, but when it comes to large files, you could run into some issues if you end up filling large amounts of memory with something you could iterate over line by line, which it sounds like something that suits Pollyanna's needs without a problem.

Pollyanna
Mar 5, 2005

Milk's on them.


Mithaldu posted:

The quotes inside the regexes. They should only be there if there are quotes in the strings in @codonarray.

Also, to make this easier, can you describe your stop condition in english?

:downs: That was it. It works perfectly now, thanks! How come sometimes regexes need quotes and sometimes they don't?

Rohaq
Aug 11, 2006

Pollyanna posted:

:downs: That was it. It works perfectly now, thanks! How come sometimes regexes need quotes and sometimes they don't?
Regexes don't need quotes, unless you're matching quotes. The quote character has no special significance in regex.

It is worth mentioning that you can use numerous surrounding characters after '=~' to denote your regex. Maybe you say code using something like the following:

Perl code:
if ( $foo =~ "bar" )
Which is syntactically valid; sometimes you might want to use alternative characters to / if say, your regex includes forward slashes to prevent yourself having to escape them using backslash.

Most people use forward slashes though, and most IDE editors recognise it for syntax highlighting.

Here's an example, along with some handy tips for using single/double quotes:
Link: http://ideone.com/Bw920G

Perl code:
#!/usr/bin/perl

my $string = "bl/ah";

# Traditional '/'s: Without the backslash below to escape the forward slash,
# we'll get a runtime error.
print "1\n" if ( $string =~ /bl\/ah/ );

# These work just fine, however.
print "2\n" if ( $string =~ "bl/ah" );

# Note that by using 'm' (match) before the regex, you can use virtually any
# character/brace as a surrounding characters. Without the 'm', you'd hit a
# runtime error in the two matches below:
print "3\n" if ( $string =~ m;bl/ah; );
print "4\n" if ( $string =~ m{bl/ah} );

# There is also a similar thing for single and double quotes, like the below:
# qq is the double quote (") equivalent:
print qq/test\n/;
# q is the single quote (') equivalent.
print q/test\n/;

# Note that \n isn't processed as a new line in single quotes. This is because
# double quotes in perl will process any special characters and variable names
# in the text (so you can include variables inline), and single quotes do not
# for example:
print "\nThe value of \$string in:\n";	# Note the backslash escaped \$
print "Double quotes: $string\n";
print 'Single quotes: $string';

Rohaq fucked around with this message at 21:50 on Nov 13, 2013

Pollyanna
Mar 5, 2005

Milk's on them.


:psyduck: This is confusing as gently caress. At least I don't have to go \/\/\/\/\/\/\/\/\/\/\/ all the time.

Another regex question. I'm trying to find instances of one character being repeated at least 6 times. For this I have:

code:
$regexg = /G{6,}/i;
$regexc = /C{6,}/i;
...but it doesn't find any even if they're there. How come? It's for a match of any character G or C repeated six or more times, case-insensitive, right?

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Pollyanna posted:

:psyduck: This is confusing as gently caress. At least I don't have to go \/\/\/\/\/\/\/\/\/\/\/ all the time.

Another regex question. I'm trying to find instances of one character being repeated at least 6 times. For this I have:

code:
$regexg = /G{6,}/i;
$regexc = /C{6,}/i;
...but it doesn't find any even if they're there. How come? It's for a match of any character G or C repeated six or more times, case-insensitive, right?

http://codepad.org/3N36zS2R

Pollyanna
Mar 5, 2005

Milk's on them.



gently caress :negative: I'm right and the drat program still doesn't work.

Here's what I have right now:

Perl code:
use lib "/path/to/module.pm";
use xlate;

$infilename = "";
$infilename = $ARGV[0] if (scalar(@ARGV) > 0);

while (1) {
	last if ($infilename && -e $infilename);
	print "Sequence file name: ";
	$infilename = <STDIN>;
	chomp $infilename; 
}

open (MYFILE, "< $infilename");

$line_num = 0;

while (<MYFILE>) {
	$line_num++;
}

# How many lines have a stretch of at least 6 Gs in a row AND a stretch of at least six Cs in a row?

$counter1 = 0;

$regexg = /G{6,}/i;
$regexc = /C{6,}/i;

foreach $line (<MYFILE>) {
	if (($line =~ $regexg) && ($line =~ $regexc)) {
		$counter1++;
	}
}
For each line in the file I opened, if that line has 6 or more Gs AND if that line has 6 or more Cs, then add one to the counter. Is that logical?

edit: Aw, dangit. That "qr" thing needs to be there for this to work. Why?

Pollyanna fucked around with this message at 23:19 on Nov 13, 2013

Adbot
ADBOT LOVES YOU

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
Wow. I'd strongly suggest you read that book before doing anything else. Whereever you've been learning Perl, it's been teaching you in the worst possible way. :(

  • Locked thread