Dates in Perl are a pretty big subject but the essence can be reduced to two simple rules: use 'localtime' to retrieve Perl's internal date block and then use 'sprintf' to format the retrieved date. The following subroutine returns the current date and time in the format 'dd-MMM-yy hh:mm' (e.g. 23-DEC-05 15:35)...
sub FormatCurrentDateAndTime
{
my $V_CURRENT = localtime;
my $V_SECOND = substr($V_CURRENT, 17, 2);
my $V_MINUTE = substr($V_CURRENT, 14, 2);
my $V_HOUR = substr($V_CURRENT, 11, 2);
my $V_DAY = substr($V_CURRENT, 8, 2);
my $V_MONTH = uc(substr($V_CURRENT, 4, 3));
my $V_YEAR = substr($V_CURRENT, 20, 4);
# -------------------------------
# And Format the output string...
# -------------------------------
$V_ID_STRING = sprintf("%02d-%s-%02d_%02d:%02d",
$V_DAY,
$V_MONTH,
$V_YEAR,
$V_HOUR,
$V_MINUTE);
TraceScript $Debug,
"MakeDateTimeID",
"Generated id is [" . $V_ID_STRING . "]";
return $V_ID_STRING;
}
The above code is very simple. Calling localtime without an argument gets the current date and time which is then sliced up into the named variables. Sprintf is then called to reformat the value the way we want it. The TraceScript call gives the clue that this particular example is being used to generate a unique ID.
:
Thursday, July 21, 2005
Monday, July 11, 2005
Getting at the bits
One place that Perl scores very highly is reading complex file formats. A really useful built-in function for this purpose is split(). This takes a divider and a string, whose length is only limited by Perl's string handling limit. The divider is in the form of a regular expression, so it can be as complicated as you wish. Split() returns an array, with each piece of the original string as an element, broken up according to the regex and the divider(s) removed. Say, for example, you wrote ...
@Result = split(/:/, "apples:oranges:pears"
then @Result would contain the elements
apples
oranges
pears
with the dividing ':' discarded. The following, real life, example is for extracting the required item from a comma-delimited list, such as a line in a CSV file...
sub GetCsvElement
{
my @V_ARRAY;
my $P_ELEMENT = $_[0];
my $P_SOURCE_STRING = $_[1];
my $V_RESULT;
# -----------------------------------
# Drop the elements into our array...
# -----------------------------------
@V_ARRAY = split (/,/, $P_SOURCE_STRING);
# ----------------------------------------------------------------
# Arrays are zero based so we pick one less than the passed value!
# ----------------------------------------------------------------
$V_RESULT = trim $V_ARRAY[--$P_ELEMENT];
# ----------------------------
# Return the requested item...
# ----------------------------
return $V_RESULT;
}
Remember, because you're using a regular expression to define the delimiter, you can process multiple types of line or even lines with more than one delimiter.
:
@Result = split(/:/, "apples:oranges:pears"
then @Result would contain the elements
apples
oranges
pears
with the dividing ':' discarded. The following, real life, example is for extracting the required item from a comma-delimited list, such as a line in a CSV file...
sub GetCsvElement
{
my @V_ARRAY;
my $P_ELEMENT = $_[0];
my $P_SOURCE_STRING = $_[1];
my $V_RESULT;
# -----------------------------------
# Drop the elements into our array...
# -----------------------------------
@V_ARRAY = split (/,/, $P_SOURCE_STRING);
# ----------------------------------------------------------------
# Arrays are zero based so we pick one less than the passed value!
# ----------------------------------------------------------------
$V_RESULT = trim $V_ARRAY[--$P_ELEMENT];
# ----------------------------
# Return the requested item...
# ----------------------------
return $V_RESULT;
}
Remember, because you're using a regular expression to define the delimiter, you can process multiple types of line or even lines with more than one delimiter.
:
Saturday, July 2, 2005
Perl sans frontiers
I often want to retrieve results from an external process within a Perl script. In theory, this is easy. All you need to do is something like...
$Result = `ls *.sql`
...which works perfectly well on any Unix (or Linux) system. The problem is that it doesn't work at all on Windows so, if you want your programme to be fully portable, you need a workaround. My solution is to use the one common feature on both Windows and Unix, the redirection character (>).
Say I want to run a SQL query (because this is something I do frequently, I have a subroutine for it)...
# =======================================
# Runs an SQL file, returning the result.
# ---------------------------------------
# $_[0] is the connection string.
# $_[1] is the file to run.
# $_[2] is a file to write the result to.
# ---------------------------------------
# (This last is necessary because the ``
# syntax does not work in Windows.)
# =======================================
sub RunSqlQuery
{
my $V_COMMAND = "sqlplus "
. $C_SQLPLUS_FLAGS
. " "
. $_[0]
." \@"
. $_[1]
. " >"
. $_[2];
my $V_RESULT;
# --------------------------------
# Run the command created above...
# --------------------------------
system $V_COMMAND;
# ---------------------------------
# Get the result back from the file
# and send it up the call chain...
# ---------------------------------
$V_RESULT = ReadResultFile $_[2];
return $V_RESULT;
}
Now the above piece of code will work, unaltered, on both Windows and Unix. Then all we need to get at the result is a matching sub-routine to read the file...
# ===============================================
# Reads a file in which a result has been placed.
# -----------------------------------------------
# $_[0] name of the file to read.
# -----------------------------------------------
# This is one of the workarounds made necessary
# because the syntax "VAR=`command`" does not
# work in Windows the same as it does in Unix.
# ===============================================
sub ReadResultFile
{
my $V_BUFFER;
open(H_SQL_FILE, "<$_[0]") or die "FAILURE: Cannot open " . $_[0];
read H_SQL_FILE, $V_BUFFER, 65535;
close H_SQL_FILE;
return $V_BUFFER;
}
The size limit of 65535 bytes is completely arbitrary and can be altered to meet the specific requirements of the application.
:
$Result = `ls *.sql`
...which works perfectly well on any Unix (or Linux) system. The problem is that it doesn't work at all on Windows so, if you want your programme to be fully portable, you need a workaround. My solution is to use the one common feature on both Windows and Unix, the redirection character (>).
Say I want to run a SQL query (because this is something I do frequently, I have a subroutine for it)...
# =======================================
# Runs an SQL file, returning the result.
# ---------------------------------------
# $_[0] is the connection string.
# $_[1] is the file to run.
# $_[2] is a file to write the result to.
# ---------------------------------------
# (This last is necessary because the ``
# syntax does not work in Windows.)
# =======================================
sub RunSqlQuery
{
my $V_COMMAND = "sqlplus "
. $C_SQLPLUS_FLAGS
. " "
. $_[0]
." \@"
. $_[1]
. " >"
. $_[2];
my $V_RESULT;
# --------------------------------
# Run the command created above...
# --------------------------------
system $V_COMMAND;
# ---------------------------------
# Get the result back from the file
# and send it up the call chain...
# ---------------------------------
$V_RESULT = ReadResultFile $_[2];
return $V_RESULT;
}
Now the above piece of code will work, unaltered, on both Windows and Unix. Then all we need to get at the result is a matching sub-routine to read the file...
# ===============================================
# Reads a file in which a result has been placed.
# -----------------------------------------------
# $_[0] name of the file to read.
# -----------------------------------------------
# This is one of the workarounds made necessary
# because the syntax "VAR=`command`" does not
# work in Windows the same as it does in Unix.
# ===============================================
sub ReadResultFile
{
my $V_BUFFER;
open(H_SQL_FILE, "<$_[0]") or die "FAILURE: Cannot open " . $_[0];
read H_SQL_FILE, $V_BUFFER, 65535;
close H_SQL_FILE;
return $V_BUFFER;
}
The size limit of 65535 bytes is completely arbitrary and can be altered to meet the specific requirements of the application.
:
Subscribe to:
Posts (Atom)
Followers
Blog Archive
Who is this Sejanus character anyway?
- Sejanus
- I'm a British freelance Analyst Programmer who has spent the last 25 years working on everything from microcontrollers to mainframes. I use a wide variety of languages at work but try to stick to C and Perl for my own projects.