[Home]Perl

18-97-14-84.crawl.commoncrawl.org | ToothyWiki | RecentChanges | Login | Advent calendar | Webcomic

Practical Extraction and Report Language

An interpreted programming language intended mainly for text processing.

Also described as "It kinda does what you expect it to, unless you expect it to make sense"  Basically a huge number of kludges thrown together that do actually make an incredibly powerful glue for linking smaller programs together.  Extremely good at what it does.  Has recently acquired object orientation, for added obfuscation.  --Vitenka
Version 6 currently resembles a Nomic game on Steroids?. -- Senji


While musing on the name origin, DavidWaller? and I decided that it was what happened when you introduced the grit of "text-processing things we need to do" to the oysters of software developers. We thought this was a good metaphor. --CH



Nifty line of Perl code. Try to figure it out before you run it:
 $_ = 1; (1 x $_) !~ /^(11+)\1+$/ && print while $_++

I can't figure it out after I've run it. It might help if I knew more than the very, very rudiments of Perl, mind you. --CH
I now think I know roughly what it's meant to do (with the help of DavidWaller?), but we can't work out what "print while" is supposed to do. As it happens, when I ran it at work, it simply printed out 23. --CH
(MoonShadow) If it helps, print's default parameter is $_. It seems the scope of the while loop is supposed to the entire statement. print might not flush on some platforms until it encounters an end of line or the script terminates. A slightly more readable / portable version might be the following:
 $_ = 1; do { (1 x $_) !~ /^(11+)\1+$/ && print "$_\n" } while $_++

An extra belated vote of much niftiness to the author of this one...  --K



A very basic perl question...

 my $tmp = $initialvalue; # initialvalue is re-used later and shouldn't be changed
$tmp =~ s/abc/def/;
print $tmp;

In any other language I would just write "print replace($initialvalue, 'abc', 'def')" and hence three lines and a temporary variable seem very wasteful and un-perl-like.  Is there a better way? --K


MoonShadow: You'd still be using some kind of temporary storage under the hood to pass the value returned from replace to print, so there's no difference in practice. Alternative forms might be things like
 for( $initialvalue ) { local $_; s/abc/def/; print; }
or
 { local $initialvalue; $initialvalue =~ s/abc/def/; print $initialvalue; }
or some such; but I personally find yours nicer to read.




A not-so-basic perl question...

 $name =~ s/$pattern/$replace/oi;

...doesn't work correctly when the replace includes group identifiers, e.g. $replace = 'Text plus $1'.

Other suggestions online have included s/$pattern/$replace/eeoi but this complains about barewords.

Has anyone done anything like this?  The context is a regex file renamer if that makes any difference. --K

 pjt33@charis:/tmp/$ cat >test.pl
$replace='qu$1';
$text='foobarbaz';
$text =~ s/arb/$replace/oi;
print $text;
pjt33@charis:/tmp/$ perl ./test.pl
foobqu$1az

Can you post an example which demonstrates your problem? --PT
I thought he meant he wanted the variable $1 to be inserted, not the literal string "$1". BICBW. --Rachael


 #! /usr/bin/perl -w
use strict;
my $a = '"x${1}x"'; # note the nesting of single and double quotes
my $b = 'abc';
$b =~ s/(b)/eval($a)/e;
print "$b\n";

gives
 axbxc

Thanks.  I tried s/$pattern/"$replace"/ee, which I was led to believe was equivalent to the above, but I'll try again when I get into work and see what happens. --K
Turns out that I can append the quotes to the replace variable beforehand but can't add them in the regex itself.  That combined with the 'o' bug mean I now have a working function!  Thanks again :) --K



I have a script containing these lines:
my @people;
@people = XMLTree::getTextsByPath($output, 'autnresponse', 'responsedata', 'autn:field', 'autn:value');


getTextsByPath? ends with the following if-block:
if (wantarray()) {
    	print "In list context\n";
    	return @results;
} elsif (defined wantarray()) {
	print "In scalar context\n";
	return $results[0];
} else {
	print "In void context\n";
	return;  # nothing
}


And the line "In scalar context" is being printed, not "In list context", and only the first array element is being returned. Any suggestions? Thanks --Rachael

I don't see anything problematic with that in itself. What's the rest of getTextsByPath? like? Does it recurse? Does the above code work as expected if you remove all the *other* code from getTextsByPath? (except for the declaration of @results, if you're in strict mode)? - MoonShadow
getTextsByPath doesn't recurse, but it calls another function, which does. I've commented out all the other code in getTextsByPath and it still prints "In scalar context".
Are you sure the getTextsByPath? you're altering is the one that is being called? Try defining the sub in the same scope, in the same file. It may be that you're actually invoking a different piece of code that then calls the code you're looking at in scalar context and returns the result. That's about all I can think of, really. - MoonShadow
It's definitely the same one - I'm stepping into it in the debugger and seeing it's the code I've just modified. --Rachael
Ah! I've figured it out. Sorry; in stripping out irrelevant surroundings so that I could paste it into the wiki, I actually stripped out the relevant thing. The line
 @people = XMLTree::getTextsByPath?($output, 'autnresponse', 'responsedata', 'autn:field', 'autn:value');
was actually
 @people = XMLTree::getTextsByPath?($output, 'autnresponse', 'responsedata', 'autn:field', 'autn:value') || die;
which does evaluate it in scalar context. I was just mindlessly following the Perl idiom and tacking || die onto the end of everything. Oops.


 >  perl -e "open DIR, 'test'; my @a = readdir(DIR); print scalar(@a);"
0
>  ls test
a  b
What am I doing wrong? (I would expect the Perl to print 2.) --Rachael
opendir, not open. Also, you'll see 4 entries, because of . and .. - MoonShadow
Gaaaah! *kickself* Thanks. (You'd think it would warn for that (in the original full script which has -w), or is there some context where you would want to use open on a dir?) --Rachael



You'd think Perl, being interpreted, wouldn't terminate with compilation errors if they're in unreachable code, but it does. I want to do something like this:
 if ($^O eq "MSWin32")
{ WindowsOnlyFunction?();}
else
{ UnixOnlyFunction?();}
but, running it on Windows, the script fails to run because the UnixOnlyFunction? is "unimplemented".
[Apparently] Perl has something like C's #ifdef, where you can ignore whole blocks of code depending on an environment variable. That would be better than nothing, but I'd really like to do it at runtime, so that I don't have to rely on any external environment variables but can just check what platform I'm on from within the script (as in the lines quoted above). Any suggestions? --Rachael

Use eval(). --MoonShadow
Excellent, thanks. That works fine around ordinary blocks of code. It doesn't work around use statements though. --Rachael
Why not? I've used it that way. What precisely are you doing? (Of course, the scope of the use statement will be limited to the inside of the eval block, so you have to rejiggle your code accordingly...) --MoonShadow
Compilation error (on Windows) is:
 Can't locate Mail/Sendmail?.pm in @INC (@INC contains: C:/users/rchurchill/i2etest/index/bin/../lib C:/Perl?/lib  C:/Perl?/site/lib .) at C:\users\rchurchill\i2etest\index/bin/run_make_index.pl line 204.
BEGIN failed--compilation aborted at C:\users\rchurchill\i2etest\index/bin/run_make_index.pl line 204.
Code is:
 if ($windows) #$windows is defined earlier as my $windows = ($^O eq "MSWin32") ;
{
    # send mail using blat.exe
}
else
  {
    eval {
        use Mail::Sendmail;
        my %mail = ( To => join(";", @mailto), From => "$user".'@linguamatics.com',
                    Subject => "TESTS [$result] $suffix ($version)",
                    Message => $message, smtp => 'mail.linguamatics.com');
        sendmail(%mail) or warn $Mail::Sendmail::error;
    }
}

If I take out the use Mail::Sendmail line and leave the other sendmail stuff in the eval block) then it works fine on Windows (although obviously won't on Unix).

MS: change that to
 if ($windows) #$windows is defined earlier as my $windows = ($^O eq "MSWin32") ;
{
    # send mail using blat.exe
}
else
  {
    eval <<'END_OF_CODE'
        use Mail::Sendmail;
        my %mail = ( To => join(";", @mailto), From => "$user".'@linguamatics.com',
                    Subject => "TESTS [$result] $suffix ($version)",
                    Message => $message, smtp => 'mail.linguamatics.com');
        sendmail(%mail) or warn $Mail::Sendmail::error;
END_OF_CODE
    ;
}
since the block form of eval is parsed at compile time and you specifically want to delay parsing until runtime.
Yay, that works - thanks! --Rachael




Have a link to my ObfuscatedPerl page: http://www.chiark.greenend.org.uk/~sbleas/creative/obfuscatedperl/index.html



See also RegExp
CategoryAbbreviation CategoryComputing CategoryLanguage

18-97-14-84.crawl.commoncrawl.org | ToothyWiki | RecentChanges | Login | Advent calendar | Webcomic
Edit this page | View other revisions | Recently used referrers
Last edited March 11, 2008 11:40 pm (viewing revision 38, which is the newest) (diff)
Search: