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
thehandtruck
Mar 5, 2006

the thing about the jews is,
Wow thank you, I've been working on this for a month.

Adbot
ADBOT LOVES YOU

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
^ and its counterpart $ are pretty basic regular expressions special characters; if you don't know them, it's probably because you never got a good introduction to perl (autodidacts in any field tend to have gaps in their knowledge). The canonical way to learn perl is via either the book Programming Perl (the 'Camel book') or Learning Perl (the 'llama book'). If you want something online, you could do worse than A Beginner's Introduction to Perl 5.10, or perldoc. Perldoc is way useful for more in-depth topics as well; for example, here's a regular expressions tutorial in perldoc. There are a couple other bits of perlish syntactic sugar in the code I wrote, but you'll pick that up pretty quickly as you progress.

unnoticed
Nov 29, 2005

That's odd...
Figured I'd move this to here instead of a separate thread:

I'm working on a perl script that will end up putting about 500000 entries into a hash. Any perl coders out there know if there's a maximum that I'll be hitting or anything like that? I couldn't find much info on the algorithm that perl uses.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
You won't find a maximum aside from your RAM. I'd honestly suggest doing this with a database, MySQL or SQLite, instead of a hash.

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
^^^^ That's a good idea, and take a look at tie() in perldoc while you're at it


Generally perl lacks static limits and you can keep on truckin til malloc fails

I believe recent perl still uses this hash function

Blotto Skorzany fucked around with this message at 00:14 on Dec 22, 2009

unnoticed
Nov 29, 2005

That's odd...

Mithaldu posted:

You won't find a maximum aside from your RAM. I'd honestly suggest doing this with a database, MySQL or SQLite, instead of a hash.

Ok thanks. Yeah, I know it's gonna be pretty slow, but it's just a rarely used script for parsing certain parameters of a log file and doing some processing and comparisons.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
Does anyone have any experience using perl with emacs? I was recommended the cperl mode, but being fairly new to emacs, I have no idea how to set that up. All I know is something about the Init file which I don't know how to find.

Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?
Any HTML::FormHandler users around? I've got a form which is comprised of a few sub-forms which are pulled in with Moose's extends() function, and I need to make some values readonly at run-time, but the readonly() attribute for a field is => 'ro' so it blows up when passed a value, and my Moose-fu isn't yet strong enough to switch an attribute to is => 'rw' by tweaking the field's meta-class (from looking at the source for Moose::Meta::Attribute I'm not sure it's even possible).

Edit: Solved by nasty hacks.

Mario Incandenza fucked around with this message at 13:11 on Jan 6, 2010

Fenderbender
Oct 10, 2003

You have the right to remain silent.
On that note, how would I go about altering the delagations (handles) for an attribute. My idea is to call the fields method on a Rose::DB::Object subclass and then push that all to a specific attribute's delegations. Haven't been able to figure out how to do this yet but it will solve a lot of upcoming issues I'm going to have to slave over if I don't do this now.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
Well I figured out the emacs nonsense. But now I a little confused about the right way to go about what I'm trying to do. I realize that this is all pretty basic, but I'm pretty new with perl and, until now, haven't really been using it for what I'm supposed to (I'm just now getting something to do the deals with text).

I have to read in a text file, grab some numbers out, and transplant them into another one. I know it should be simple, but I just have a few questions.

First, can I just open the filehandle and immediately start scanning through it with index? If not, how do I turn it into a readable string, or do I even want to do that?

I'm also a little unsure about how to go about grabbing the data. I assume once I've indexed to where I want to be I can just use regular expressions to grab what I want, but I'll see when I get there.

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
code:
open my $in, '<', 'in.txt' or die $!;     #open for reading; note error handling;
                                          #$! is analagous to strerror(errno) in C
for my $line (<$in>) {                    #read line at a time
                 #do stuff
}
open(my $out, '>', 'out.txt') or die $!;  #writing; note optional parens for clarity
print $out $stuff_to_output;              #write to output file
or
code:
use File::Slurp;
my $whole_file = read_file('in.txt');  #note file::slurp handles errors for you, dying on error by default
#do stuff
write_file('out.txt', $output);        #write_file() can also take array or arrayref as second arg
or
code:
#invoke as ./your_program.pl input_file_1 input_file_2...
open my $out, '>', 'out.txt' or die $!;
while (<>) {                            #diamond operator without arg takes command line arguments
                                        #as input files and scans over them in order line by line;
                                        #if no command line args are present, it reads from stdin
                                        #this can be Very Useful
    #do stuff, noting $_ holds contents of current line
}
print $out $stuff_to_output;

Perl has even more handy stuff to do with reading and writing files, but these basics should tide you over for what you want to do. Both the camel book and the llama book give an excellent foundation for this sort of basic poo poo, with the latter assuming less unix knowledge. http://perldoc.perl.org is a good online reference as well, and http://search.cpan.org/ is indispensable; I've been told http://learn.perl.org has links to some good tutorials as well.

Blotto Skorzany fucked around with this message at 20:28 on Jan 7, 2010

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Otto Skorzeny posted:

code:
open my $in, '<', 'in.txt' or die $!;     #open for reading; note error handling;
                                          #$! is analagous to strerror(errno) in C
for my $line (<$in>) {                    #read line at a time
                 #do stuff
}
open(my $out, '>', 'out.txt') or die $!;  #writing; note optional parens for clarity
print $out $stuff_to_output;              #write to output file
or
code:
use File::Slurp;
my $whole_file = read_file('in.txt');  #note file::slurp handles errors for you, dying on error by default
#do stuff
write_file('out.txt', $output);        #write_file() can also take array or arrayref as second arg
or
code:
#invoke as ./your_program.pl input_file_1 input_file_2...
open my $out, '>', 'out.txt' or die $!;
while (<>) {                            #diamond operator without arg takes command line arguments
                                        #as input files and scans over them in order line by line;
                                        #if no command line args are present, it reads from stdin
                                        #this can be Very Useful
    #do stuff, noting $_ holds contents of current line
}
print $out $stuff_to_output;

Perl has even more handy stuff to do with reading and writing files, but these basics should tide you over for what you want to do. Both the camel book and the llama book give an excellent foundation for this sort of basic poo poo, with the latter assuming less unix knowledge. http://perldoc.perl.org is a good online reference as well, and http://search.cpan.org/ is indispensable; I've been told http://learn.perl.org has links to some good tutorials as well.

Great! thanks!

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
How would you deal with an input file that's split up into several different parts, most of which I don't need, if I'm reading in the file line by line? I was planning on setting up a hash of different flags that would tell what I was trying to do at that particular point, and having the reading loop just be a bunch of if-statements about what to do if the flags are set up a certain way. Does that seem too convoluted or is there maybe a better way of doing that?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Maybe the flip flop operator can do what you want.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Triple Tech posted:

Maybe the flip flop operator can do what you want.

I didn't even think about doing something like that but it seems like to could definitely help out.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

Triple Tech posted:

Maybe the flip flop operator can do what you want.

Whoa. I only just now understood why it's called flip flop. Thanks for the link.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Triple Tech posted:

Maybe the flip flop operator can do what you want.

Quick question, does this work for any conditionals, or just regular expressions?

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
Any time it's being evaluated in a scalar context

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Otto Skorzeny posted:

Any time it's being evaluated in a scalar context

so does
code:
for ($i = 1; $i <= 10; $i++) {
	if(($i>2)..($i<7)){
		print "$i\n";
	}
}
do what I think it does?

Vanadium
Jan 8, 2005

No. Are you looking for if(($i==3)..($i==6))?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?

Captain Frigate posted:

so does [mah codez] do what I think it does?

No. You usually flip flop between boundaries (like $i == 2 or /START/). If you run your code, you print everything from 3 up.

Why: The code fails until it hits three. At which point it satisfies and flips to the second condition. Code up until that condition is true, it's less than seven. Then, when you hit seven, that second expression is false, so it flops back to the first. But wait, every high number is always greater than 2. So it prints the rest.

You want hard boundaries like Vanadium posted.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Vanadium posted:

No. Are you looking for if(($i==3)..($i==6))?

Hm. Trying that for some reason causes an infinite loop or something. It just keeps printing sixes.

EDIT: Ok, it looks like it skips the rest of the numbers as well. It goes straight to six and just stays there.
EDIT 2: Well, I did some fiddling around. This is what I'm getting, and it doesn't make a whole lot of sense to me.

code:
if statement:                                  result:
if(($i=3) .. ($i=6))                           6 repeating    
if(($i>3) .. ($i=6))                           6 repeating
if(($i<3) .. ($i=6))                           6
if(($i=3) .. ($i<6))                           3 repeating
if(($i=3) .. ($i>6))                           3456 repeating
if(($i<3) .. ($i>6))                           1234567
if(($i>3) .. ($i>6))                           45678910
if(($i>3) .. ($i<6))                           45678910
if(($i<3) .. ($i<6))                           12
I don't think I really understand what's going on here.

Captain Frigate fucked around with this message at 17:45 on Jan 8, 2010

Vanadium
Jan 8, 2005

Captain Frigate posted:

I don't think I really understand what's going on here.

Me either. This worked for me, as in it printed 3, 4, 5, 6:

code:
for (my $i = 1; $i <= 10; $i++) {
	if(($i==3)..($i==6)) {
		print "$i\n";
	}
}

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Vanadium posted:

Me either. This worked for me, as in it printed 3, 4, 5, 6:

code:
for (my $i = 1; $i <= 10; $i++) {
	if(($i==3)..($i==6)) {
		print "$i\n";
	}
}

Wow, this is why I try and avoid coding. The reason it was repeating was because I was assigning values in the if statements with "=" instead of checking them...

Captain Frigate fucked around with this message at 18:04 on Jan 8, 2010

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
So here's my final chart (probably mostly for my own reference, but it might help someone else too)
code:
if statement:                                  result:
if(($i==3) .. ($i==6))                         3456    
if(($i>3) .. ($i==6))                          45678910
if(($i<3) .. ($i=6))                           123456
if(($i=3) .. ($i<6))                           3
if(($i=3) .. ($i>6))                           34567
if(($i<3) .. ($i>6))                           1234567
if(($i>3) .. ($i>6))                           45678910
if(($i>3) .. ($i<6))                           45678910
if(($i<3) .. ($i<6))                           12

Erasmus Darwin
Mar 6, 2001
Or to abstract the chart a bit:

pre:
$res = $x .. $y;

(state) starts false and represents the internal hidden state of the .. operator.

* - Either True or False.

$x | $y | (state) || $res | (new state)
---------------------------------------
 F |  * |    F    ||   F  |     F       <-- Pre-Flip or post-Flop
 F |  F |    T    ||   T  |     T       <-- Post-Flip and pre-Flop
 T |  F |    *    ||   T  |     T       <-- Flip
 * |  T |    T    ||   T  |     F       <-- Flop
 T |  T |    F    ||   T  |     F       <-- Immediate Flip-Flop

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
Ok now I have a question about regular expression matching variables. I'm sorry to be filling the thread with my poo poo, but I can't seem to find any good explanation in the books that I have. Lets say I have:
code:
for my $line (<$input>){
     if(($line =~ /regex_1/) .. ($line =~ /regex_2/)){
          if($line =~ /(\d)(\.)(\d)/){  #for example
               #do something
          }
     }
}
and regex_1 and regex_2 have parenthetical groupings in either or both of them, to what do my matching variables ($1, $2, etc) refer? Does it depend on the block, the most recent one matched, or something else?

slipped
Jul 12, 2001
regex vars always refer to the most recent regex computed

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
Guess the context!
code:
open my $__outfh, '>', \my $__output;
select $__outfh;
my $__input = do {local $/; <DATA>};
my @__results = eval {
        3 * 4 /5
};
select STDOUT;
print $__output || "@__results";
__DATA__

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
Another quick, stupid question. This time about filehandles (at least that's what I think I'm doing wrong).

Lets say I want to print out all of the lines of a script after a certain number of lines, so I try something like this:
code:
chdir "C:\Documents and Setings\user\My Documents\scripts";
open my $infile, "<test.pl"
	or die "no good: $!\n";

$i = 0;

for my $line (<$infile>){
	if($i < 190){
		next;
	}else{
		print $line;
		
	}
	print $i;
	$i++;
}
I try that, and get no output. Please excuse the sloppy loop, this is just something I threw together to test something. The fact that I get no output at all says to me that the loop isn't even starting, which I think is really odd and makes me think I did something wrong when I opened the file.

Vanadium
Jan 8, 2005

You ought to increment $i when it is below 190. I am guessing you misunderstand next.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Vanadium posted:

You ought to increment $i when it is below 190. I am guessing you misunderstand next.

Ah, good! That makes sense to me so far. I moved the $i++ to inside the first if statement and it worked fine. But how about this thing:
code:
chdir "C:\Documents and Setings\user\My Documents\scripts";
open ($outfile, '>', "new.txt")
	or die "no good: $!\n";

$i = 0;

for my $line (<$outfile>){
	if($i<100){
		print $outfile $i;
		$i++;
	}else{
		die "done: $!\n";
	}
}
It will create the output file, but leave it empty. Is this a similar looping issue, or is there something else I'm doing wrong?

EDIT: Or is this because it's a new file, and therefore empty, causing a "false" value in the (<$outfile) statement?

EDIT2: Ok, I'm pretty sure that's what was causing the problem because I made it into a normal for loop:
code:
for ($i = 1; $i <= 100; $i++) {
	print $outfile $i . "\n";
}
and it worked properly.

Captain Frigate fucked around with this message at 20:43 on Jan 12, 2010

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
You're doing well, checking for errors on the open() and using lexical filehandles. I'd suggest 1) checking that chdir() isn't failing:
code:
chdir '/path/to/dir' 
    or die "chdir failed: $!";
and 2)whipping up something super simple like
code:
open my $infile, '<', '/path/to/file' 
    or die "can't open: $!";
print for <$infile>
to eliminate any possibilities that something other than reading the file is the problem. With that said, there are a couple of things can simplify what you're doing here a little bit (doesn't seem like much in a trivial example, but every bit of effort shaved is nice when you're trying to do something more complex):
  1. One of Perl's special variables is $.    the current line number of the last filehandle accessed, meaning you don't have to keep track of it manually
  2. print, if supplied with no arguments, will default to printing $_ the default variable for most of Perl's builtin functions and the most used of perl's special variables
  3. $_ holds the contents of the current element in a for loop if no name is given

So overall, you could write something like
code:
chdir 'C:\Documents and Setings\user\My Documents\scripts'
    or die "Couldn't chdir: $!";
open my $infile, '<', 'test.pl'
    or die "Couldn't open: $!";

for (<$infile>) {
    print if $. > 190;
    print $.;
}
e: sort of beaten but enough folks don't know about $. that they keep track of lines themselves when perl's already doing it for them that I'll leave it up

CanSpice
Jan 12, 2002

GO CANUCKS GO

Captain Frigate posted:

Ah, good! That makes sense to me so far. I moved the $i++ to inside the first if statement and it worked fine. But how about this thing:
code:
chdir "C:\Documents and Setings\user\My Documents\scripts";
open ($outfile, '>', "new.txt")
	or die "no good: $!\n";

$i = 0;

for my $line (<$outfile>){
	if($i<100){
		print $outfile $i;
		$i++;
	}else{
		die "done: $!\n";
	}
}
It will create the output file, but leave it empty. Is this a similar looping issue, or is there something else I'm doing wrong?

What is <$outfile>? That's your first problem. You've opened a filehandle for write, and then <$outfile> is trying to read it, but since that file is empty it just bombs out of the for loop right away and your output file stays empty. I think you need two filehandles, one for the output file (which is what you've already done) and one for input.

When you're a beginner, mucking around with files in-place is a very good way to delete or corrupt your files. Read from one, write to a second:
code:
open my $infh, '<', "input.txt";
open my $outfh, '>', "output.txt";
my $i = 0;
while my $line ( <$infh> ) {
  print $outfh "$i\n";
  $i++;
  last if $i > 100;
}
close $outfh;
close $infh;
Edit: and of course do proper error checking on those opens and closes.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
Neat! I didn't know about the $. That could actually come in handy!

welcome to hell
Jun 9, 2006
You almost never want to do
code:
for (<$fh>) {
    ...
}
It results in the entire file getting read into an array, then that array getting iterated over. Instead, you usually should do
code:
while (<$fh>) {
    ...
}
which will read the file one line at a time. Pretty much nothing else in your code would have to change. In addition to using less memory, the special variable $. won't work correctly in the first case, because the entire file has already been read by the time it is used.

Also, CanSpice slightly messed up the syntax when converting the for to a while. You would want
code:
open my $infh, '<', "input.txt";
open my $outfh, '>', "output.txt";
my $i = 0;
while ( my $line = <$infh> ) {
  print $outfh "$i\n";
  $i++;
  last if $i > 100;
}
close $outfh;
close $infh;

CanSpice
Jan 12, 2002

GO CANUCKS GO

Captain Frigate posted:

Neat! I didn't know about the $.
Which is probably why you shouldn't use it: not enough people know about it. If I have to go to my Programming Perl book to figure out what a special variable is for, I won't use it. If absolutely necessary, you should use the English module (put 'use English;' at the top of your program) and then you can call $. $INPUT_LINE_NUMBER instead, which is a little clearer.

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
Another smallish question: is there any simple way of converting numbers in strings to integers? Lets say I read in some number as a string and want to add some some number and output the result as a string. How would I go about doing this, if they are all integers?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
At a really high level, there aren't really types with scalars. (internally, there is, but that's not what we're talking about)

code:
# integer'ed string
my $a = "5";

# string plus integer
$a += 1;

# strung integer
say "I love $a types of beef.";

Adbot
ADBOT LOVES YOU

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Triple Tech posted:

At a really high level, there aren't really types with scalars. (internally, there is, but that's not what we're talking about)

code:
# integer'ed string
my $a = "5";

# string plus integer
$a += 1;

# strung integer
say "I love $a types of beef.";

:doh: This is really something I should have remembered.

  • Locked thread