Why does print give different output with and without newline? - arrays

I am getting two different results with and without new line character in the print statement of regular expression match. why?
$string16="abfoo bcfooo defooo ghfooo ijfoo klfooo mnfooo";
#foo=$string16=~ m/foo/g;
print(#foo);
print("\n");
$string17="abfoo bcfooo defooo ghfooo ijfoo klfooo mnfooo";
#foo=$string17=~ m/foo/g;
print(#foo."\n");
result:
foofoofoofoofoofoofoo
7

Because you are using the concatenation operator ., which forces #foo into scalar context. Arrays return their number of elements in scalar context.
Use an argument list instead of the concatenation with your print to get the list and the newline. The array #foo will be expanded to the list it contains anyway, so the newline will just be another argument to print.
print #foo, "\n";
As an alternative, you can use say, which needs to be activated with use feature 'say'. It removes the need to append newlines when printing. say is available from Perl 5.10.
use feature 'say';
say #foo;
You can also turn it on with
use v5.10;
This has nothing to do with the regular expression. It's a core behavior of Perl, and how lists in Perl work.
Here's a good explanation of what context means in Perl.

Related

Why does Powershell combines array of arrays?

I use arrays of arrays in a Powershell script, however, sometimes, my array of arrays, actually contains only one array.
For some reason, Powershell keeps replacing that array containing one array, by just one array. I don't get it, no other scripting / coding language I ever used has done that before.
Example, this is what I do not want:
PS C:\Users\> $a = #(#(123,456,789))
PS C:\Users\> $a[0]
123
This is what I want:
PS C:\Users\> $a = #(#(123,456,789), #())
PS C:\Users\> $a[0]
123
456
789
Why do I have to force an extra empty array for Powershell to consider my array of arrays as such when it only contains one array ? This is driving me nuts !
You need to put a comma as the first item:
$a = #(, #(123,456,789) )
The reason for this is that the comma is essentially the array construction parameters. This MSDN article has more information.
#() operator interpret its content as statements not as expression. Let us put explicit ;.
#(#(123,456,789;);)
What do you have here:
123,456,789 — binary comma operator create an array with three elements.
Result: array [123,456,789].
123,456,789; — as expression in this statement return collection, PowerShell enumerate this collection and write collection's elements (not collection itself) to the pipeline.
Result: three elements 123, 456 and 789 written to the pipeline.
#(123,456,789;) — array subexpression operator collect all the items written to pipeline as result of invocation of nested statements and create array from them.
Result: array [123,456,789].
#(123,456,789;); — as expression in this statement return collection, PowerShell enumerate this collection and write collection's elements (not collection itself) to the pipeline.
Result: three elements 123, 456 and 789 written to the pipeline.
#(#(123,456,789;);) — array subexpression operator collect all the items written to pipeline as result of invocation of nested statements and create array from them.
Result: array [123,456,789].
So, when you write #(collection), PowerShell return copy of collection, not collection wrapped into single element array. If you want to create array with single element, then you should use unary comma operator: ,expression. This will create single element array regardless of expression return collection or not.
Also, when you write #(a,b,c,etc), it is binary comma, who create array. Array subexpression operator just copy that array. But why do you need a copy? Is any reason, why you can not use original array? All you need for not making extra copy is just to omit # character: (a,b,c,etc).

Can a perl regex use parens but skip backreferencing on them?

I have this regex:
#disks = $sysconfig =~ /(\d+)\.\d+:(\s+[\w.\/]+){5}\s+\((\w+)\)/ig
If there were only one line that matched, I'd get something like
1835 x #array
1836 35
1837 ' 520B/sect'
1838 'KXG813JF'
It matches:
the first digits in the string
the fifth copy of the "spaces then alphanumeric-periods-and-slashes" and
the alphanumeric string at the end
I don't want to backreference #2 above and clutter my array with it, but I also don't want to write out that repeating pattern when what I've got is a more concise regex (to look at).
Is there a way to say "don't backreference this piece" or should I just deal with it when I parse the array out into something more usable by my program?
Yes, there is. Use the non-capturing group construct: (?: ... ).
You even should use this by default, unless you need backreferences or capturing.

Storing a Hash of Arrays into An Array?

I have to modify some Perl scripts for a piped run and write a wrapper script to run them with a given set of input parameters. Before I can do that, I have to understand what is going in the first program. I need help deciphering this code:
# declare and initialise an empty hash
my %to_keep= ();
# an array
#line = ('some\one', 'two', 'three', 'four');
# trim the identifier
$line[0]=~s/\/[1]$//;
# store this into an array
#{$to_keep{$line[0]}{'1'}}=($line[1],$line[2]);
print #;
I'm familiar with the perl substitute function, s///. It goes:
s/text-regex_to_be_replaced/replacement/modifier.
However, I'm not too sure what the code above is doing. If I understand correctly, it replaces every occurrence of of '\' with line[1], until the end of the string (indicated by the '$/'). Is this correct?
The other part I'm unsure about is the code below the 'store' comment. I think it's storing a hash of array into an array. Can someone explain how the code works and what it prints out given the variables? Also, how can I retrieve the data I store in the array?
Bonus question: Can someone explain how modifying a perl script for a piped run works?
thanks
hmm, this is wired.
s/\/[1]$//;
would will only match and remove /1 at the end of a string. So in your example it has no influence.
#{$to_keep{$line[0]}{'1'}}=($line[1],$line[2]);
broken down, on the left side you got
$to_keep{'some\one'}{1} which is undefined in the example! But if we say it would give you the value foo, then you take this value and replaces in to #{foo} which basically means use the value foo as the array name, hence #foo.
on the right side you save the second and third element of $line as a list into this variable name, #foo.
If we ignore the undefined and try to guess the intention, you got a script that defines its own variable names. Using the first element of list as the variable name, and setting it equal to the rest of the list

Problems with Arrays in Perl

I am new to Perl and having some difficulty with arrays in Perl. Can somebody will explain to me as to why I am not able to print the value of an array in the script below.
$sum=();
$min = 999;
$LogEntry = '';
foreach $item (1, 2, 3, 4, 5)
{
$min = $item if $min > $item;
if ($LogEntry eq '') {
push(#sum,"1"); }
print "debugging the IF condition\n";
}
print "Array is: $sum\n";
print "Min = $min\n";
The output I get is:
debugging the IF condition
debugging the IF condition
debugging the IF condition
debugging the IF condition
debugging the IF condition
Array is:
Min = 1
Shouldn't I get Array is: 1 1 1 1 1 (5 times).
Can somebody please help?
Thanks.
You need two things:
use strict;
use warnings;
at which point the bug in your code ($sum instead of #sum) should become obvious...
$sum is not the same variable as #sum.
In this case you would benefit from starting your script with:
use strict;
use warnings;
Strict forces you to declare all variables, and warnings gives warnings..
In the meantime, change the first line to:
#sum = ();
and the second-to-last line to:
print "Array is: " . join (', ', #sum) . "\n";
See join.
As others have noted, you need to understand the way Perl uses sigils ($, #, %) to denote data structures and the access of the data in them.
You are using a scalar sigil ($), which will simply try to access a scalar variable named $sum, that has nothing to do with a completely distinct array variable named #sum - and you obviously want the latter.
What confuses you is likely the fact that, once the array variable #sum exists, you can access individual values in the array using $sum[0] syntax, but here the sigil+braces ($[]) act as a "unified" syntactic constract.
The first thing you need to do (after using strict and warnings) is to read the following documentation on sigils in Perl (aside from good Perl book):
https://stackoverflow.com/a/2732643/119280 - brian d. foy's excellent summary
The rest of the answers to the same question
This SO answer
The best summary I can give you on the syntax of accessing data structures in Perl is (quoting from my older comment)
the sigil represents the amount of data from the data structure that you are retrieving ($ of 1 element, # for a list of elements, % for entire hash)
whereas the brace style represent what your data structure is (square for array, curly for hash).
As a special case, when there are NO braces, the sigil will represent BOTH the amount of data, as well as what the data structure is.
Please note that in your specific case, it's the last bullet point that matters. Since you're referring to the array as a whole, you won't have braces, and therefore the sigil will represent the data structure type - since it's an array, you must use the # sigil.
You push the values into the array #sum, then finish up by printing the scalar $sum. #sum and $sum are two completely independent variables. If you print "#sum\n" instead, you should get the output "11111".
print "Array is: $sum\n";
will print a non-existent scalar variable called $sum, not the array #sum and not the first item of the array.
If you 'use strict' it will flag the user of un-initialized variables like this.
You should definitly add use strict; and use warnings; to your script. That would have complained about the print "Array is: $sum\n"; line (among others).
And you initialize an array with my #sum=(); not with my $sum=();
Like CFL_Jeff mentions, you can't just do a quick print. Instead, do something like:
print "Array is ".join(', ',#array);
Still would like to add some details to this picture. )
See, Perl is well-known as a Very High Level Language. And this is not just because you can replace (1,2,3,4,5) with (1..5) and get the same result.
And not because you may leave your variables without (explicitly) assigning some initial values to them: my #arr is as good as my #arr = (), and my $scal (instead of my $scal = 'some filler value') may actually save you an hour or two one day. Perl is usually (with use warnings, yes) good at spotting undefined values in unusual places - but not so lucky with 'filler values'...
The true point of VHLL is that, in my opinion, you can express a solution in Perl code just like in any human language available (and some may be even less suitable for that case).
Don't believe me? Ok, check your code - or rather your set of tasks, for example.
Need to find the lowest element in a array? Or a sum of all values in array? List::Util module is to your command:
use List::Util qw( min sum );
my #array_of_values = (1..10);
my $min_value = min( #array_of_values );
my $sum_of_values = sum( #array_of_values );
say "In the beginning was... #array_of_values";
say "With lowest point at $min_value";
say "Collected they give $sum_of_values";
Need to construct an array from another array, filtering out unneeded values? grep is here to save the day:
#filtered_array = grep { $filter_condition } #source_array;
See the pattern? Don't try to code your solution into some machine-codish mumbo-jumbo. ) Find a solution in your own language, then just find means to translate THAT solution into Perl code instead. It's easier than you thought. )
Disclaimer: I do understand that reinventing the wheel may be good for learning why wheels are so useful at first place. ) But I do see how often wheels are reimplemented - becoming uglier and slower in process - in production code, just because people got used to this mode of thinking.

Selecting arrays in nicely printed format in SQL

I'm trying to select for a two dimensional array of integers, and directing the output to a file. Is there any way that I can write a postgresql statement that would make the output of the select statement nicely formatted. As in each array of integers that is an element of the 2D array is on its own line.
Right now I just get this output:
SELECT array FROM table LIMIT 1;
{{0,0,0},{1,1,1},{2,2,2},{3,3,3},{0,0,0},{1,1,1},{2,2,2},{3,3,3}
,{0,0,0},{1,1,1},{2,2,2},{3,3,3},{0,0,0},{1,1,1},{2,2,2},{3,3,3}
,{0,0,0},{1,1,1},{2,2,2},{3,3,3},{0,0,0},{1,1,1},{2,2,2},{3,3,3}}
And I would like to get something more like this:
{0,0,0}
{1,1,1}
{2,2,2}
...
I can do this after the query returns with some parsing, but if its possible to do it in Postgres itself that would be ideal.
There are several ways. One way is to cast the array to text and split it up with regexp_split_to_table().
This function is present in PostgreSQL 8.3 or later.
SELECT regexp_split_to_table(trim(my_2d_intarr::text, '{}'), '},{');
Output:
0,0,0
1,1,1
2,2,2
If you want the enclosing brackets (maybe you don't?), add them back like this:
SELECT '{' || regexp_split_to_table(trim(my_2d_intarr::text, '{}'), '},{') || '}';
Ourtput:
{0,0,0}
{1,1,1}
{2,2,2}
Alternative:
This should also work with PostgreSQL 8.2 or maybe even earlier, but I did not test that.
SELECT my_2d_int_arr_var[x:x][1:3]
FROM (SELECT generate_series(1, array_upper(my_2d_intarr, 1), 1)::int4 AS x)) x
Output:
{{0,0,0}}
{{1,1,1}}
{{2,2,2}}
(You may want to strip some curly brackets ..)
Else, I would write a plpgsql function that loops through the array. Fairly easy.
There is also the related unnest() function, but it returns a row per base element (integer in this case), so it's no use here.
One (fast!) way to output the result: COPY.

Resources