Brandon's Notepad

June 5, 2015

Playing WAV Files In PERL

Filed under: Perl,Programming — Brandon @ 3:42 pm
Tags: , , , , ,

Home > My Lists > Programming Notes > PERL > Playing WAV Files In PERL


I don’t remember why exactly, but a few years ago I wrote a countdown timer that would sound a chime when it reached zero. I decided to keep the code that plays the sound for future reference. Note, this works using ActiveState PERL on Windows.



use Win32::Sound;

$wav = 'C:\path\to\file.wav';

Win32::Sound::Play($wav);


Advertisements

June 10, 2013

Interactive PERL Shell Environment

Home > My Lists > Programming Notes > PERL > Interactive PERL Shell Environment


Our first family computer was the IBM PCjr, and as i recall, we had two boot options: DOS 2.1 on 5.25″ floppy or BASIC A on cartridge. That’s right, depending on what we needed to do, we could use BASIC as an operating system, more or less. Bill Joy’s C shell (csh) was written to resemble the C programming language and can be used interactively or as a script interpreter. In more modern times, Python too can be run in either mode. Since I program a lot in PERL, it sure would be nice to have the ability to “live” inside a program, especially for debugging and testing purposes.


The Basis

Actually, it is quite possible to run PERL in an interactive mode. Consider the basic two-liner below that I picked up here from Asim Jalis of MetaProse:

#!/usr/bin/env perl
do{print("perl> ");$_x=<>;chomp $_x;print(eval($_x)."\n")}while($_x ne "q")

In a loop, this program presents a prompt, accepts input, strips off the newline at the end, and then executes (evaluates) the code block, that is until it encounters an input string consisting simply of ‘q’.

I reluctantly included the word ‘shell‘ in the title of this post, since this PERL environment isn’t really a user-interface between the user and the OS kernel, but it does resemble what most of us think of when we hear the word in this context. Moreover, this should not be confused with the Perl Shell, psh.

Of course, I can’t be satisfied with the bare minimum. There are a few bells and whistles I’d like to have. To make room for some additions, I expanded the script as follows:

  1. #!usr/bin/env perl
  2. do {
  3.    print("perl> ");
  4.    $_x=<>;
  5.    chomp $_x;
  6.    print(eval($_x)."\n")
  7. } while($_x ne "q")

Customizations

Recreating History. It’s always helpful to have a listing of the last actions performed. Unix shells usually include two methods for recalling and re-executing commands with or without editing. The first is the use of the up and down arrow keys to cycle through previous commands. This is the same functionality provided by the old DOSKEY command in DOS, which was later built into the command prompt in Windows. While this is a really cool feature, the programming is a bit involved for me to tackle at this time; besides, it would be a wasted effort since running this interactive environment in ActivePERL on Windows (where I actually do the majority of my scripting) magically makes this feature available. I’ve tried this in bash and ksh (set -o vi) on Linux but it did not work.

The second is a ‘history‘ command that simply lists the previous n commands on the screen. The list is usually numbered and a command can be re-executed by typing !n, where n is the line number of the desired command. I doubt I will get that fancy, but I would like to implement a basic history command.

Lazy Line Endings. I thought it might be nice to eliminate the need to end each line in a semicolon, just to make the environment more user-friendly. This too proved to be unnecessary, as the eval() command makes the semicolon optional by default (unless, of course, if multiple lines of code are being stacked end-to-end on the same command line).

I will update the section with more ideas and implementations as they come to pass.


January 30, 2012

Getting Google Maps

Filed under: How-To,Online Tools,Perl,Programming — Brandon @ 4:08 pm
Tags: , , , , , , , , ,

So, I’d like to have a current traffic map delivered to my e-mail at the precise moment I’m leaving work for the day. Call me lazy, but this is the sort of thing that can be automated pretty easily and I don’t want to go look it up, I want it delivered. Someday, I’ll get around to setting this up, but as they say, a journey begins with a single step. In this case, the step is to find a way a good to download Google Maps with a script. For now, that is the scope of this post.


Here’s some initial research to plow through:
Mapki: Google Map Parameters Best reference so far!
Google Static Maps API*
A PERL/Wget solution
A Python script
MapTileCacher in PERL
In Bash
Discussion on Google blocking tile downloads

* On 2/7/2012, I tried using the Google Static Maps API and received Error 400 (malformed or illegal request) when using the URL described therein. I have had more luck using Google Maps directly to frame the map, getting the (perma)link, and tweaking the parameters.


January 13, 2012

Single Keystroke Menu Using Term::ReadKey

Filed under: Perl — Brandon @ 11:55 am
Tags: ,

Home > My Lists > Programming Notes > PERL > Single Keystroke Menu


Using Term::ReadKey, you can implement a console menu/prompt that accepts a single keystroke. There are many similar implementations of ReadKey available on the Web. This one is in the form of a reusable subroutine. Only valid options are accepted and the choice is returned to the calling script for futher use. It does not convert the choice to upper- or lower-case, because sometimes it is nice to have both options available.



The Subroutine

This code can be placed in a script or in a separate module.

 1: use Term::ReadKey;
 2:
 3: sub getPromptOption ($$)
 4: {
 5: 	my $prompt  = shift;
 6:	my $options = shift;
 7:	my $choice;
 8:
 9:	ReadMode 'cbreak';
10:	print $prompt;
11:	$choice = ReadKey(0) until $choice =~ m/[$options]/;
12:	ReadMode 'normal';
13:	return $choice;
14: }

Obviously, the Term::ReadKey must be loaded first (line 1). The getPromptOption() subroutine accepts two mandatory parameters as indicated by the declared prototype (line 3). Additional field-validation logic may be desired, but is omitted here for brevity. The terminal’s “read” mode is changed to cbreak, which accepts a single character as input (line 9). The prompt that was passed into the subroutine is printed on the screen (line 10) and then the program enters a loop that reads characters from keyboard input until one of the valid options is entered (line 11). Once a valid key has been pressed, the read mode is returned to normal mode (input accepted until the Enter key is pressed; line 12) and the chosen option is returned to the calling logic (line 13).

Usage

This is a very contrived routine that illustrates the use of the subroutine described above. It allows the user to increment or decrement a current value.

 1. my $i = 0;
 2. my $action = '';
 3. print "Current value: $i\n\n";
 4. until ( $action =~ m/[Xx]/ ) {
 5.	$action = getPromptOption(
 6.		"Select Action: [I]ncr, [D]ecr, or E[X]it",
 7.		"IiDdXx"
 8.	);
 9.	$i++ if ( $action =~ m/[Ii]/ );
10.	$i-- if ( $action =~ m/[Dd]/ );
11.	print "\n\nCurrent value: $i\n\n";
12. }

The iterator (“$i”) is set to an initial value of zero (line 1) and the next action flag (“$action”) set to null (line 2). The current value is printed on the screen (line 3) so that the user knows what it is. Next, the user is prompted to increment or decrement the value, or to exit the program (lines 5-8). If the user chooses to change the value by pressing the “i” key (line 9) or the “d” key (line 10), then the value is printed again on the screen for the benefit of the user (line 11). If the user presses the “x” key, the loop ends (line 4) and process control flows out to the end of the script. Please notice that both the upper- and lower-cases are valid options (line 7), but that the program is indifferent to which is used (lines 4, 9, 10).


January 10, 2012

Tie::File Examples

Filed under: Perl — Brandon @ 3:07 pm
Tags: ,

Home > My Lists > Programming Notes > PERL > Tie::File Examples


Using Tie::File, you can operate directly on a text file as an array. This provides random access to lines in a file and allows for speedy manipulation of very large files since the file itself is not loaded into memory. The following are some examples with explanation as to how they work. (Yes, these examples are extremely rudimentary and a bit redundant at that; this is because I like to have complete examples at my fingertips to use as base templates when I need them for real programming work.)


The Data File

Any ASCII text file can be used with the following examples. I use “myfile.txt” for illustrative purposes, and for me, it is a twenty-line file that contains consecutive numbers on each line (line 1 is “1”, line 2 is “2”, etc.). The following code creates this data file and quickly resets it as needed.

1: open (OUT,">myfile.txt");
2: print OUT join("\n",1..20);
3: close OUT;

Basic Example

This is a very basic example for using Tie::File. It just prints the contents of an array on the screen.

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: print join ( "\n", @records );
5: untie @records;

The module must first be loaded using the use function (line 1). Next, an array is defined that will be tied to the file (line 2). The tie command is where the magic happens (line 3). Now the lines in the file can be operated upon as though they were just elements in an array. The print/join function is a common way to print an array to the screen (line 4). The untie function releases the file (line 5), though this is often omitted due to laziness.

Direct Access

Reading a file and printing records is only so much fun. Here’s an example of how to change a single line in the file directly.

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: $records[9] = "foo";
5: print join ( "\n", @records );
6: untie @records;

This is the same code as before, except that line 4 has been injected. It is a simple assignment that changes the tenth line of the file to “foo”. Remember that PERL arrays are zero-based, so $records[9] is actually the tenth element in the array.

Autochomp

Notice that newlines must either be chomped on input or readded for output. This is handled automatically.

Windows Newlines

Here’s an interesting trick if you are using PERL on Windows. Consider the following code.

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: $records[9] = "foo\nbar";
5: print join ( "\n", @records );
6: untie @records;

Adding a newline character (“\n”) to the array element value will only embed it in the string. Inspect the file afterward, and find that no new line has been created in the file, even though it appears from the screen output that one had been added. Since line endings in Windows are two characters instead of one, carriage-return and linefeed, you must prepend the other character (“\r”).

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: $records[9] = "foo\r\nbar";
5: print join ( "\n", @records );
6: untie @records;

Now the file does show an additional line. Of course, there are much better ways of doing this.

Changing Record Separators

Much like the RS and ORS variables in AWK, the record separator can be changed to any text string. This is done when the file is tied. Only this line is presented here.

1: tie @records, 'Tie::File', "myfile.txt", recsep => 'zap';

Now, the file will be separated into records on every occurrence of the string ‘zap’. I don’t want to spend the time to write and test a working example for this, as the need for this sort of thing may never arise in my work. It was just interesting to note.

Splicing

To remove one or more lines from a tied file, use the splice command.

1: use Tie::File;
2: my ( @records, @removed );
3: tie @records, 'Tie::File', "myfile.txt";
4: @removed = splice(@records,1,3);
5: print join ( "\n", @records );
6: untie @records;

Again, this is the same code we’ve been using, except an additional array has been declared (line 2) and the splice command has been introduced to remove the second, third, and fourth lines from the file (line 4). The first parameter of the splice function is the array, the second is the offset from the beginning of the array (one element), and the third is the length of the slice to be removed (three elements).

Here’s how elements can be replaced.

1: use Tie::File;
2: my ( @records, @removed );
3: tie @records, 'Tie::File', "myfile.txt";
4: @removed = splice(@records,1,3,26);
5: print join ( "\n", @records );
6: untie @records;

The same records are removed as above, but one new element has been inserted in their place with a value of 26.

Push, Pop, Shift, Unshift

All of these functions have splice equivalents, but they can be used as they normally would to manipulate the tied file.

Iteration

Random access is nice, but sometimes it is necessary to iterate through the records in a file. The following illustrates how to print the contents of the array to the screen by iteration instead of using print/join.

1. use Tie::File;
2. my ( @records, $record );
3. tie @records, 'Tie::File', "myfile.txt";
4. foreach $record ( @records ) { print "$record\n"; }
5: untie @records;

In addition to declaring the array, a record scalar is defined (line 2). The foreach iterator is used as one would expect to traverse through the array from beginning to end. A for loop could have been used just as easily.


August 23, 2011

Slurping Files In Perl

Filed under: Perl — Brandon @ 10:57 am
Tags: , ,

“Slurping” is a technical term that means to import an entire file into memory at one time. This is typically done when the data imported will not be changed, because it is static lookup data for example, or because you want to protect the contents of the file from accidental corruption. I use this technique often and was going to write a how-to post, but it seems that Uri Guttman has already posted an excellent treatment of this topic on the Perl.com blog titled Perl Slurp-Eaze.


February 26, 2010

Using The Windows Clipboard in Perl

Filed under: Perl — Brandon @ 11:05 am

The following snippet illustrates the use of the Win32::Clipboard module.

use Win32::Clipboard;
$clip = Win32::Clipboard();
print "Type your name: ";
$input = <>
chomp $input;
$clip->Set("Hello, $input!");
print "You may now paste!\n";

June 30, 2009

Using Perl Hashes

Filed under: Perl — Brandon @ 10:00 pm

Home > My Lists > Programming Notes > PERL > Using PERL Hashes


A hash, or associative array, is basically an array that has a textual key instead of a numeric key. Any Perl reference will explain basic usage, but the following is a compilation of items that I almost always have to look up if I have not coded in Perl for a while. A few “tricks” that I’ve learnt over time have been included as well.


Things to Remember

Creating Hashes. Hashes can be created using various methods. Below is the syntax for several options. Each method produces exactly the same result, a hash in which numeric values ‘1’ and ‘2’ are referenced by their textual equivalents.

%numbers = (); # Create an empty hash.
$numbers{one} = 1; $numbers{two} = 2; # Set one at a time.
%numbers = (one,1,two,2); # Use barewords for key/value pairs.
%numbers = ('one','1','two','2'); # Quote if key or value has spaces.
%numbers = qw(one 1 two 2); # Use a quoted-word list.
%numbers = (one => 1,two => 2); # Force strings on the left.
@numbers{one,two} = (1,2); # In non-intuitive array context.
@numbers{@keys} = @values; # Logical extention of the above.
map { $_ = ++$i } @numbers{one,two}; # Something to ponder.

Elements Existing & Defined.
The ‘exists’ function returns true if they specified key exists in the specified hash, whereas the ‘defined’ function determines if the value of the element has been defined.

The following two commands report the statuses of the key and the value of $hash{$key}:

exists($hash{$key})  ? print 'Exists, and ' : print 'Does not exist, and ';
defined($hash{$key}) ? print 'is defined.'  : print 'is not defined.';

Running these lines only should result in:

Does not exist, and is not defined.

Prepending the the following line, setting the element to an undefined value:

$hash{$key} = undef;

should result in:

Exists, and is not defined.

Prepending the the following line, setting the element to a null value:

$hash{$key} = '';

should result in:

Exists, and is defined.

General Note About Data Structures. Hashes are often used to represent data entities, but how they are used dictates perspective. Consider the following:

  • A simple hash can be analogous to a simple data table and the hash’s key to the table’s primary key. For example, %phone_numbers represents the same thing as a table called “Phone Numbers” and $phone_numbers{‘Bob’} = 555-1234 represents a record in that data table which we now know contains at least two fields, “Name” (pk) & “Number”. Additional fields in the table that (of course) relate to the same key must be stored in a different hash.
  • A hash of (anonymous) hashes eliminates the need to use multiple named hashes to represent fields. For example, %contacts can represent the “Contacts” table in the database, $contacts{‘Bob’} represents the row uniquely identified by the primary key ‘Bob’, and $contacts{‘Bob’}{‘address’}, $contacts{‘Bob’}{‘home phone’}, $contacts{‘Bob’}{‘work phone’}, $contacts{‘Bob’}{‘mobile phone’}, and $contacts{‘Bob’}{‘birthday’} represent the various fields in that table.
  • A hash of arrays can represent a set of named lists. For example, the %lists hash may include $lists{‘To Do’}, $lists{‘Shopping’} & $lists{‘Calls To Make’}. If each of these were a simple string element, this hash wouldn’t be very useful; however, if each contains an array reference, then elements can be pushed, popped, shifted, unshifted, and even grepped, sliced & spliced as needed.
  • Larger structures are simply combinations of these smaller structures. For example, returning to the %contacts example above, $contacts{‘Bob’}{‘call log’} could be an array containing string elements, each noting the date and a brief description of a call to Bob. The first would be referenced as $contacts{‘Bob’}{‘call log’}[0], the second as $contacts{‘Bob’}{‘call log’}[1], and so forth.

Creation of these types of structures is covered next.

Hash of Hashes. Three different methods are used here to create such a structure, though all of the methods for creating hashes as explained above can apply.

# Using anonymous hash constructor.  Structure engineered from the start.
%numbers = (
     german => {
          one => ein,
          two => zwei
     }
);

# Using the constructor inline.  Structure segments built only when needed.
$numbers{spanish} = {
     one => uno,
     two => dos
};

# Using named hashes.  Least efficient and least intuitive.
%french = (
     one => un,
     two => deux
);
$numbers{french} = \%french;

The following code snippet will do two things: illustrate how to reference elements within the structure and prove that the %numbers hash was built according to expectations.

print "Languages: " . join(', ',keys %numbers) . "\n";
foreach $lang (keys %numbers) {
     print "Numbers in $lang:\n";
     foreach $num (keys %{$numbers{$lang}}) {
          print "\t$num == $numbers{$lang}{$num}\n";
     }
}

Let’s interpret this clause from line 5 of the snippet: $numbers{$lang}{$num}. The way to read this is that the first segment, $numbers{$lang}, is translated into a hash reference (a pointer for C programmers), which is used in turn to resolve the second segment, HASH(0x123456){$num}. In the loop on the preceding line, the $numbers{$lang} hash reference is being placed (or “cast”) into hash context using the %{} construct because the keys function expects a hash reference as a parameter.

Hashes of Arrays. Here is one way to create an array as a hash elements and then push values to it.

# Using anonymous array constructor.
%numbers = (
     English => ["zero", "one", "two", "three"],
     German => ["null", "ein", "zwei", "drei"],
     Spanish => ["cero", "uno", "dos", "tres"]
);

# Using push and quoted words.
push(@{$numbers{French}}, qw/ zero un deux trois/);

As with hashes of hashes above, other methods are available, such as using references to named arrays. These have been omitted for brevity. Note the casting of the element into an array context: @{$numbers{French}}. Here is a snippet of code to validate the contents:

foreach $k (sort keys(%numbers)) {
	print "$k numbers are " . join(', ',@{$numbers{$k}}) . ", etc.\n";
}



Hash Tricks

Sort Unique. On multiple occasions, I’ve had the need to remove duplicate values from an array. In the Unix shell, a sort -u works nicely, but Perl’s sort doesn’t work quite that way. Instead of programming this in place each time, I’ve often written a subroutine similar to this one:

sub sort_unique {
     my %h; my $k;
     foreach $k (@_) {
          $h{$k}++;
     }
     return(sort keys(%h));
}

The subroutine accepts a simple list as input. In a loop, elements of the list are used as keys for an internal hash. With each pass, the value of the corresponding hash element is incremented. The list of hash keys is sorted and returned as a list. Strictly speaking, the sorting isn’t mandatory, but otherwise, the keys will be returned in an arbitrary order. A side-benefit that may be exploited is that the number of occurances of each list item is known once the input list is traversed.

Please see this page from the perl.com FAQ for some shorter and more efficient alternatives. Here are modularized variants of options (b):

sub sort_unique {
     undef my %h;
     return sort grep(!$h{$_}++, @_);
}

and (d):

sub sort_unique {
     undef my %h;
     @h{@_} = ();
     return sort keys %h;
}

Again, the sort is optional but nice.




Create a free website or blog at WordPress.com.