Forum Moderators: coopster & phranque

Message Too Old, No Replies

Bag-O-Tricks for Perl

Let´s collect some nice and useful perl scripts

         

andreasfriedrich

12:52 am on Mar 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



tag replace - replace HTML tags or attribute values

This script lets you replace HTML tags and change the values in attributes. Imagine you wanted to replace all div tags which have a class attribute of quote to p tags. Or you would like to change all links pointing to aaron.html to stevie.php. Using this little script makes such tasks very easy.

Some examples

Here´s how you would do these things:


./tagrep /path/to/html/files div p TAGNAME class=quote
./tagrep /path/to/html/files aaron.html stevie.php href

Syntax

tagrep takes quite a few arguments on the command line.


Usage: ./tagrep <dir> <pattern> <replacement> <attribute¦TAGNAME>
[<(id¦class)=identifier>] [<empty_tags>]

Here is what they are:

  • dir: The path to a directory containing the HTML files that you want to be searched for <pattern> or the path to a single HTML file.
  • pattern: The pattern to search for. This pattern will be used in a Perl [perl.com] regular expression so it has to be a valid Perl [perl.com] re pattern. The object that the pattern will be applied to will depend on the setting of <attribute¦TAGNAME>.
  • replacement: This is a string that will be replaced for the pattern. You may use backreferences here if your <pattern> build them using parens.
  • attribute¦TAGNAME: If want to search in an attribute sepcify the name. If you want to change tagnames use the keyword TAGNAME. The <pattern> will be the tagname to be replaced with <replacement>
  • (id¦class)=identifier: This optional parameter lets put additional restraints on your replacements. Only elements that have the given attribute of either id or class and the specified identifier will be searched for <pattern>. id=aaron will search only in the start tag of elements that have an id of aaron.
  • empty_tags: This is a Perl [perl.com] regular expression pattern of empty elements that you use in the HTML documents. This parameter is required when you specify TAGNAME and any additional restraints with <(id¦class)=identifier>. To replace the tagname in end tags only when their start tag has a certain id or class we need to know which end tag belongs to which start tag. This is done by counting opening and closing tags. Since HTML allows for quite a few optional end tags and even for empty elements this approach only works when we know when not to expect an end tag. Figuring that out with an algorithm is quite hard and one reason why XML [w3.org] and XHTML abandoned this approach. To make it easier on me and the script you will have to tell the script which elements do not have an end tag. If you use li elements and td elements without an end tag you would specify li¦td.

Code

Here is the code of this script. Simply save it as tagrep and adjust the path to the Perl [perl.com] binary as needed.


#!/usr/bin/perl -w
# $Id: tagrep,v 1.2 2003/02/28 22:42:45 af Exp $
#
use [perldoc.com] strict [perldoc.com];
#
use [perldoc.com] File::Find [perldoc.com];
use [perldoc.com] HTML::Parser [perldoc.com];
#
my [perldoc.com] ($type, $id) = split [perldoc.com] /=/, $ARGV[4] if $ARGV[4];
my [perldoc.com] $empty = '';
$empty = join [perldoc.com] '', '¦', $ARGV[5] if $ARGV[5];
my [perldoc.com] $replace_end = 0;
#
my [perldoc.com] $p = HTML::Parser->new(api_version => 3);
$p->handler( start => sub {
my [perldoc.com] $tag = shift [perldoc.com];
my [perldoc.com] $attr = shift [perldoc.com];
my [perldoc.com] $changed = 0;
$replace_end++ if $replace_end>=1000 and $tag!~ /br$empty/o;
print [perldoc.com](OUT shift), return [perldoc.com] if $type
and (!exists [perldoc.com] $attr->{$type} or $attr->{$type}!~ /$id/o);
if ($ARGV[3] eq 'TAGNAME') {
$tag = $ARGV[2], $changed++, $replace_end=1000
if $tag =~ /$ARGV[1]/o;
} else {
$attr->{$ARGV[3]} =~ s!$ARGV[1]!$ARGV[2]!go,
$changed++ if exists [perldoc.com] $attr->{$ARGV[3]};
}
print [perldoc.com](OUT shift [perldoc.com]), return [perldoc.com] unless $changed;
print [perldoc.com] OUT '<', $tag, ' ', join [perldoc.com](' ', map [perldoc.com] {
join [perldoc.com] '', $_, '="', $attr->{$_}, '"'
} keys [perldoc.com] %$attr), '>'; }, "tagname,attr,text");
$p->handler( end => sub [perldoc.com] {
print [perldoc.com](OUT "</$ARGV[2]>"), return [perldoc.com]
if $ARGV[3] eq 'TAGNAME' and shift [perldoc.com] =~ /$ARGV[1]/o
and $replace_end==1000;
$replace_end--;
print [perldoc.com] OUT pop [perldoc.com]; }, "tagname,tagname,text");
$p->handler( default => sub [perldoc.com] { print [perldoc.com] OUT shift [perldoc.com] }, "text");
#
find(sub [perldoc.com] {
return [perldoc.com] if -d $File::Find::name;
return [perldoc.com] unless $File::Find::name =~ /\.html?$/;
open [perldoc.com] 'OUT', ">$File::Find::name.temp"
or die [perldoc.com] "Can't open $File::Find::name.temp: $!\n";
print [perldoc.com] "Examining $File::Find::name...\n";
$p->parse_file($File::Find::name)
or die [perldoc.com] "Can't parse file: $File::Find::name.temp: $!\n";
close [perldoc.com] 'OUT';
rename [perldoc.com]($File::Find::name, "$File::Find::name.orig");
rename [perldoc.com]("$File::Find::name.temp", $File::Find::name);
}, $ARGV[0] ¦¦ die [perldoc.com]
"Usage: $0 <dir> <pattern> <replacement> <attribute¦TAGNAME>
[<(id¦class)=identifier>]\n");

Please use at your own risk. I tested this script with quite a few of my HTML files. But they were mine and others may have a different style. The script should work for those as well, but you never know.

However, your original files will be saved as filename.orig. So you can always go back to that version. Just don´t run the script twice in a row since then it will override your original files and you´ll never get those back unless you made some backup.

Please post when this script does not work for you.

Andreas

Birdman

1:40 pm on Mar 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Nice, Andreas! Now if I can learn to use my brand new Perl download I can check it out. win_proxy comes first, though ;)

andreasfriedrich

3:07 pm on Mar 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



This is an improved version of the script I posted in this thread: replacing a word with a link on whole site [webmasterworld.com]


HTML replace - replace the content of HTML elements

This script lets you do search and replace operations on the content of HTML elements only. Imagine you wanted to replace a person´s name with a link to their website. Of course this should be done only if that name is not already within the content of an a element. Or suppose you wanted to do this but sometimes you used the person´s full name but sometimes only their first name.

Using this little script makes such tasks very easy.

Some examples

Here´s how you would do these things:


./htmlrep /path/to/html/files "Aaron C\." "<a href=''>Aaron C.</a>" body a
./htmlrep /path/to/html/files "(Aaron(\s+C\.)?)" "<a href=''>\$1</a>" body a

You can make your search case-insensitive by prepending your pattern with (?i). If you wanted to replace every title that contains aaron with Stevie B. you would call htmlrep like so:


./htmlrep /path/to/html/files "^(?i).*aaron.*$" "Stevie B." title

Syntax

htmlrep takes quite a few arguments on the command line.


Usage: ./htmlrep <dir> <pattern> <replacement> <elements+> <elements->
[<attribute=value>]

Here is what they are:

  • dir: The path to a directory containing the HTML files that you want to be searched for <pattern> or the path to a single HTML file.
  • pattern: The pattern to search for. This pattern will be used in a Perl [perl.com] regular expression so it has to be a valid Perl [perl.com] re pattern.
  • replacement: This is a string that will be replaced for the pattern. You may use backreferences here if your <pattern> build them using parens. Note that you need to escape these backreferences as shown in the second example.
  • elements+: A regular expression matching element names whose content should be subject to replacing <pattern> by <replacement>.
  • elements-: A regular expression matching elements contained with <elements+> which should be exempt from replacing <pattern> by <replacement>. This pattern is optional.
  • attribute=value: This optional parameter lets put additional restraints on your replacements. Only the content of elements that have the given attribute and the specified value will be searched for <pattern>. class=menu will search only in the content of elements below <elements+> which have a class of menu.

Code

Here is the code of this script. Simply save it as htmlrep and adjust the path to the Perl [perl.com] binary as needed.


#!/usr/bin/perl -w
# $Id: htmlrep,v 1.4 2003/03/01 13:51:37 af Exp $
#
use [perldoc.com] strict;
#
use [perldoc.com] File::Find [perldoc.com];
use [perldoc.com] HTML::Parser [perldoc.com];
#
my [perldoc.com] $sub = eval [perldoc.com] "sub [perldoc.com] { s [perldoc.com]!$ARGV[1]!$ARGV[2]!g }";
die [perldoc.com] $@ if $@;
#
my [perldoc.com] ($type, $id) = split /=/, $ARGV[5] if $ARGV[5];
my [perldoc.com] $r = 0;
my [perldoc.com] $rr = 0;
my [perldoc.com] $p = HTML::Parser [perldoc.com]->new(api_version => 3);
$p->handler( start => sub [perldoc.com] {
my [perldoc.com] $attr = pop [perldoc.com];
print [perldoc.com](OUT pop [perldoc.com]), $r=0, return [perldoc.com] if shift [perldoc.com] =~ /$ARGV[3]/o and $type
and ((exists $attr->{$type} and $attr->{$type}!~ /$id/o)
or!exists $attr->{$type});
$r=1 if shift [perldoc.com] =~ /$ARGV[3]/o;
$rr=$r, $r=0 if $ARGV[4] and shift [perldoc.com] =~ /$ARGV[4]/o;
print [perldoc.com] OUT pop [perldoc.com]; }, "tagname,tagname,tagname,text,attr");
$p->handler( end => sub [perldoc.com] {
$r=0 if shift [perldoc.com] =~ /$ARGV[3]/o;
$r=$rr if $ARGV[4] and shift [perldoc.com] =~ /$ARGV[4]/o;
print [perldoc.com] OUT pop [perldoc.com]; }, "tagname,tagname,text");
$p->handler( text => sub [perldoc.com] {
print [perldoc.com](OUT shift [perldoc.com]), return [perldoc.com] unless $r;
local $_ = shift [perldoc.com];
&$sub;
print [perldoc.com] OUT }, "text");
$p->handler( default => sub [perldoc.com] { print [perldoc.com] OUT shift [perldoc.com] }, "text");
#
find(sub [perldoc.com] {
return [perldoc.com] if -d $File::Find::name;
return [perldoc.com] unless $File::Find::name =~ /\.html?$/;
open [perldoc.com] 'OUT', ">$File::Find::name.temp"
or die [perldoc.com] "Can't open $File::Find::name.temp: $!\n";
$r = 0;
print [perldoc.com] "Examining $File::Find::name...\n";
$p->parse_file($File::Find::name)
or die [perldoc.com] "Can't parse file: $File::Find::name.temp: $!\n";
close [perldoc.com] 'OUT';
rename [perldoc.com]($File::Find::name, "$File::Find::name.orig");
rename [perldoc.com]("$File::Find::name.temp", $File::Find::name);
}, $ARGV[0] ¦¦ die [perldoc.com]
"Usage: $0 <dir> <pattern> <replacement> <elements+> [<elements->]
[<attribute=value>]\n");

Andreas


Note: Make sure to replace "¦" with a solid vertical pipe.

gperrones

3:45 pm on Mar 4, 2003 (gmt 0)

10+ Year Member



Andreas, thank you for sharing. These two scripts are great timesavers! I have a big static HTML site and had to manually edit hundreds of tags more than one time.

andreasfriedrich

2:31 am on Mar 13, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Highlighting Search Terms on Static Pages

In Bag-O-Tricks for PHP II - some code snippets that should be helpful for all in creating dynamic sites - Highlighting Search Terms [webmasterworld.com] I explained how to highlight search terms on dynamically generated pages. Now how about highlighting search terms on static pages.

Obviously this will need some kind of script to alter the pages according to the search terms used. Now you could simply change all your static pages to PHP [php.net] and use the above mentioned method. There is a better way that will not require you to change your existing static pages. It uses mod_rewrite [httpd.apache.org] to transparently call a highlighting script when the referrer is a search engine.

.htaccess

The following two rules need to go into your .htaccess file.


RewriteCond [httpd.apache.org] %{HTTP_REFERER} google¦alltheweb¦brisbane [NC]
RewriteRule [httpd.apache.org] \.html$ hst.pl?file=%{REQUEST_FILENAME};%{QUERY_STRING}

script

This is the script that performs the highligting:


#!/usr/bin/Perl [perl.com]
#
use [perldoc.com] strict [perldoc.com];
use [perldoc.com] HTML::Parser [perldoc.com];
#
print [perldoc.com] <<END;
Content-Type: text/html
__EMPTY__LINE__
END
#
my %para = split [perldoc.com] /;¦=¦&/, $ENV{QUERY_STRING};
#
my $i = 'a';
my @rules = ();
foreach (split [perldoc.com](/[\s+]+/, $para{'q'})) {
push [perldoc.com] @rules, "\$x =~ s¦\\b$_\\b¦<em class='$i'>$_</em>¦i;";
$i++;
}
my $rules = join [perldoc.com] '', @rules;
my $m = eval [perldoc.com] "sub {my \$x = shift; $rules; return \$x;}";
#
my $p = HTML::Parser->new(api_version => 3);
$p->handler(default => sub { print shift }, "text");
$p->handler(start => sub
{ print [perldoc.com]('<style type="text/CSS [w3.org]">em.a{}em.b{}em.c{}</style>',
pop);
return [perldoc.com] unless shift eq 'body';
shift->handler(text => sub { print &$m(shift) }, "dtext");
}, "tagname,self,text");
#
$p->parse_file($para{file});

Styling highlighting

By putting some CSS [w3.org] rules into the empty em.a ... em.n container you can style each highlighted search term individually.

Andreas

Allen

8:35 am on Mar 13, 2003 (gmt 0)

10+ Year Member



Sorry, couldn't resist...

To make all you script much more secure and 10x faster to code, convert them to PHP :P

Allen

andreasfriedrich

4:07 pm on Mar 13, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I know one shouldn´t feed the trolls, but I couldn´t resist either.

Care to elaborate on that?

  1. Specifically why is PHP [php.net] running as a webserver module faster than Perl [perl.com] running as a webserver module?
  2. Why is PHP [php.net] more secure than Perl [perl.com] when comparing mod_php<->mod__perl and PHP [php.net].cgi<->Perl [perl.com].cgi?
  3. Why PHP [php.net] is faster to code when recursively doing something to each file under a certain directory takes simply use [perldoc.com] File::Find [perldoc.com]; find(sub [perldoc.com]{ do_whatever; }, '/dir'); whereas in PHP [php.net] one had to do the recursion manually? That´s not hard for sure, but requires some more coding.
  4. What´s a PHP [php.net] equivalent to Perl [perl.com]´s HTML::Parser [perldoc.com] that allows you to simply define some call back functions and handles everything else automatically?
  5. How is typing $var = preg_match [php.net]("'pattern'", "", $var); 10 times faster than typing $var =~ s [perldoc.com]/pattern//;?
  6. How is coding a proxy server in PHP [php.net] faster than in Perl [perl.com] when I get a simple daemon in Perl [perl.com] by use [perldoc.com]ing HTTP::Daemon [perldoc.com] when I have to hand code it in PHP [php.net]?
  7. How is installing a new module faster in PHP [php.net] than in Perl [perl.com] when in Perl [perl.com] it takes only a simple Perl [perl.com] -MCPAN [cpan.org] -e 'CPAN [cpan.org]::Shell->install("module_name")' from the shell prompt?

If you can answer these questions and show me that coding in PHP [php.net] is indeed 10 times faster then I will happily abandon Perl [perl.com] forever and switch to PHP [php.net].

I believe that both bags have their pros and cons and that especially the first two scripts in this bag are coded and run way faster in Perl [perl.com] than in PHP [php.net].

I´m looking forward to your answers, Allen.

Andreas

andreasfriedrich

2:12 pm on Mar 21, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Since nobody provided any evidence to the contrary I still consider Perl [perl.com] to be secure and [...] fast to code and will go on using it.


Encoding email addresses

While this is certainly not a very safe way to prevent spam bots from picking up your email addresses it works for the time being since those bots are written with speed in mind so they generally do not decode entities before parsing the html code.


s [perldoc.com]/((?:mailto:)?[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z]{2,3})/encode_email($1)/ge;
#
sub [perldoc.com] encode_email {
my @email = split [perldoc.com] //, shift [perldoc.com];
for (my $i=0;$i<$#email;$i++) {
$email[$i] = sprintf [perldoc.com] "&#%d;", ord [perldoc.com]($email[$i]);
}
return [perldoc.com] join [perldoc.com] '', @email;
}

The script will look for anything that looks like a mailto: link and convert it into numeric entities. Browsers will decode the link while spam bots will not.

This method should be ok in the EU as well where you are required to put a working and easy to find and use email address on your site. I believe that JavaScript solutions will not suffice since you need JavaScript enabled to view the email address.

Andreas

Birdman

2:23 pm on Mar 21, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Andreas,

I'd like to implement that script but I haven't done my Perl [perl.com] homework. Where do I put the script?

andreasfriedrich

2:31 pm on Mar 21, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



That will depend on your setup Birdman. If you are using PHP [php.net] then the PHP [php.net] version in Bag-O-Tricks for PHP II [webmasterworld.com] might suit you better. If you have a Perl [perl.com] script that produces a webpage then you would run the RE after the html code has been assembled. If you retrieve the email address from a db you can call
encode_email
directly as well.

Andreas

andreasfriedrich

2:19 pm on Mar 26, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



tag replace - some modifications

Here are two ways to improve on the initial version.

Expanding variables in replacement string

If you want to be able to expand variables in your replacement string you can change the following line


$attr->{$ARGV[3]} =~ s [perldoc.com]!$ARGV[1]!$ARGV[2]!go,

to read like so:


$attr->{$ARGV[3]} =~ s [perldoc.com]!$ARGV[1]!$ARGV[2]!g,
$attr->{$ARGV[3]} =~ s [perldoc.com]!(\$[a-zA-Z0-9_:]+)!$1!gee,

You could then do something like this:


./tagrep /var/www/html/aaron-carter/ '^friends.cgi$' \
'friends.cgi?file=$File::Find::name' href

This will add the file name as the file parameter to the URIs in your href [w3.org] attributes.

Execute Perl [perl.com] code on replacement

The most flexibility is gained when you can run arbitrary Perl [perl.com] code to build your replacement string. To allow for that replace these lines in the original script


$attr->{$ARGV[3]} =~ s!$ARGV[1]!$ARGV[2]!go,
$changed++ if exists $attr->{$ARGV[3]};

with these:


if (exists [perldoc.com] $attr->{$ARGV[3]}) {
$changed++;
if ((my $rep) = $ARGV[2] =~ m [perldoc.com]!^sub [perldoc.com]\s*{([^}]+)!) {
$attr->{$ARGV[3]} =~ s [perldoc.com]!$ARGV[1]!$rep!gee;
} else {
$attr->{$ARGV[3]} =~ s [perldoc.com]!$ARGV[1]!$ARGV[2]!g;
$attr->{$ARGV[3]} =~ s [perldoc.com]!(\$[a-zA-Z0-9_:]+)!$1!gee;
}
}

You could then do something like this:


./tagrep /var/www/html/aaron-carter/ '^friends.cgi$' \
'sub{(my $n = $File::Find::name) =~ \
s!^/var/www/html!http://www.aaroncarter.com!; \
return "friends.cgi?file=$n";}' href

This will add the URI of your HTML page as the file parameter to the URIs in your href [w3.org] attributes.


<a href="friends.cgi">email a friend</a>

will be changed to


<a href="friends.cgi?file=http://www.aaroncarter.com/aaron-carter/file.html
">email a friend</a>

Andreas

Damian

3:32 pm on Mar 26, 2003 (gmt 0)

10+ Year Member



Nice thread Andreas. My two cents..

Have your script send you email

A simple subroutine that you can use in your scripts to have it send you email. This can be a nice feature on some events such as security alerts, people filling in forms, known ip's visiting your site etc..

$mailprogram should be your mailprogram, ie
$mailprogram = "/usr/sbin/sendmail";

and the syntax to use the sub is:
&Email($title,$message);
or
&Email("Title of email","Hi! This is an email from my script to myself");

sub Email {

my ($title, $message) = @_;

open (MAIL,"¦$mailprogram -t");
print MAIL "To: name\@example.com\n";
print MAIL "From: script\@example.com\n";
print MAIL "Subject: $title\n\n";
print MAIL "$message \n";
close(MAIL);

}

change the pipe character ¦ to a 'regular' pipe character, this has to do with the way regular pipes are shown on WebmasterWorld

andreasfriedrich

12:15 am on Apr 4, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



See Using heredoc syntax [webmasterworld.com] in the Bag-O-Tricks for PHP II [webmasterworld.com] for some subtle differences in here doc syntax between Perl [perl.com] and PHP [php.net].

Andreas

davez1000

4:46 pm on Apr 18, 2003 (gmt 0)

10+ Year Member



Just a quick one, most of you probably already know this, lets say you have a txt file that looks like this:

1¦¦774079¦¦Zack¦¦3
2¦¦902345¦¦Alan¦¦8
3¦¦148271¦¦Peter¦¦106
4¦¦008593¦¦Nancy¦¦9
5¦¦954311¦¦Victor¦¦0

You want to sort the 3rd column, names, and print out each line.

open the file and read into @data:


open(FILE, "<thefile.txt");
@data = <FILE>;
close (FILE);

now the loop:


foreach $line(sort{lc((split(/\¦\¦/, $a))[2]) cmp lc((split(/\¦\¦/, $b))[2])} @data){
chomp $line if $line =~ /\n$/i;
($num,$ID,$name,$count) = split(/\¦\¦/, $line);
print "$num $ID $name $count<BR>";
}

lc using cmp sorts alpha regardless of case. To sort in reverse, just swap the $a and $b variables around.

to sort by a numeric column, lets say the second column, remove the lowercase(lc) command, and use the spaceship operator, so the first line of the loop would be this instead:


foreach $line(sort{(split(/\¦\¦/, $a))[1] <=> (split(/\¦\¦/, $b))[1]} @data){

Hope this quick elaboration helps...

Dave

[edited by: jatar_k at 12:01 am (utc) on April 19, 2003]
[edit reason] no sigs thanks [/edit]

ShawnR

6:58 am on Apr 19, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks Dave, and Welcome to WebmasterWorld!

Quite a first post! I think the norm is for first posts to be requests for help, not contributions to the body of knowledge, so thanks.

Why do you need the chomp?

Just to be pedantic, I think there is a typo? Don't you need the '[1]' after '$a))'?

Shawn

davez1000

3:37 pm on Apr 19, 2003 (gmt 0)

10+ Year Member



Shawn,

Yeah you do, the post has been edited cause I put a sig up. I tested the script before I posted it and it works, that bit is missing now. Should be:


foreach $line(sort{(split(/\¦\¦/, $a))[1] <=> (split(/\¦\¦/, $b))[1]} @data){

I always chomp for safety, so I can use the last column item without wondering if there is a newline or not.

I have quite a few groovy perl bits I've written, I'll post them up one by one.

davez1000

3:48 pm on Apr 19, 2003 (gmt 0)

10+ Year Member



Here is a subroutine for putting commas in numbers, good for counters. This sub can take a number up to 12 digits (which is usually far more than most average counters) and must not be a double (contain decimal places). I'll write a sub for that soon.

2 vars to the sub,

&comma($count, ",")
first is the number, second is the symbol, depending on what country you are in. Use a
","
for US, but a
"."
for some euro countries.


sub comma {
$count = @_[0];
$commer = @_[1];
if (length($count) =~ /[4-6]/){$count =~ s/(\d{1,3})(\d{3})/$1$commer$2/i;}
elsif (length($count) =~ /[7-9]/){$count =~ s/(\d{1,3})(\d{3})(\d{3})/$1$commer$2$commer$3/i;}
elsif (length($count) =~ /[10-12]/){$count =~ s/(\d{1,3})(\d{3})(\d{3})(\d{3})/$1$commer$2$commer$3$commer$4/i;}
return $count;
}#end sub


$count = "123456789012";
print &comma($count, ",");

prints this:

123,456,789,012

davez1000

4:10 pm on Apr 19, 2003 (gmt 0)

10+ Year Member



You need to make 11 small gif images, 0.gif, 1.gif, 2.gif, 3.gif etc, and then an extra one for the comma called "comma.gif".
Put the files in the same directory as this perl file, plus a text file, "counter.txt". CHMOD the perl file 755, and the text file 666.
Use this file as an SSI call.

If you need the whole package with images, send me a sticky and I'll send you the zip.

Please replace the broken pipes in this script with the proper ones on your keyboard.


#!/usr/bin/perl -w


$countfile = "counter.txt";


sub comma {
$count = @_[0];
$commer = @_[1];
if (length($count) =~ /[4-6]/){$count =~ s/(\d{1,3})(\d{3})/$1$commer$2/i;}
elsif (length($count) =~ /[7-9]/){$count =~ s/(\d{1,3})(\d{3})(\d{3})/$1$commer$2$commer$3/i;}
elsif (length($count) =~ /[10-12]/){$count =~ s/(\d{1,3})(\d{3})(\d{3})(\d{3})/$1$commer$2$commer$3$commer$4/i;}
return $count;
}#end sub


open (DATA, "<$countfile") ¦¦ &fejl("Cannot open counter");
flock (DATA, 2);
@count = <DATA>;
flock (DATA, 8);
close (DATA);


foreach $counta(@count){
$countaup = $counta + 1;
}


open (DATAB, ">$countfile") ¦¦ &fejl("Cannot open counter");
flock (DATAB, 2);


print DATAB $countaup;


flock (DATAB, 8);
close (DATAB);


@thecount = split(//, &comma($countaup, ","));


print "Content-type: text/html\n\n";


foreach $number (@thecount) {
if ($number eq ","){$number = "comma";}
push (@thenumber, "<IMG SRC=\"$number.gif\" BORDER=\"0\">");
}


print "<nobr>" , @thenumber , "</nobr>";


sub fejl {
print "Content-type: text/html\n\n";
print @_[0];
die;
}
die;

ShawnR

2:01 pm on Apr 24, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Escaping non-uri characters

Say $url='www.domain.com/image%20dir/pic%201.jpg?hello=%22blah%20blah%22';

then

my $decoded_url = $url; 
$decoded_url =~ s/%([a-f\d]{2})/pack('C', hex $1)/egi;

results in $decoded_url being set to:
www.domain.com/image dir/pic 1.jpg?hello="blah blah"

my $encoded_url = $decoded_url; 
$encoded_url =~ s/([^\w\d;\/?:@&=+\$,-.!~*()'])/'%' . unpack('H2', $1)/eg;

results in $encoded_url being set to:
www.domain.com/image%20dir/pic%201.jpg?hello=%22blah%20blah%22

Shawn