perl/postscript csv label maker

L

luser-ex-troll

Has this already been done better?
Surely this idea isn't new?
This is a project for my mom, for whom
MSWord and Excel no longer play nicely together.
-- luser-ex-troll

#!/usr/bin/perl
# labels.pl reads csv records in the form:
# "Name","123 Street","Apt","City, ST ZIP"
# from a file named "addr.csv" and
# produces a postscript program on stdout
# suitable for piping into ps2pdf or
# even distiller, maybe
# CAVEATS: prototype produces at most
# one page. label and sheet sizes are hard-coded
# at 3 3-inch-width labels which are 4*17 points
# high. I don't have any real ones on hand
# to measure.

$IN = "addr.csv";
open IN or die "Can't open input: $!";

print <<PROLOG;
%!
/in{72 mul}def
/LEAD 17 def
/LM 10 def
/count 0 def
/TM 11 in LEAD sub def
/Palatino-Roman 15 selectfont

[
PROLOG

while(<IN>) {
s/\n$//;
s/^"/\[\(/;
s/","/\)\(/g;
s/"$/\)\]/;
s/$/\n/;
print;
}

print <<PSPROGRAM;
]

{ %each record
LM TM moveto
{ %each address line
dup () eq { pop } { % skip empties
show % paint the string
%currentpoint exch = = = % diagnostic
LM currentpoint exch pop LEAD sub moveto % reposition
} ifelse
} forall
/LM LM 3 in add store % move over
/count count 1 add store
count 3 mod 0 eq { % back to left after each 3
/LM 10 store /TM TM LEAD 4 mul sub store
} if
} forall

showpage

PSPROGRAM
 
M

macropod

You could, of course, fix the MS Office installation instead of giving your mom something sp arcane to play with.
 
L

luser-ex-troll

You could, of course, fix the MS Office installation instead of giving your mom something sp arcane to play with.

Agreed. But I wanted to have a plan B ready, and I
thought two mutually-embracing languages was interesting.
Besides she's never been happy with the Word+Excel
solution, particularly the word side. When it stopped
working entirely, I thought a different tactic might
be more effective. This way would retain the part she
likes (maintaining the database in excel), and replace
the part she don't (which already required another
program).

Since she already has distiller, she won't need
ghostscript, just perl. everybody needs perl.


luxexterol
 
L

luser-ex-troll

Mommy likes it!
Double-clicking a shortcut is ultimately easier
than any Wizard M$Word can concoct.
Wait till I show her how to edit the file with
a text-editor instead of Excel!

Version 0.2beta:

#!/usr/bin/perl
# labels.pl reads csv records in the form:
# "Name","123 Street","Apt","City, ST ZIP"
# from files named on the command line or
# "addr.csv", if none are specified, and
# produces a postscript program on stdout
# containing records in the form:
# [(Name)(123 Street)(Apt)(City, ST ZIP)]
# suitable for piping into ps2pdf or distiller.
# eg.$ labels|ps2pdf - out.pdf
# CAVEATS:
# coded for Avery 5160 2.5935" x 1"
# letter-sheet labels 3 x 10 / page

if ($#ARGV == -1) { $ARGV[0] = "addr.csv"; } #default argument

print <<PROLOG;
%!
% persuade acrobat reader to obey the numbers
[ {Catalog} << /ViewerPreferences << /PrintScaling /None >> >> /PUT
pdfmark
/in{72 mul}def % tom thumb's shoe size

% measurements
/H 1 in def % how big
/W 2.5935 in def % they are
/Palatino-Roman 16 selectfont % set text 16/
/LEAD H 4 div def % 18
/LM 0.1875 10 add def % edge + padding
/TM 11 in 0.5 in sub LEAD sub def % top - margin - line

% control
/count 0 def
/perLINE 3 def
/perPAGE perLINE 10 mul def

{ %make array as executable to avoid stackoverflow
PROLOG

$\ = $/;
while(<>) {
chop;
s/^"/\{\(/;
s/","/\)\(/g;
s/"$/\)\}/;
print;
}

print <<PSPROGRAM;
} cvlit

{ % each record
cvlit LM TM moveto
{ % each address line
dup () eq { pop } { % skip empties
%dup currentpoint exch = = = % diagnostic
show % paint the string
LM currentpoint exch pop LEAD sub moveto % reposition
} ifelse
} forall
/LM LM W add store % move over
/count count 1 add store
count perLINE mod 0 eq { % back to left after each 3
/LM 10 store
/TM TM H sub store
} if
count perPAGE mod 0 eq { % print a page when it's full
showpage
/LM 10 store
/TM 11 in LEAD sub store
} if
} forall

count perPAGE mod 0 ne { showpage } if
%the end
PSPROGRAM

#eof labels


sample input (addr.csv):
"M. Joshua Ryan","1234 Streetname","","City, ST 12345"
"M. Joshua Ryan","4567 Streetname","","City, ST 23456"
"M. Joshua Ryan","7890 Streetname","","City, ST 34567"
"M. Joshua Ryan","1234 Streetname","","City, ST 45678"
"M. Joshua Ryan","4567 Streetname","","City, ST 56789"
"M. Joshua Ryan","7890 Streetname","","City, ST 67890"
"M. Joshua Ryan","7890 Streetname","","City, ST 67890"
"","","",""


sample output:
%!
% persuade acrobat reader to obey the numbers
[ {Catalog} << /ViewerPreferences << /PrintScaling /None >> >> /PUT
pdfmark
/in{72 mul}def % tom thumb's shoe size

% measurements
/H 1 in def % how big
/W 2.5935 in def % they are
/Palatino-Roman 16 selectfont % set text 16/
/LEAD H 4 div def % 18
/LM 0.1875 10 add def % edge + padding
/TM 11 in 0.5 in sub LEAD sub def % top - margin - line

% control
/count 0 def
/perLINE 3 def
/perPAGE perLINE 10 mul def

{ %make array as executable to avoid stackoverflow
{(M. Joshua Ryan)(1234 Streetname)()(City, ST 12345)}
{(M. Joshua Ryan)(4567 Streetname)()(City, ST 23456)}
{(M. Joshua Ryan)(7890 Streetname)()(City, ST 34567)}
{(M. Joshua Ryan)(1234 Streetname)()(City, ST 45678)}
{(M. Joshua Ryan)(4567 Streetname)()(City, ST 56789)}
{(M. Joshua Ryan)(7890 Streetname)()(City, ST 67890)}
{(M. Joshua Ryan)(7890 Streetname)()(City, ST 67890)}
{()()()()}
} cvlit

{ % each record
cvlit LM TM moveto
{ % each address line
dup () eq { pop } { % skip empties
%dup currentpoint exch = = = % diagnostic
show % paint the string
LM currentpoint exch pop LEAD sub moveto % reposition
} ifelse
} forall
/LM LM W add store % move over
/count count 1 add store
count perLINE mod 0 eq { % back to left after each 3
/LM 10 store
/TM TM H sub store
} if
count perPAGE mod 0 eq { % print a page when it's full
showpage
/LM 10 store
/TM 11 in LEAD sub store
} if
} forall

count perPAGE mod 0 ne { showpage } if
%the end

lxt
(yes, that's my real name, mostly)
 
T

Tad J McClellan

["Followup-To:" header set to comp.lang.perl.misc.]


luser-ex-troll said:
#!/usr/bin/perl

Ask for all the help you can get:

use strict;
use warnings;

if ($#ARGV == -1) { $ARGV[0] = "addr.csv"; } #default argument


$ARGV[0] = "addr.csv" unless defined $ARGV[0]; # default argument

while(<>) {
chop;


chop() was how we removed newlines in the mid-90s.

chomp() is how we remove newlines nowadays.

s/^"/\{\(/;
s/","/\)\(/g;
s/"$/\)\}/;


The replacement part of s/PATTERN/REPLACEMENT/ is a string.

None of those backslashed characters are special in strings,
so none of those backslashes are needed.

s/^"/{(/;
s/","/)(/g;
s/"$/)}/;
 
I

Ilya Zakharevich

Ask for all the help you can get:

use strict;
use warnings;

Or, better, add -w ot the #!-line...
if ($#ARGV == -1) { $ARGV[0] = "addr.csv"; } #default argument
$ARGV[0] = "addr.csv" unless defined $ARGV[0]; # default argument

I would write

@ARGV = "addr.csv" unless @ARGV;

[ Unfortunately, the most logical @ARGV ||= "addr.csv" does not
compile... If it would, the scalar/list context determination
might get in the way, too... ]
The replacement part of s/PATTERN/REPLACEMENT/ is a string.

Still, one should keep in mind that backslashes may help with "less
capable" editors... ;-)

Ilya
 
L

luser-ex-troll

["Followup-To:" header set to comp.lang.perl.misc.]

luser-ex-troll said:
#!/usr/bin/perl

Ask for all the help you can get:

    use strict;
    use warnings;
if ($#ARGV == -1) { $ARGV[0] = "addr.csv"; } #default argument

    $ARGV[0] = "addr.csv" unless defined $ARGV[0]; # default argument
while(<>) {
    chop;

chop() was how we removed newlines in the mid-90s.

chomp() is how we remove newlines nowadays.
    s/^"/\{\(/;
    s/","/\)\(/g;
    s/"$/\)\}/;

The replacement part of s/PATTERN/REPLACEMENT/ is a string.

None of those backslashed characters are special in strings,
so none of those backslashes are needed.

    s/^"/{(/;
    s/","/)(/g;
    s/"$/)}/;

Excellent. Thank you.
I was transcribing my memory of vi substitutions
while simultaneously relearning perl. It went though
some very ugly stages.

lxt
 
T

Tim McDaniel

Ask for all the help you can get:

use strict;
use warnings;

Or, better, add -w ot the #!-line...
if ($#ARGV == -1) { $ARGV[0] = "addr.csv"; } #default argument
$ARGV[0] = "addr.csv" unless defined $ARGV[0]; # default argument

I would write

@ARGV = "addr.csv" unless @ARGV;

I would write

@ARGV = ('addr.csv') if @ARGV == 0;

The parens don't actually cause a list context, but they're visually
reminiscent. In C, where {...} was allowed but not required around
one statement, I used {...} anyway.

I use '...' unless I need variable interpolation.
 
A

A. Sinan Unur

(e-mail address removed) (Tim McDaniel) wrote in
#!/usr/bin/perl

Ask for all the help you can get:

use strict;
use warnings;

Or, better, add -w ot the #!-line...
if ($#ARGV == -1) { $ARGV[0] = "addr.csv"; } #default argument
$ARGV[0] = "addr.csv" unless defined $ARGV[0]; # default
argument

I would write

@ARGV = "addr.csv" unless @ARGV;

I would write

@ARGV = ('addr.csv') if @ARGV == 0;


I would write:

@ARGV = qw( addr.csv ) unless @ARGV;

Sinan

--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
I

Ilya Zakharevich

Ok, I'll bite: How is -w better than "use warnings"?

IMO, `no warnings' is quite use()ful, but `use warnings' is absolutely
use()less.

Just try removing -w from

perl -we "sub a{print shift}" -e "use warnings; a my $x"

(I pretend I forgot to initialize $x, and pass it to a function in a
different module.)

Hope this helps,
Ilya
 
J

John W. Krahn

Ilya said:
IMO, `no warnings' is quite use()ful, but `use warnings' is absolutely
use()less.

Just try removing -w from

perl -we "sub a{print shift}" -e "use warnings; a my $x"

perl -e "sub a{print shift}" -e "use warnings; a my $x"

Or is that not what you meant?



John
 
P

Peter J. Holzer

IMO, `no warnings' is quite use()ful, but `use warnings' is absolutely
use()less.

Just try removing -w from

perl -we "sub a{print shift}" -e "use warnings; a my $x"

% perl -e 'use warnings; sub a{print shift}' -e 'use warnings; a my $x'
Use of uninitialized value within @_ in print at -e line 1.

Yes, "use warnings" needs to be in every module. It usually is, which
means that you get warnings even if you don't use -w.

hp
 
I

Ilya Zakharevich

% perl -e 'use warnings; sub a{print shift}' -e 'use warnings; a my $x'
Use of uninitialized value within @_ in print at -e line 1.

Not applicable - you do not have control over "the first -e". It is
one of hundreds somebody else's modules your script is using...
Yes, "use warnings" needs to be in every module.

No. Just use -w. It would just work.

And cannot be in ANY portable enough module - this would break
compatibility with pre-5.6.0...

Hope this helps,
Ilya
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,233
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top