350 likes | 427 Views
Simple Databases. DBM Files and DBM Hashes. Every system that runs perl has some form of simple DB capacity A DBM file is a flat file database Implementations can differ between architectures. Limit of 1000 bytes per item Only limit to number of items is disk space. Opening a DBM Hash.
E N D
DBM Files and DBM Hashes • Every system that runs perl has some form of simple DB capacity • A DBM file is a flat file database • Implementations can differ between architectures. • Limit of 1000 bytes per item • Only limit to number of items is disk space
Opening a DBM Hash • We work with DBM files using a DBM Hash • To open a DBM Hash: dbmopen(%DATA, “my_database”, 0644); or die “Can’t create $!”; • Returns true if the database could be opened/created and false otherwise.
Closing a DBM Hash • Traditionally the DBM Hash is terminated with the program. • Otherwise: dbmclose(%DATA);
Using a DBM Hash • Works just like other hashes, except its stored on disk: $DATA{“fred”} = “bedrock”; delete $DATA{“barney”}; foreach my $key(keys %DATA) { print “$key has value $DATA{$key}\n”; }
Using a DBM hash cont… while(my($key, $value)=each(%DATA)) { print “$key has value of $value\n”; }
DBM Files and C • If you’re using a DBM file that will also be maintained by C programs, you need to be aware of trailing NUL (\0) chars on strings. my $value = $ALI{“merlyn\0”}; my $value =~ s/\0$//;
Manipulating Data with pack • Usually we want to store more than one item of data per key • - Pack will take a format string, and a list of arguments, and packs them into one string • c - char - 1 byte • s - short - 2 bytes • l - long - 4 bytes
Pack Cont… my $buffer=pack(“csl”, 31, 4159, 265359); my ($c, $s, $l) = unpack (“c s l”, $buffer); • White space is used to improve readability • Can follow a format with a number to indicate repetition: “cccccc” is the same as “c6” “c*” - pack each remaining arg into c
Fixed Length Random Access Databases • Fixed length means each record is the same length • Consider storing information about bowlers. Each record stores players name, age, last 3 scores and timestamp of last game. • “a40 C i5 L” • If reading the whole database, read chunks of data 55 bytes long until eof. If you want 5th record, skip 4x55 bytes.
Fixed Length Random Access Databases • In order to use these will need to learn: • opening a disk file for reading and writing • move around in file to an arbitrary position • fetch data by length rather than newline • Write data in fixed length blocks
Opening for Reading and Writing • The open function has an additional mode: open (FRED, “<fred”); open (FRED, “+<fred”); also open (WILMA, “>wilma”); open (WILMA, “+>wilma”);
Seek • seek (FRED, 55*$n, 0)
IO for Fixed Length DB my $buf my $number_read = read(FRED, $buf, 55); my ($name, $age, $s1, $s2, $s3, $when) = unpack “a40 c i3 l”, $buf); print FRED pack (“a40 c i3 l”, $name, $age, $newscore, $s1, $s2, $time)
Length of packed string my $pack_length = length pack ($pack_format”, “data”, 0, 1, 2);
Variable Length (Text) Databases • Often simple databases are just text files written a way that allows a program to maintain them. • Editing such files in place can be difficult. • Imagine a set of files, each with key: value pairs, and we need to alter several pairs in every file:
Example, Editing in Place fred03.dat Program Name: granite Author: Gilbert Bates Phone: +12 345 6789 • Say we want to change the name, and remove the phone number:
Example, Editing in Place @ARGV = glob “fred*.dat” or die “error”; $^I = “.bak”; while (<>){ s/^Author:.*/Author: Alison Smith/; s/^Phone:.*\n//; print; }
Perl Command Line Options perl -p -i.bak -w -e ‘s/Randall/Randal/g’ fred*.dat -p tells perl to write a program: while (<>) { print; } -e “executable code follows”
The Expanded Code #!/usr/bin/perl -w @ARGV = glob ”fred*.dat”; $^I = “.bak”; while (<>) { s/Randall/Randal/g; print; }
Trapping Errors with Eval • Sometimes ordinary code can create fatal errors: $barney = $fred / $dino print “match\n” if (/^$wilma/) open CAVEMAN, $fred or die “$!”;
Trapping errors with eval eval {$barney = $fred/$dino }; • If $dino is 0, it will crash the eval block, but not the program • Check the return of eval with $@
Trapping Errors with Eval foreach my $person (qw/ fred wilma betty /) { eval { open FILE, “<$person” or die “$!”; my ($total, $count); while (<FILE>) { $total += $_; $count++; } my $average = $total/$count; }; if ($@) { print “Error occurred $@”; } }
Eval Return Value • Like a subroutine, eval will return last expr evaluated. Err - undef or empty list • There are 4 kinds of error it can’t trap: • Anything that crashes perl itself • Syntax Error • Exit operator • Warnings
Picking Items from a List with Grep my @odd_numbers; foreach (1..1000) { push @odd_numbers, $_ if $_ %2; } OR my @odd_nums = grep {$_ % 2} 1..1000;
Grep my @matching_lines = grep {/\bfred\b/i} <FILE>; OR my @matching_lines = grep /\bfred\b/i, <FILE>;
Transforming Items from a list without map: my @data = (4.75, 1.5, 2, 1234, 6.9456, 12345678.9, 29.95); my @formatted_data; foreach (@data) { push @formatted_data, &big_money{$_); }
Transforming items from a list, with map my @formatted_data = map { &big_money($_) } @data; print “The prices are\n”, map {sprintf(“%25s\n”, $_) } @formatted_data;
A simple map • If you’re mapping with a simple expression rather than a whole code block: print “powers of 2:\n”, map “\t” . (2 ** $_). “\n”, 0..15;
Unquoted Hash Keys • Sometimes you don’t need the quote marks on hashes. • If the key is a bareword: $score{fred} • When using the big arrow my %score = ( barney => 195, fred => 205 };
More Powerful Regular Expressions • Non Greedy Quantifiers: The four quantifiers we’ve looked at so far, are greedy, they will match as much as they possibly can: /fred.+barney/ $_ = “fred and barney went bowling last night”
Non-greedy quantifiers • Fore every greedy quantifier, there is a non-greedy one. $text1 = I’m talking about Fred and <BOLD>Wilma</BOLD>! $text2 = No, <BOLD>Wilma</BOLD>, not <BOLD>Velma</BOLD>! s#<BOLD>(.*?)</BOLD>#$1#g
Matching Multiple Line Text • RE usually work with single lines $_=“I’m mubh better\nthanBarney is\nat bowling,\nWilma\n” • When using the m option, ^ and $ will now match internal new lines. print “Found’wilma’ at start of line\n” if /^wilma\b/im;
Matching Multiple Lines of Text • Similarly, you can do a substitution on each line: open FILE, $filename or die ”$!”; my $lines = join ‘’, <FILE>; $lines =~ s/^/$filename: /gm