Softpanorama

May the source be with you, but remember the KISS principle ;-)
Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and  bastardization of classic Unix

Perl subroutines and functions

 News

Best Books

Recommended Links Perl substr function Perl index and rindex built-in functions Perl Split function sprintf in Perl

Perl uc, lc, ucfirst and lcfirst functions

grep & map Perl tr function sort defined Pack/Unpack   Using Perl Chr() and Ord() Functions chr function

Namespaces

Debugging

Perl modules

Perl Warts

Perl philosophy and history Tips Humor Etc

Introduction

The art of decomposition of a program into a set of functions is a pretty tricky are. One of the first discussion belongs to Parnas. He tried to demonstrate that it is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchart or program text (see "On the Criteria To Be Used in Decomposing Systems into Modules" published by the Communications of the ACM.). But after almost 30 years after the publication of the paper his suggestions looks somewhat naive (all he proposed is some lexical analysis of the sentences). In reality the creation of subroutines can be top-down or bottom up. In top down approach this is a process of factorization when you find repeatable patterns in programming code and generalize them into subroutine. In bottom up approach you create some abstract machine with higher level operations represented by subroutines and then try to write your solution in term of those abstract higher level operations (modifying and tuning them to the problem as your understanding of the task in hand improves). Parnas made a good point that the programmer who knows data structures and algorithms well is better than programmer who do not -- the former is able to approach problems from several paradigms and, for example, compiler construction is one such very powerful paradigm that can be used. Also see Summary of Design Readings for a short abstract and An Integrated Representation for Software Development and Discovery for a useful discussion).

Some subroutines are almost always present in most programs. For example the subroutine that prints and/or writes to a log file a warning or an error message is a typical example of "unique" subroutines. Die in Perl is an example of a primitive solution of this program within the language framework. Another one is the subroutine for analysis of input arguments passed to the program. Perl standard modules provide several solution to this problem.

In the past there was a special area computer science called modular programming that tried to study this program and refine the language features that made decomposition of the problem into subroutines easier and created subroutines less dependent upon each other. The idea of namespaces as a very important component of modularization came out of this research. It was the dominant approach to the "programming in large" before OO became fashionable.

Generally you want to organize your code into pieces that are easy to understand and work with and that are more or less separate from each other and communicate only using minimum number of variables. In practice, when you create your program from a simple prototype into full-blown production program, subroutines are often an afterthought because in a process of making the program more complex you notice that two fragments of code are similar enough to factor them into subroutines. And in version three or four of five your decomposition looks so ugly that you start plan to rewrite it but postponed it until version seven because codebase became too large ;-) In general modular programming can help you to hide the details so that readers of your source code can better understand the overall structure of your program, but good decomposition for a large problem is not easy to achieve.

In bastardized form the idea of creation of the catalog of classic decompositions within the OO paradigm is present in so called "programming pattern" movement.

Overview of Literature

Perl documentation contains a section called perlsub which is authoritative for the topic and should be read first.

A good publicly available introduction can be found in Learning Perl, 3rd Edition- Chapter 4- Subroutines. It does not cover the scope rules too well, though.

The other notable free source is Subroutines and References in Perl

There are also several valuable articles


Top Visited
Switchboard
Latest
Past week
Past month

NEWS CONTENTS

Old News ;-)

[Nov 23, 2019] min, max, sum in Perl using ListUtil

See also ListMoreUtils - Provide the stuff missing in ListUtil - metacpan.org
Nov 23, 2019 | perlmaven.com
List::Util module provides a number of simple and some more complex functions that can be used on lists, anything that returns a list anything that can be seen as a list.

For example these can be used on arrays as they "return their content" in list context . min

If given a list of numbers to it, it will return the smallest number:

examples/min.pl

  1. use 5.010 ;
  2. use strict ;
  3. use warnings ;
  4. use List :: Util qw ( min );
  5. say min ( 10 , 3 , - 8 , 21 ); # -8
  6. my @prices = ( 17.2 , 23.6 , 5.50 , 74 , '10.3' );
  7. say min ( @prices ); # 5.5
  8. # Argument "2x" isn't numeric in subroutine entry at examples/min.pl line 14.
  9. say min ( 10 , 3 , '2x' , 21 ); # 2

If one of the arguments is a string that cannot be fully converted to a number automatically and if you have use warnings on as you should , then you'll see the following warnings: Argument ... isn't numeric in subroutine entry at ...

minstr

There is a corresponding function called minstr that will accept strings and sort them according to the ASCII order, though I guess it will work with Unicode as well if that's what you are feeding it.

examples/minstr.pl
  1. use 5.010 ;
  2. use strict ;
  3. use warnings ;
  4. use List :: Util qw ( minstr );
  5. say minstr ( 'f' , 'b' , 'e' ); # b

It can also accept numbers as parameters and will treat them as strings. The result might surprise you, if you are not familiar with the automatic number to string conversion of Perl, and that the string "11" is ahead of the string "2" because the comparison works character-by-character and in this case the first character of "11" is ahead of the first (and only) character of "2" in the ASCII table.

examples/minstr_numbers.pl

  1. use 5.010 ;
  2. use strict ;
  3. use warnings ;
  4. use List :: Util qw ( minstr );
  5. say minstr ( 2 , 11 , 99 ); # 11

After all internally it uses the lt operator.

max

Similar to min just returns the biggest number.

maxstr

Similar to minstr , returns the biggest string in ASCII order.

sum

The sum function adds up the provided numbers and returns their sum. If one or more of the values provided is a string that cannot be fully converted to a number it will generate a warning like this: Argument ... isn't numeric in subroutine entry at ... . If the parameters of sum are empty the function returns undef . This is unfortunate as it should be 0, but in order to provide backwards compatibility, if the provided list is empty then undef is returned.

examples/sum.pl

  1. use 5.010 ;
  2. use strict ;
  3. use warnings ;
  4. use List :: Util qw ( sum );
  5. say sum ( 10 , 3 , - 8 , 21 ); # 26
  6. my @prices = ( 17.2 , 23.6 , '1.1' );
  7. say sum ( @prices ); # 41.9
  8. my @empty ;
  9. # Use of uninitialized value in say at examples/sum.pl line 14.
  10. say sum ( @empty ); # (prints nothing)
sum0

In order to fix the above issue, that sum() return undef , in version 1.26 of the module, in 2012, a new function called sum0 was introduced that behaves exactly like the sum function, but returns 0 if no values was supplied.

examples/sum0.pl

  1. use 5.010 ;
  2. use strict ;
  3. use warnings ;
  4. use List :: Util qw ( sum0 );
  5. say sum0 ( 10 , 3 , - 8 , 21 ); # 26
  6. my @prices = ( 17.2 , 23.6 , '1.1' );
  7. say sum0 ( @prices ); # 41.9
  8. my @empty ;
  9. say sum0 ( @empty ); # 0
product

The product function multiplies its parameters. As this function is newer it was not constrained with backward compatibility issues so if the provided list is empty, the returned value will be 1.

examples/product.pl

  1. use 5.010 ;
  2. use strict ;
  3. use warnings ;
  4. use List :: Util qw ( product );
  5. my @interest = ( 1.2 , 2.6 , 4 , '1.3' );
  6. say product ( @interest ); # 16.224
  7. my @empty ;
  8. say product ( @empty ); # 1
Other functions of List::Util

The module has a number of other functions that were used in various other articles:

first

first returns the first element from a list that satisfies the given condition. For examples on how to use it an why is it good check out the articles Fast lookup by name or by date - Array - Hash - Linked List and Search for hash in an array of hashes .

any

The any function will return true if any of the given values satisfies the given condition. It is shown in the article Filtering values using Perl grep as a better solution.

It is also used in the example showing how to create a testing module and how to implement 'is_any' to test multiple expected values .

all

The all function will return true if all the supplied values satisfy the given condition. It can be seen in the article Check several regexes on many strings .

reduce

The reduce function might be familiar to you from the MapReduce programming model that was lauded around "BigData". It makes it provides a way to summarize data in an easy way. Implementing factorial in Perl - n! is a good and simple example. It is also used in the Fast lookup by name or by date - Array - Hash - Linked List article.

[Sep 30, 2019] int - perldoc.perl.org

Sep 30, 2019 | perldoc.perl.org

[Sep 19, 2019] Min and max functions in Perl by Tim

Feb 01, 2012 | timmurphy.org

Posted: 1st February 2012 by Tim in Perl

Tags: list , math , max , min , Perl , script 3

Min and max functions are available in perl, but you need to load them first. To do this, add

use List::Util qw[min max];

to the top of the script. These functions take a list of numbers and return the min/max of that list. The list can have 2 numbers or 100 – it doesn't matter:

use List::Util qw[min max];

print min(1,3) . "\n";
print max(1,2,3,4,5) . "\n";
print min(1) . "\n";

[Sep 19, 2019] Luke's Thought Dump Cute Perl Gem to Get the Minimum-Maximum Value

Notable quotes:
"... the comparison operators return 1 or 0 for true and false, respectively, which are then used by this code to index the array ref. ..."
Sep 19, 2019 | lukesthoughtdump.blogspot.com

Sunday, August 2, 2009 Cute Perl Gem to Get the Minimum/Maximum Value Saw this little nugget on #perl@irc.perl.org the other night. It determines the minimum of two values:

[$b, $a]->[$a <= $b]
It takes advantage of the fact that Perl doesn't have a Boolean return type for true or false, so the comparison operators return 1 or 0 for true and false, respectively, which are then used by this code to index the array ref.

To get the maximum of the two values, just flip the operator to >= Posted by Luke at

Labels: hacks , perl

[Sep 19, 2019] List::MoreUtils's minmax is more efficient when you need both the min and the max (because it does fewer comparisons).

Notable quotes:
"... List::MoreUtils's minmax is more efficient when you need both the min and the max (because it does fewer comparisons). ..."
Sep 19, 2019 | stackoverflow.com

List::Util's min and max are fine,

use List::Util qw( min max );
my $min = min @numbers;
my $max = max @numbers;

But List::MoreUtils's minmax is more efficient when you need both the min and the max (because it does fewer comparisons).

use List::MoreUtils qw( minmax );
my ($min, $max) = minmax @numbers;

List::Util is part of core, but List::MoreUtils isn't.

--ikegami

[Dec 20, 2017] chomp - perldoc.perl.org

Notable quotes:
"... Note that parentheses are necessary ..."
Dec 20, 2017 | perldoc.perl.org

chomp Perl functions A-Z | Perl functions by category | The 'perlfunc' manpage

[Nov 23, 2017] A Perl array 'contains' example by Alvin Alexander

Jun 03, 2016 | alvinalexander.com

Perl array FAQ: How can I test to see if a Perl array already contains a given value? (Also written as, How do I search an array with the Perl grep function?)

I use the Perl grep function to see if a Perl array contains a given entry. For instance, in this Perl code:

if ( grep { $_ eq $clientAddress} @ip_addresses ) {
  # the array already contains this ip address; skip it this time
  next;
} else {
  # the array does not yet contain this ip address; add it
  push @ip_addresses, $clientAddress;
}

I'm testing to see if the Perl array "@ip_addresses" contains an entry given by the variable "$clientAddress".

Just use this Perl array search technique in an "if" clause, as shown, and then add whatever logic you want within your if and else statements. In this case, if the current IP address is not already in the array, I add it to the array in the "else" clause, but of course your logic will be unique.

An easier "Perl array contains" example

If it's easier to read without a variable in there, here's another example of this "Perl array contains" code:

if ( grep { $_ eq '192.168.1.100'} @ip_addresses )

if you'd like more details, I didn't realize it, but I have another good example out here in my " Perl grep array tutorial ." (It's pretty bad when you can't find things on your own website.)

[Nov 22, 2017] Perl grep array FAQ - How to search an array-list of strings alvinalexander.com

Nov 22, 2017 | alvinalexander.com

Perl grep array FAQ - How to search an array/list of strings By Alvin Alexander. Last updated: June 3 2016 Perl "grep array" FAQ: Can you demonstrate a Perl grep array example? (Related: Can you demonstrate how to search a Perl array?)

A very cool thing about Perl is that you can search lists (arrays) with the Perl grep function. This makes it very easy to find things in large lists -- without having to write your own Perl for/foreach loops.

A simple Perl grep array example (Perl array search)

Here's a simple Perl array grep example. First I create a small string array (pizza toppings), and then search the Perl array for the string "pepper":

# create a perl list/array of strings
@pizzas = qw(cheese pepperoni veggie sausage spinach garlic);

# use the perl grep function to search the @pizzas list for the string "pepper"
@results = grep /pepper/, @pizzas;

# print the results
print "@results\n";

As you might guess from looking at the code, my @results Perl array prints the following output:

pepperoni
Perl grep array - case-insensitive searching

If you're familiar with Perl regular expressions, you might also guess that it's very easy to make this Perl array search example case-insensitive using the standard i operator at the end of my search string.

Here's what our Perl grep array example looks like with this change:

@results = grep /pepper/i, @pizzas;
Perl grep array and regular expressions (regex)

You can also use more complex Perl regular expressions (regex) in your array search. For instance, if for some reason you wanted to find all strings in your array that contain at least eight consecutive word characters, you could use this search pattern:

@results = grep /\w{8}/, @pizzas;

That example results in the following output:

pepperoni
Perl grep array - Summary

I hope this Perl grep array example (Perl array search example) has been helpful. For related Perl examples, see the Related block on this web page, or use the search form on this website. If you have any questions, or better yet, more Perl array search examples, feel free to use the Comments section below.

[Nov 22, 2017] perl - How can I also get an element's index when I grep through an array - Stack Overflow

Nov 22, 2017 | stackoverflow.com

Learn more up vote down vote favorite

Geo ,Jun 10, 2010 at 16:39

Let's say I have this list:
my @list = qw(one two three four five);

and I want to grab all the elements containing o . I'd have this:

my @containing_o = grep { /o/ } @list;

But what would I have to do to also receive an index, or to be able to access the index in grep 's body?

,

my @index_containing_o = grep { $list[$_] =~ /o/ } 0..$#list;  # ==> (0,1,3)

my %hash_of_containing_o = map { $list[$_]=~/o/?($list[$_]=>$_):() } 0..$#list
            # ==> ( 'one' => 0, 'two' => 1, 'four' => 3 )

[Nov 22, 2017] Perl Searching for item in an Array - Stack Overflow

Nov 22, 2017 | stackoverflow.com

Perl: Searching for item in an Array Ask Question up vote down vote favorite 1

Majic Johnson ,Apr 20, 2012 at 4:53

Given an array @A we want to check if the element $B is in it. One way is to say this:
Foreach $element (@A){
    if($element eq $B){
        print "$B is in array A";
    }
}

However when it gets to Perl, I am thinking always about the most elegant way. And this is what I am thinking: Is there a way to find out if array A contains B if we convert A to a variable string and use

index(@A,$B)=>0

Is that possible?

cHao ,Apr 20, 2012 at 4:55

grep { $_ eq $B } @A ? – cHao Apr 20 '12 at 4:55

daxim ,Apr 20, 2012 at 7:06

Related: stackoverflow.com/questions/7898499/ stackoverflow.com/questions/3086874/daxim Apr 20 '12 at 7:06

Nikhil Jain ,Apr 20, 2012 at 5:49

There are many ways to find out whether the element is present in the array or not:
  1. Using foreach
    foreach my $element (@a) {
        if($element eq $b) {
           # do something             
           last;
        }
    }
    
  2. Using Grep:
    my $found = grep { $_ eq $b } @a;
    
  3. Using List::Util module
    use List::Util qw(first); 
    
    my $found = first { $_ eq $b } @a;
    
  4. Using Hash initialised by a Slice
    my %check;
    @check{@a} = ();
    
    my $found = exists $check{$b};
    
  5. Using Hash initialised by map
    my %check = map { $_ => 1 } @a;
    
    my $found = $check{$b};
    

pilcrow ,May 2, 2012 at 19:56

The List::Util::first() example is (potentially) subtly incorrect when searching for false values, since $found will also evaluate false. ( die unless $found ... oops!) List::MoreUtils::any does the right thing here. – pilcrow May 2 '12 at 19:56

yazu ,Apr 20, 2012 at 4:56

use 5.10.1;

$B ~~ @A and say '$B in @A';

brian d foy ,Apr 20, 2012 at 13:07

You have to be very careful with this because this distributes the match over the elements. If @A has an array reference element that contains $B, this will still match even though $B isn't a top level element of @A. The smart match is fundamentally broken for this and many other reasons. – brian d foy Apr 20 '12 at 13:07

obmib ,Apr 20, 2012 at 5:51

use List::AllUtils qw/ any /;
print "\@A contains $B" if any { $B eq $_ } @A;

bvr ,Apr 20, 2012 at 7:43

I would recommend first in this case, as it does not have to traverse whole array. It can stop when item is found. – bvr Apr 20 '12 at 7:43

brian d foy ,Apr 20, 2012 at 13:10

any can stop too because it needs only one element to be true. – brian d foy Apr 20 '12 at 13:10

pilcrow ,May 3, 2012 at 1:38

Beware that first can also return a false value if it finds, e.g., "0", which would confound the example given in this answer. any has the desired semantics. – pilcrow May 3 '12 at 1:38

[Nov 16, 2017] perl - Grep Two Dimensional Array - Stack Overflow

Nov 16, 2017 | stackoverflow.com

Grep Two Dimensional Array Ask Question up vote down vote favorite

Taranasaur ,yesterday

Since this is not a question directly covered here, thought best I ask and answer it.

I had an issue where I wanted to add a node name to a list only if the same node doesn't already exist. The array was built using:

push (@fin_nodes, [$node, $hindex, $e->{$hip}->{FREQ}]);

So given when given array (@fin_nodes) that looks like:

$VAR1 = [
      'first-node',
      '4',
      3
    ];
$VAR2 = [
      'second-node',
      '1',
      3
    ];
$VAR3 = [
      'another-node',
      '1',
      5
    ];
$VAR4 = [
      'some-node',
      '0',
      5
    ];

To do a grep on this the following works:

my @match = grep { grep { $_ =~ $node } @$_ } @fin_nodes;

So given a $node "second-node" the above statement will return @match as:

$VAR1 = [
  'second-node',
  '1',
  3
];

Sobrique ,yesterday

Why not use a hash instead? – Sobrique yesterday

ysth ,yesterday

when dumping an array, do Data::Dumper::Dumper(\@array), not ...(@array). if passed a list, Dumper dumps each element individually, which is not what you want here – ysth yesterday

,

I would say "don't" and instead:
my %fin_nodes;
$fin_nodes{$node} = [$hindex, $e->{$hip}->{FREQ}]);

And then you can simply if ($fin_nodes{$node}) {

Failing that though - you don't need to grep every element, as your node name is always first.

So:

 my @matches = grep { $_ -> [0] eq $node } @fin_nodes;

eq is probably a better choice than =~ here, because the latter will substring match. (And worse, can potentially do some quite unexpected things if you've metacharacters in there, since you're not quoting or escaping them)

E.g. in your example - if you look for a node called "node" you'll get multiple hits.

Note - if you're only looking for one match, you can do something like:

my ( $first_match ) =  grep { $_ -> [0] eq $node } @fin_nodes;

This will just get you the first result, and the rest will be discarded. (Which isn't too efficient, because grep will continue to iterate the whole list).

Taranasaur ,yesterday

Your last statement was on point, I only needed one match. Then before pushing a node onto fin_nodes this was enough: "if (!$first_match)" – Taranasaur yesterday

Borodin ,yesterday

@Taranasaur: I think you missed the point of Sobrique's answer. A hash is by far the better choice for this, and you can simply write $fin_nodes{$node} //= [ $hindex, $e->{$hip}{FREQ} ] and avoid the need for any explicit test altogether. – Borodin yesterday

Taranasaur ,yesterday

@Borodin, no I do get Sobrique's point. The fin_nodes array is being used for a simple list function that another method is already using quite happily in my program. I will at some point go back and create a hash as there might be more attributes I'll need to include in that array/hash – Taranasaur yesterday

ysth ,yesterday

"because the latter will substring match" assuming no regex metacharacters; if there are any, it will be even worse – ysth yesterday

Sobrique ,yesterday

Good point @ysth I will add that. – Sobrique yesterday

[Nov 15, 2017] Strange behaviour of tr function in case the set1 is supplied by a variable

Notable quotes:
"... Characters may be literals or any of the escape sequences accepted in double-quoted strings. But there is no interpolation, so "$" and "@" are treated as literals. ..."
Nov 15, 2017 | perlmonks.com
Nov 16, 2017 at 02:50 UTC ( # 1203542 = perlquestion : print w/replies , xml ) Need Help??

likbez has asked for the wisdom of the Perl Monks concerning the following question:

Looks like in tr function a scalar variable is accepted as the first argument, but is not compiled properly into set of characters

use strict;
use warnings;

my $str1 = 'abcde';
my $str2 = 'eda';
my $diff1 = 0;

eval "\$diff1=\$str1=~tr/$str2//";

print "diff1: $diff1\n";

$ perl foo.pl
diff1: 3

[download]

This produces in perl 5, version 26:

Test 1: strait set diff1=0, diff2=3
Test 2: complement set diff1=5, diff2=2

[download]

Obviously only the second result in both tests is correct. Looks like only explicitly given first set is correctly compiled. Is this a feature or a bug ?

Athanasius (Chancellor) on Nov 16, 2017 at 03:08 UTC

Re: Strange behaviour of tr function in case the set1 is supplied by a variable

Hello likbez ,

The transliteration operator tr/SEARCHLIST/REPLACEMENTLIST/ does not interpolate its SEARCHLIST , so in your first example the search list is simply the literal characters , , , , . See Quote and Quote like Operators .

Hope that helps,

Athanasius  < contra mundum Iustus alius egestas vitae, eros Piratica,

roboticus (Chancellor) on Nov 16, 2017 at 03:08 UTC

Re: Strange behaviour of tr function in case the set1 is supplied by a variable

likbez :

Feature, per the tr docs

Characters may be literals or any of the escape sequences accepted in double-quoted strings. But there is no interpolation, so "$" and "@" are treated as literals.

A hyphen at the beginning or end, or preceded by a backslash is considered a literal. Escape sequence details are in the table near the beginning of this section.

So if you want to use a string to specify the values in a tr statement, you'll probably have to do it via a string eval:

$ cat foo.pl use strict; use warnings;
my $str1 = 'abcde';
my $str2 = 'eda';
my $diff1 = 0;
eval "\$diff1=\$str1=~tr/$str2//";
print "diff1: $diff1\n";
perl foo.pl diff1: 3

[download]

... roboticus

When your only tool is a hammer, all problems look like your thumb.

Anonymous Monk on Nov 16, 2017 at 03:09 UTC

Re: Strange behaviour of tr function in case the set1 is supplied by a variable

Looks like in tr function a scalar variable is accepted as the fist argument, but is not compiled properly into set of characters

:)

you're guessing how tr /// works, you're guessing it works like s/// or m///, but you can't guess , it doesn't work like that, it doesn't interpolate variables, read perldoc -f tr for the details

likbez !!! on Nov 16, 2017 at 04:41 UTC

Re^2: Strange behaviour of tr function in case the set1 is supplied by a variable
you're guessing how tr/// works, you're guessing it works like s/// or m///, but you can't guess , it doesn't work like that, it doesn't interpolate variables, read perldoc -f tr for the details
Houston, we have a problem ;-)

First of all that limits tr area of applicability.

The second, it's not that I am guessing, I just (wrongly) extrapolated regex behavior on tr, as people more often use regex then tr. Funny, but searching my old code and comments in it is clear that I remembered (probably discovered the hard way, not by reading the documentation ;-) this nuance several years ago. Not now. Completely forgotten. Erased from memory. And that tells you something about Perl complexity (actually tr is not that frequently used by most programmers, especially for counting characters).

And that's a real situation, that we face with Perl in other areas too (and not only with Perl): Perl exceeds typical human memory capacity to hold the information about the language. That's why we need "crutches" like strict.

You simply can't remember all the nuances of more then a dozen of string-related built-in functions, can you? You probably can (and should) for index/rindex and substr , but that's about it.

So here are two problems here:

1. Are / / strings uniformly interpreted in the language, or there is a "gotcha" because they are differently interpreted by tr (essentially as a single quoted strings) and regex (as double quoted strings) ?

2. If so, what is the quality of warnings about this gotcha? There is no warning issued, if you use strict and warnings. BTW, it looks like $ can be escaped:

main::(-e:1): 0
DB<5> $_='\$bba\$'
DB<6> tr/\$/?/
DB<7> print $_
\?bba\?

[download]

Right now there is zero warnings issued with use strict and use warnings enabled. Looks like this idea of using =~ for tr was not so good, after all. Regular syntax like tr(set1, set2) would be much better. But it's to late to change and now we need warnings to be implemented.

likbez !!! on Nov 16, 2017 at 03:10 UTC

Re: Strange behaviour of tr function in case the set1 is supplied by a variable

With eval statement works correctly. So it looks like $ is treated by tr as a regular symbol and no warnings are issued.

$statement='$diff1=$str1'."=~tr/$str2//;";
eval($statement);
print "With eval: diff1=$diff1\n";
[download]

that will produce:

With eval: diff1=3

ww (Archbishop) on Nov 16, 2017 at 03:16 UTC

Re: Strange behaviour of tr function in case the set1 is supplied by a variable

Same results in AS 5.24 under Win7x64.

Suspected problem might have arisen from lack of strict, warnings. Wrong, same results BUT using both remains a generally good idea.

Also wondered if compiling (with qr/.../ ) might change the outcome. Wrong again, albeit with variant (erroneous) output.

Correct me if I'm wrong, guessing that "strait" is a typo or personal shortening of "straight."

Update: Now that I've seen earlier replies... ouch, pounding forehead into brick wall!

[Nov 08, 2017] In Perl, how can I concisely check if a $variable is defined and contains a non zero length string?

Nov 08, 2017 | stackoverflow.com

Jessica , Sep 26, 2009 at 0:23

I currently use the following Perl to check if a variable is defined and contains text. I have to check defined first to avoid an 'uninitialized value' warning:
if (defined $name && length $name > 0) {
    # do something with $name
}

Is there a better (presumably more concise) way to write this?

brian d foy ,Sep 26, 2009 at 19:27

You often see the check for definedness so you don't have to deal with the warning for using an undef value (and in Perl 5.10 it tells you the offending variable):
 Use of uninitialized value $name in ...

So, to get around this warning, people come up with all sorts of code, and that code starts to look like an important part of the solution rather than the bubble gum and duct tape that it is. Sometimes, it's better to show what you are doing by explicitly turning off the warning that you are trying to avoid:

 {
 no warnings 'uninitialized';

 if( length $name ) {
      ...
      }
 }

In other cases, use some sort of null value instead of the data. With Perl 5.10's defined-or operator , you can give length an explicit empty string (defined, and give back zero length) instead of the variable that will trigger the warning:

 use 5.010;

 if( length( $name // '' ) ) {
      ...
      }

In Perl 5.12, it's a bit easier because length on an undefined value also returns undefined . That might seem like a bit of silliness, but that pleases the mathematician I might have wanted to be. That doesn't issue a warning, which is the reason this question exists.

use 5.012;
use warnings;

my $name;

if( length $name ) { # no warning
    ...
    }

rjbs , Jul 9, 2014 at 17:14

Also, in v5.12 and later, length undef returns undef, instead of warning and returning 0. In boolean context, undef is just as false as 0, so if you're targeting v5.12 or later, you can just write if (length $name) { ... }rjbs Jul 9 '14 at 17:14

Adam Bellaire ,Sep 26, 2009 at 0:44

As mobrule indicates, you could use the following instead for a small savings:
if (defined $name && $name ne '') {
    # do something with $name
}

You could ditch the defined check and get something even shorter, e.g.:

if ($name ne '') {
    # do something with $name
}

But in the case where $name is not defined, although the logic flow will work just as intended, if you are using warnings (and you should be), then you'll get the following admonishment:

Use of uninitialized value in string ne

So, if there's a chance that $name might not be defined, you really do need to check for definedness first and foremost in order to avoid that warning. As Sinan Ünür points out, you can use Scalar::MoreUtils to get code that does exactly that (checks for definedness, then checks for zero length) out of the box, via the empty() method:

use Scalar::MoreUtils qw(empty);
if(not empty($name)) {
    # do something with $name 
}

Sinan Ünür ,Sep 26, 2009 at 10:07

First, since length always returns a non-negative number,
if ( length $name )

and

if ( length $name > 0 )

are equivalent.

If you are OK with replacing an undefined value with an empty string, you can use Perl 5.10's //= operator which assigns the RHS to the LHS unless the LHS is defined:

#!/usr/bin/perl

use feature qw( say );
use strict; use warnings;

my $name;

say 'nonempty' if length($name //= '');
say "'$name'";

Note the absence of warnings about an uninitialized variable as $name is assigned the empty string if it is undefined.

However, if you do not want to depend on 5.10 being installed, use the functions provided by Scalar::MoreUtils . For example, the above can be written as:

#!/usr/bin/perl

use strict; use warnings;

use Scalar::MoreUtils qw( define );

my $name;

print "nonempty\n" if length($name = define $name);
print "'$name'\n";

If you don't want to clobber $name , use default .

DVK , Sep 26, 2009 at 15:19

+1 for "//=" mention (how'd I know that'd be Sinan's answer :) – DVK Sep 26 '09 at 15:19

brian d foy , Sep 26, 2009 at 19:16

I wouldn't use //= in this case since it changes the data as a side effect. Instead, use the slightly shorter length( $name // '' ) . – brian d foy Sep 26 '09 at 19:16

Sinan Ünür , Sep 26, 2009 at 20:15

@brian d'foy I think it depends on what is being done in the function. – Sinan Ünür Sep 26 '09 at 20:15

Chris Lutz , Sep 28, 2009 at 6:11

+1 The // and //= operators are possibly the most useful specialized operators in existence. – Chris Lutz Sep 28 '09 at 6:11

brian d foy , Aug 29, 2015 at 1:44

As @rjbs pointed out in my answer, with v5.12 and later length can now return something that is not a number (but not NaN ;) – brian d foy Aug 29 '15 at 1:44

Gaurav ,Sep 28, 2009 at 6:29

In cases where I don't care whether the variable is undef or equal to '' , I usually summarize it as:
$name = "" unless defined $name;
if($name ne '') {
  # do something with $name
}

Chris Lutz , Sep 28, 2009 at 6:31

In Perl 5.10, this can be shortened to $name //= ""; which is exactly what Sinan posted. – Chris Lutz Sep 28 '09 at 6:31

RET , Sep 28, 2009 at 7:16

And even if you don't have perl 5.10, you can still write $name ||= "";RET Sep 28 '09 at 7:16

brian d foy , Sep 29, 2009 at 4:25

@RET: you can't use the || operator here since it replaces the string '0' with ''. You have to check if it is defined, not true. – brian d foy Sep 29 '09 at 4:25

Gaurav , Sep 29, 2009 at 4:27

Chris, RET: Yup, I know. I was specifically trying to suggest that if Jessica was not concerned with the difference between undef and "" , she should just change one to the other and use a single test. This won't work in the general case, for which the other solutions posted are way better, but in this specific case leads to neat code. Should I rephrase my answer to make this clearer? – Gaurav Sep 29 '09 at 4:27

mob ,Sep 26, 2009 at 0:29

You could say
 $name ne ""

instead of

 length $name > 0

brian d foy , Sep 26, 2009 at 19:20

This will still give you a warning. The reason people check definedness first is to avoid the 'uninitialized value' warning. – brian d foy Sep 26 '09 at 19:20

daotoad ,Sep 26, 2009 at 1:33

It isn't always possible to do repetitive things in a simple and elegant way.

Just do what you always do when you have common code that gets replicated across many projects:

Search CPAN, someone may have already the code for you. For this issue I found Scalar::MoreUtils .

If you don't fined something you like on CPAN, make a module and put the code in a subroutine:

package My::String::Util;
use strict;
use warnings;
our @ISA = qw( Exporter );
our @EXPORT = ();
our @EXPORT_OK = qw( is_nonempty);

use Carp  qw(croak);

sub is_nonempty ($) {
    croak "is_nonempty() requires an argument" 
        unless @_ == 1;

    no warnings 'uninitialized';

    return( defined $_[0] and length $_[0] != 0 );
}

1;

=head1 BOILERPLATE POD

blah blah blah

=head3 is_nonempty

Returns true if the argument is defined and has non-zero length.    

More boilerplate POD.

=cut

Then in your code call it:

use My::String::Util qw( is_nonempty );

if ( is_nonempty $name ) {
    # do something with $name
}

Or if you object to prototypes and don't object to the extra parens, skip the prototype in the module, and call it like: is_nonempty($name) .

Zoran Simic , Sep 26, 2009 at 4:03

Isn't this like using a hammer to kill a fly? – Zoran Simic Sep 26 '09 at 4:03

Sinan Ünür , Sep 26, 2009 at 7:05

@Zoran No. Factoring code out like this beats having a complicated condition replicated in many different places. That would be like using pinpricks to kill an elephant. @daotoad: I think you should shorten your answer to emphasize the use of Scalar::MoreUtils . – Sinan Ünür Sep 26 '09 at 7:05

Adam Bellaire , Sep 26, 2009 at 11:45

@Zoran: Scalar::MoreUtils is a very lightweight module with no dependencies. Its semantics are also well known. Unless you are allergic to CPAN, there's not much reason to avoid using it. – Adam Bellaire Sep 26 '09 at 11:45

daotoad , Sep 28, 2009 at 7:35

@Chris Lutz, yeah, I shouldn't. But prototypes are semi-broken--there are easy ways to break prototype enforcement. For example, crappy and/or outdated tutorials continue to encourage the use of the & sigil when calling functions. So I tend not to rely on prototypes to do all the work. I suppose I could add "and quit using the & sigil on sub calls unless you really mean it" to the error message. – daotoad Sep 28 '09 at 7:35

brian d foy , Sep 28, 2009 at 18:52

It's easier to think about prototypes as hints to the perl compiler so it knows how to parse something. They aren't there to validate arguments. They may be broken in terms of people's expectations, but so many things are. :) – brian d foy Sep 28 '09 at 18:52

Puriney ,Jan 28, 2014 at 22:02

my %hash ; 
$hash{"what"} = "What"; 
$hash{"how"} = "How"; 
my $word = $hash{"now"}; 
print $word; 
if (! $word) {
    print "Catch Ya\n"; 
}
else {
    print $word ; 
}

Dave Sherohman ,Sep 26, 2009 at 10:04

How about
if (length ($name || '')) {
  # do something with $name
}

This isn't quite equivalent to your original version, as it will also return false if $name is the numeric value 0 or the string '0' , but will behave the same in all other cases.

In perl 5.10 (or later), the appropriate approach would be to use the defined-or operator instead:

use feature ':5.10';
if (length ($name // '')) {
  # do something with $name
}

This will decide what to get the length of based on whether $name is defined, rather than whether it's true, so 0/ '0' will handle those cases correctly, but it requires a more recent version of perl than many people have available.

brian d foy , Sep 26, 2009 at 19:17

Why lead off with a broken solution only to say that it is broken? – brian d foy Sep 26 '09 at 19:17

Dave Sherohman , Sep 26, 2009 at 22:20

Because, as I also mentioned, 5.10 is "a more recent version of perl than many people have available." YMMV, but "this is a 99% solution that I know you can use, but there's a better one that maybe you can use, maybe you can't" seems better to me than "here's the perfect solution, but you probably can't use it, so here's an alternative you can probably get by with as a fallback." – Dave Sherohman Sep 26 '09 at 22:20

brian d foy , Sep 28, 2009 at 6:09

Even with earlier perls you can have a working solution instead of a broken one. – brian d foy Sep 28 '09 at 6:09

Joseph ,Sep 29, 2009 at 13:23

if ($name )
{
    #since undef and '' both evaluate to false 
    #this should work only when string is defined and non-empty...
    #unless you're expecting someting like $name="0" which is false.
    #notice though that $name="00" is not false
}

; , Sep 29, 2009 at 15:20

Unfortunately this will be false when $name = 0; – user180804 Sep 29 '09 at 15:20

Joseph ,Sep 9 , 2012 at 3:39

yep, you're right – Joseph Oct 2 '09 at 9:07

[Nov 08, 2017] Skipping null/empty fields caught by split()

Jun 01, 2019 | bytes.com

sicarie

I am attempting to parse a CSV, but am not allowed to install the CSV parsing module because of "security reasons" (what a joke), so I'm attempting to use 'split' to break up a comma-delimited file.

My issue is that as soon as an "empty" field comes up (two commas in a row), split seems to think the line is done and goes to the next one.

Everything I've read online says that split will return a null field, but I don't know how to get it to go to the next element and not just skip to the next line.

Expand|Select|Wrap|Line Numbers

  1. while (<INFILE>) {
  2. # use 'split' to avoid module-dependent functionality
  3. # split line on commas, OS info in [3] (4th group, but
  4. # counting starts first element at 0)
  5. # line = <textonly>,<text+num>,<ip>,<whatIwant>,
  6. chomp($_);
  7. @a_splitLine = split (/,/, $_);
  8. # move OS info out of string to avoid accidentally
  9. # parsing over stuff
  10. $s_info = $a_splitLine[3];
Could anyone see either a better way to accomplish what I'm trying to do, or help get split to capture all the elements?

I was thinking I could run a simple substitution before parsing of a known string (something ridiculous that'll never show up in my data - like &^%$#), then split, and then when printing, if that matches the current item, just print some sort of whitespace, but that doesn't sound like the best method to me - like I'm overcomplicating it.

Jun 19 '09 # 1



Expert Mod 100+

P: 465
RonB
My issue is that as soon as an "empty" field comes up (two commas in a row), split seems to think the line is done and goes to the next one .
No it doesn't. You have a flawed impression of what's happening.

Expand|Select|Wrap|Line Numbers

  1. C:\TEMP>type test.pl
  2. #!/usr/bin/perl
  3. use strict;
  4. use warnings;
  5. use Data::Dumper;
  6. my $str = 'a,,,b,,,,6,,';
  7. my @fields = split /,/, $str;
  8. print Dumper @fields;
Expand|Select|Wrap|Line Numbers
  1. C:\TEMP>test.pl
  2. $VAR1 = 'a';
  3. $VAR2 = '';
  4. $VAR3 = '';
  5. $VAR4 = 'b';
  6. $VAR5 = '';
  7. $VAR6 = '';
  8. $VAR7 = '';
  9. $VAR8 = '6';
Expand|Select|Wrap|Line Numbers
  1. C:\TEMP>perldoc -f split
  2. split /PATTERN/,EXPR,LIMIT
  3. split /PATTERN/,EXPR
  4. split /PATTERN/
  5. split Splits the string EXPR into a list of strings and returns that
  6. list. By default, empty leading fields are preserved, and empty
  7. trailing ones are deleted. (If all fields are empty, they are
  8. considered to be trailing.)
  9. ....
  10. ....
  11. ....
Jun 19 '09 # 2

reply


Expert Mod 2.5K+

P: 4,667
sicarie

Interesting, so then how would I access the b or the 6?

  1. #!/bin/perl
  2. use strict;
  3. use warnings;
  4. use Data::Dumper;
  5. my $str = 'a,,,b,,,,6,,';
  6. my @fields = split /,/, $str;
  7. my $n = 0;
  8. print Dumper @fields;
  9. while ($fields[$n]) {
  10. print "$n: $fields[$n]\n";
  11. $n++;
  12. }
  13. print "done!\n";
Expand|Select|Wrap|Line Numbers
  1. $ ./splitTest.pl
  2. $VAR1 = 'a';
  3. $VAR2 = '';
  4. $VAR3 = '';
  5. $VAR4 = 'b';
  6. $VAR5 = '';
  7. $VAR6 = '';
  8. $VAR7 = '';
  9. $VAR8 = '6';
  10. 0: a
  11. done!
In the above, my attempt to print with a while loop stops as soon as the first empty set is reached. I'm guessing I'd have to check each one to see which are valid and which are not, but what am I looking for - null?

Jun 19 '09 # 3

reply

Expert Mod 100+

P: 465
RonB

If you know which field/index you want, then simply print that field.

If you want/need to loop over the array elements, then use a for or foreach loop, not a while loop.

Expand|Select|Wrap|Line Numbers
  1. for my $i ( 0..$#fields ) {
  2. # only print fields that have a value
  3. print "induce $i = '$fields[$i]'\n" if length $fields[$i];
  4. }
Jun 19 '09 # 4

reply


Expert Mod 2.5K+

P: 3,496
numberwhun

I have to agree with Ron. Since this is a csv file, you should already know which field is what. All you would have to do is reference it by its index. Otherwise, you can use the code above to iterate through each one and pull out the variables with values other than null.

Regards,

Jeff

Jun 20 '09 # 5

reply


Expert Mod 2.5K+

P: 4,667
sicarie

Cool, thanks. I am really only interested in one of those fields, but then have to make sure once I edit that field, I re-append all the others back on, so I will play around with that.

Thanks again!

Recommended Links

Google matched content

Softpanorama Recommended

Top articles

Sites



Etc

Society

Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy

Quotes

War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes

Bulletin:

Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law

History:

Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Haterís Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D


Copyright © 1996-2020 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to to buy a cup of coffee for authors of this site

Disclaimer:

The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: February, 29, 2020