How to refer GetOptions of special character? - perl

I'm using GetOptions to act as a switch in my Perl code. I have an array that needs to be separated by a special character. Currently, I can write this following code.
&GetOptions('sep:i');
if ($opt_sep) {
$sep = "\.";
} else {
$sep = "\/";
}
When I try -sep 1, my output will be Flower.Red.Small. Without this statement or -sep 0 , my output will be Flower/Red/Small. Any idea how to exactly refer to any special character which user defined to separate my output statement? The separator may be any character of:
# # ^ * & % ; -

Are you asking for the following?
my #fields = split /\Q$opt_sep/, $str;

You can use s (string) instead of i (integer). Refer to Getopt::Long:
use warnings;
use strict;
use Getopt::Long qw(GetOptions);
my %opt = (sep => '/');
GetOptions(\%opt, 'sep=s');
my #stuff = qw(Flower Red Small);
print join($opt{sep}, #stuff), "\n";
__END__
script.pl -sep /
Flower/Red/Small
script.pl -sep .
Flower.Red.Small
script.pl -sep #
Flower#Red#Small

Related

how to extract the subset from a special character string using perl

I need to get the subset of a string starting from a specific start word and end before the specified word. Store in the string variable.
Example: pre-wrap">test-for??maths/camp
I need to fetch the subset.
Expected output: test-for??maths
After: pre-wrap"> or may be starting with: test
and before: /camp
I have no clue how to achieve this in Perl.
Here is the code I tried. The output is not coming as expected:
#!/usr/bin/perl
use warnings;
use strict;
my $string = 'pre-wrap">test-for??maths/camp';
my $quoted_substring = quotemeta($string);
my ($quoted_substring1) = split('/camp*', $quoted_substring);
my (undef, $substring2) = split('>\s*', $quoted_substring1);
print $string, "\n";
print $substring2, "\n";
Output:
$ perl test.pl
pre-wrap">test-for??maths/camp
test\-for\?\?maths\ # but why this \ is coming
The following code extracts the part between $before and $after (which may contain regex metacharacters, they are treated as pure characters inside the \Q...\E expressions):
my $string = 'pre-wrap">test-for??maths/camp';
my $before = 'pre-wrap">';
my $after = '/camp';
if ($string =~ /\Q$before\E(.*?)\Q$after\E/) {
print $1; # prints 'test-for??maths'
}
pre-wrap">test-for??maths/camp is in 'd',
perl -ne '/((?<=pre-wrap">)|(?<=>)(?=test))\S+(?=\/camp)/ ; print $&' d

How to search and replace string in a file in Perl

The content of my input file is shown below:
abc\**def\ghi**\abc\!!!!!
abc\**4nfiug\frgrefd\gtefe\wf4fs**\abc\df3gwddw
abc\**eg4/refw**\abc\f3
I need to replace whatever string in between abc \ --------------\abc in my input file with ABC\CBA.
I have tried something like below to get the strings that need to be replaced. But I get stuck when I need to use the search and replace:
my $string1 = qr/abc\W+([^a]+)/;
my $string2 = map{/$string1/ => " "} #input_file; # The string that needs to be replaced
my $string3 = 'ABC\CBA' # String in that. I want it to replace to
s/$string2/$string3/g
How can I fix this?
perl -i -pe 's/this/that/g;' file1
A one-liner to fix a file:
perl -plwe 's/abc\\\K.*(?=\\abc)/ABC\\CBA/' input.txt > output.txt
Or as a script:
use strict;
use warnings;
while (<DATA>) {
s/abc\\\K.*(?=\\abc)/ABC\\CBA/;
print;
}
__DATA__
abc\**def\ghi**\abc\!!!!!
abc\**4nfiug\frgrefd\gtefe\wf4fs**\abc\df3gwddw
abc\**eg4/refw**\abc\f3
The \K (keep) escape sequence means these characters will not be removed. Similarly, the look-ahead assertion (?= ... ) will keep that part of the match. I assumed you only wanted to change the characters in between.
Instead of \K one can use a look-behind assertion: (?<=abc\\). As a personal preference, I used \K instead.
#!/usr/bin/perl
use strict;
use warnings;
open my $fh,"<", "tryit.txt" or die $!;
while (my $line = <$fh>) {
$line =~ s/(abc\\)(.*?)(\\abc)/$1ABC\\CBA$3/;
print $line;
}
gives the following with the input data.
abc\ABC\CBA\abc\!!!!!
abc\ABC\CBA\abc\df3gwddw
abc\ABC\CBA\abc\f3
If you do not want the substitution to operate on the default variable $_, you have to use the =~ operator:
#!/usr/bin/perl
use warnings;
use strict;
my #input_file = split /\n/, <<'__EOF__';
abc\**def\ghi**\abc\!!!!!
abc\**4nfiug\frgrefd\gtefe\wf4fs**\abc\df3gwddw
abc\**eg4/refw**\abc\f3
__EOF__
my $pattern = qr/abc\\.*\\abc/; # pattern to be matched
my $string2 = join "\n", #input_file; # the string that need to be replaced
my $string3 = 'ABC\CBA'; # string i that i want it to replace to
$string2 =~ s/$pattern/$string3/g;
print $string2;
To address your comment about replacing text "inplace" in the file directly, you can use the -i switch for a one-liner. In a script, you can perhaps look at using Tie::File, which allows read-write access to lines of a file as (mutable) elements in an array. To copy Mike/TLP's answer:
#!/usr/bin/perl
use strict;
use warnings;
use Tie::File;
tie my #file, "Tie::File", "tryit.txt" or die $!;
# I think you have to use $_ here (done implicitly)
while (#file) {
s/(abc\\)(.*?)(\\abc)/$1ABC\\CBA$3/;
print;
}

How to loop over each word in an argument for perl

I'd like to have a perl program that I can call with something like:
perl myProgram --input="This is a sentence"
And then have perl print the output to terminal, in this format
word1 = This
word2 = is
word3 = a
word4 = sentence
I'm usually a c/c++/java programmer, but I've been looking at perl recently, and I just can't fathom it.
Use Getopt::Long and split.
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my $input = '';
GetOptions( 'input=s' => \$input );
my $count = 0;
for (split ' ', $input) {
printf("word%d = %s\n", ++$count, $_);
}
'split' doesn't handle excess leading, trailing, and embedded spaces. Your best bet is a repeated match over non-space characters, m{\S+}gso.
The first command-line parameter is $ARGV[0]. Putting that together we have:
#! /usr/bin/perl
use strict;
use warnings;
my #words = $ARGV[0] =~ m{\S+}gso;
for (my $i = 0; $i < #words; $i++) {
print "word", $i + 1, " = ", $words[$i], "\n";
}
(I've iterated over the array using an index only because the question was originally framed in terms of emitting a rising value with each line. Ordinarily we would want to just use for or foreach to iterate over a list directly.)
Calling as:
perl test.pl ' This is a sentence '
prints:
word1 = This
word2 = is
word3 = a
word4 = sentence
If you explicitly want to pick up input on a double-dash long option name then use Getopt::Long as described by Quentin.
Please have a look at perldoc split().
foreach my $word (split (/ /, 'This is a sentence'))
{
print "word is $word\n";
}
Edit: Added parentheses around the split call.

extract every nth number

i want to extract every 3rd number ( 42.034 , 41.630 , 40.158 as so on ) from the file
see example-
42.034 13.749 28.463 41.630 12.627 28.412 40.158 12.173 30.831 26.823
12.596 32.191 26.366 13.332 32.938 25.289 12.810 32.419 23.949 13.329
Any suggestions using perl script ?
Thanks,
dac
You can split file's contents to separate numbers and use the modulo operator to extract every 3rd number:
my $contents = do { local $/; open my $fh, "file" or die $!; <$fh> };
my #numbers = split /\s+/, $contents;
for (0..$#numbers) {
$_ % 3 == 0 and print "$numbers[$_]\n";
}
use strict;
use warnings;
use 5.010; ## for say
use List::MoreUtils qw/natatime/;
my #vals = qw/42.034 13.749 28.463 41.630 12.627 28.412 40.158 12.173 30.831
26.823 12.596 32.191 26.366 13.332 32.938 25.289 12.810 32.419 23.949 13.329/;
my $it = natatime 3, #vals;
say while (($_) = $it->());
This is probably the shortest way to specify that. If #list is your list of numbers
#list[ grep { $_ % 3 == 0 } 0..$#list ]
It's a one-liner!
$ perl -lane 'print for grep {++$i % 3 == 1} #F' /path/to/your/input
-n gives you line-by-line processing, -a autosplitting for field processing, and $i (effectively initialized to zero for our purposes) keeps count of the number of fields processed...
This method avoids reading the entire file into memory at once:
use strict;
my #queue;
while (<>) {
push #queue, / ( \d+ (?: \. \d* ) ? ) /gx;
while (#queue >= 3) {
my $third = (splice #queue, 0, 3)[2];
print $third, "\n"; # Or do whatever with it.
}
}
If the file has 10 numbers in every line you can use this:
perl -pe 's/([\d.]+) [\d.]+ [\d.]+/$1/g;' file
It's not a clean solution but it should "do the job".
Looks like this post lacked a solution that didn't read the whole file and used grep.
#!/usr/bin/perl -w
use strict;
my $re = qr/-?\d+(?:\.\d*)/; # Insert a more precise regexp here
my $n = 3;
my $count = 0;
while (<>) {
my #res = grep { not $count++ % $n } m/($re)/go;
print "#res\n";
};
I believe you’ll find that this work per spec, behaves politely, and never reads in more than it needs to.
#!/usr/bin/env perl
use 5.010_001;
use strict;
use autodie;
use warnings qw[ FATAL all ];
use open qw[ :std IO :utf8 ];
END { close STDOUT }
use Regexp::Common;
my $real_num_rx = $RE{num}{real};
my $left_edge_rx = qr{
(?: (?<= \A ) # or use \b
| (?<= \p{White_Space} ) # or use \D
)
}x;
my $right_edge_rx = qr{
(?= \z # or use \b
| \p{White_Space} # or use \D
)
}x;
my $a_number_rx = $left_edge_rx
. $real_num_rx
. $right_edge_rx
;
if (-t STDIN && #ARGV == 0) {
warn "$0: reading numbers from stdin,"
. " type ^D to end, ^C to kill\n";
}
$/ = " ";
my $count = 0;
while (<>) {
while (/($a_number_rx)/g) {
say $1 if $count++ % 3 == 0;
}
}

Why aren't newlines being printed in this Perl code?

I have some simple Perl code:
#!/usr/bin/perl
use strict; # not in the OP, recommended
use warnings; # not in the OP, recommended
my $val = 1;
for ( 1 .. 100 ) {
$val = ($val * $val + 1) % 8051;
print ($val / 8050) . " \n";
}
But when I run it, the output is:
bash-3.2$ perl ./rand.pl
0.0002484472049689440.000621118012422360.003229813664596270.08409937888198760.92
... <snipped for brevity> ...
2919250.9284472049689440.3526708074534160.1081987577639750.2295652173913040.1839
751552795030.433540372670807bash-3.2$
Am I doing something wrong?
C:\> perldoc -f print:
Also be careful not to follow the
print keyword with a left parenthesis
unless you want the corresponding
right parenthesis to terminate the
arguments to the print--interpose a +
or put parentheses around all the
arguments.
Therefore, what you need is:
print( ($val / 8050) . "\n" );
or
print +($val / 8050) . "\n";
The statement you have prints the result of $val / 8050 and then concatenates "\n" to the return value of print and then discards the resulting value.
Incidentally, if you:
use warnings;
then perl will tell you:
print (...) interpreted as function at t.pl line 5.
Useless use of concatenation (.) or string in void context at t.pl line 5.
This is more of a comment than an answer, but I don't know how else to make it and the question is already answered anyway.
Note that using say instead of print neatly sidesteps the whole issue. That is,
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my $val = 1;
for ( 1 .. 100 ) {
$val = ($val * $val + 1) % 8051;
say ($val / 8050);
}
works as intended without the issue even coming up. I'm still amazed at how useful say is, given it's such a tiny difference.
It is possible that the line is interpreted as follows
(print($val / 8050)) . " \n";
i.e. the parentheses being used as delimiters for a function argument list, with the ."\n" being silently discarded. Try:
print( ($val/8050) . "\n" );