perl find and replace ../ and   - perl

I am using Perl to replace all instances of
../../../../../../abc' and  
in a string with
/ and , respectively.
The method I am using looks like this:
sub encode
{
my $result = $_[0];
$result =~ s/..\/..\/..\/..\/..\/..\//\//g;
$result =~ s/ / /g;
return $result;
}
Is this correct?

Essentially, yes, although the first regex has to be written in a different way: because . matches any character, we have to escape it \. or put it in its own character class [.]. The first regex can also be written cleaner as
...;
$result =~ s{ (?: [.][.]/ ){6} }
{/}gx;
...;
We look for the literal pattern ../ repeated 6 times and then replace it. Because I use curly braces as a delimiter I don't have to escape the slash. Because I use the /x modifier I can have these spaces inside the regex improving readability.

Try this. It will print /foo bar/baz.
#!/usr/bin/perl -w
use strict;
my $result = "../../../../../../foo bar/baz";
#$result =~ s/(\.\.\/)+/\//g; #for any number of ../
$result =~ s/(\.\.\/){6}/\//g; #for 6 exactly
$result =~ s/ / /g;
print $result . "\n";

you forgot the abc, i think:
sub encode
{
my $result = $_[0];
$result =~ s/(?:..\/){6}abc/\//g;
$result =~ s/ / /g;
return $result;
}

Related

using two search and replace regex commands in Perl

In a file, I have to replace
.L1 to L_xx_1
.L2 to L_xx_2
.L3 to L_xx_3
...
and
.LC1 to LC_xx_1
.LC2 to Lc_xx_2
.LC3 to LC_xx_3
...
For these two search and replacements I have two different Perl scripts containing following two different loops:
for ($i=0; $currentLine=<file>; $i++) {
$currentLine =~ s/.L(\d+)/L_$ARGV[1]_$1/gi;
print $currentLine;
}
and
for ($i=0; $currentLine=<file>; $i++) {
$currentLine =~ s/.LC(\d+)/LC_$ARGV[1]_$1/gi;
print $currentLine;
}
respectively.
Can I merge these two loops into one by merging two S commands into one.
Yes, you can combine the 2 substitutions into one with a different regular expression. You can capture the "L" followed by an optional "C".
use warnings;
use strict;
my $str = 'xx';
while (my $currentLine = <DATA>) {
$currentLine =~ s/\.(LC?)(\d+)/$1_${str}_$2/gi;
print $currentLine;
}
__DATA__
.L1
.L2
.L3
.LC1
.LC2
.LC3
This prints:
L_xx_1
L_xx_2
L_xx_3
LC_xx_1
LC_xx_2
LC_xx_3
Note that I escaped the first character (the period). This will only match a literal period.
Modify your regex to
$currentLine =~ s/\.L(C?)(\d+)/L$1_$ARGV[1]_$2/gi;

Why is chomp not removing whitespace around my string?

I don't understand why perl chomp isn't removing the whitespace surrounding my string. I've even tried to call chomp twice, for example, using bash:
$ perl -e 'use 5.22.4; chomp(my $extra=" lol "); chomp($extra); say "<$extra>"'
< lol >
I really expected to get
<lol>
Chomp only removes the line ending (can be set with $/ variable) from the end of the string. It does not trim the string. Perl does not have a built-in trim function. I usually spell out two substitutions instead:
s/^\s+//, s/\s+$// for $string;
Further reading:
perldoc -f chomp
Perl FAQ: How do I strip blank space from the beginning/end of a string?
To remove all whitespace:
$string =~ s/\s+//g;
Left trim:
$string =~ s/^\s+//;
Right Trim:
$string =~ s/\s+$//;
Left and Right trim:
$string =~ s/^\s+|\s+$//g
We can then also build trimming fucntions. This helps in much bigger scripts where you would not want to write the full replacement strings each time, we write them once, then use the function to do the work.
This simple function can be used in any script as trim($string);
sub trim {
$_[0] =~ s/^\s+|\s+$//g;
}
Similarly with a full strip of whitespace.
sub full_strip {
$_[0] =~ s/\s+//g;
}
in a script:
use strict;
use warnings;
my $string = " this is line with leading and trailing whitespaces ";
my $string2 = " another one of those lines ";
trim($string);
trim($string2);
print "$string\n";
print "$string2\n";
full_strip($string);
full_strip($string2);
print "$string\n";
print "$string2\n";
sub trim {
$_[0] =~ s/^\s+|\s+$//g;
}
sub full_strip {
$_[0] =~ s/\s+//g;
}
$string=~s/^\s+|\s+$//g;
This would work well for any generic string where you want to remove beginning and ending spaces.

Unmatched ) in reg when using lc function

I am trying to run the following code:
$lines = "Enjoyable )) DAY";
$lines =~ lc $lines;
print $lines;
It fails on the second line where I get the error mentioned in the title. I understand the brackets are causing the trouble. I think I could use "quotemeta", but the thing is that my string contains info that I go on to process later, so I would like to keep the string intact as far as possible and not tamper with it too much.
You have two problems here.
1. =~ is used to execute a specific set of operations
The =~ operator is used to either match with //, m//, qr// or a string; or to substitute with s/// or tr///.
If all you want to do is lowercase the contents of $lines then you should use = not =~.
$lines = "Enjoyable )) DAY";
$lines = lc $lines;
print $lines;
2. Regular expressions have special characters which must be escaped
If you want to match $lines against a lower case version of $Lines, which should return true if $lines was already entirely lower case and false otherwise, then you need to escape the ")" characters.
#!/usr/bin/env perl
use strict;
use warnings;
my $lines = "enjoyable )) day";
if ($lines =~ lc quotemeta $lines) {
print "lines is lower case\n";
}
print $lines;
Note this is a toy example trying to find a reason for doing $lines =~ lc $lines - It would be much better (faster, safer) to solve this with eq as in $lines eq lc $lines.
See perldoc -f quotemeta or http://perldoc.perl.org/functions/quotemeta.html for more details on quotemeta.
=~ is used for regular expressions. "lc" is not part of regex, it's a function like this: $new = lc($old);
I don't recall the regex operator for lowercase, because I use lc() all the time.

What does dot-equals mean in Perl?

What does ".=" mean in Perl (dot-equals)? Example code below (in the while clause):
if( my $file = shift #ARGV ) {
$parser->parse( Source => {SystemId => $file} );
} else {
my $input = "";
while( <STDIN> ) { $input .= $_; }
$parser->parse( Source => {String => $input} );
}
exit;
Thanks for any insight.
The period . is the concatenation operator. The equal sign to the right means that this is an assignment operator, like in C.
For example:
$input .= $_;
Does the same as
$input = $input . $_;
However, there's also some perl magic in this, for example this removes the need to initialize a variable to avoid "uninitialized" warnings. Try the difference:
perl -we 'my $x; $x = $x + 1' # Use of uninitialized value in addition ...
perl -we 'my $x; $x += 1' # no warning
This means that the line in your code:
my $input = "";
Is quite redundant. Albeit some people might find it comforting.
For pretty much any binary operator X, $a X= $b is equivalent to $a = $a X $b. The dot . is a string concatenation operator; thus, $a .= $b means "stick $b at the end of $a".
In your code, you start with an empty $input, then repeatedly read a line and append it to $input until there's no lines left. You should end up with the entire file as the contents of $input, one line at a time.
It should be equivalent to the loopless
local $/;
$input = <STDIN>;
(define line separator as a non-defined character, then read until the "end of line" that never comes).
EDIT: Changed according to TLP's comment.
You have found the string concatenation operator.
Let's try it :
my $string = "foo";
$string .= "bar";
print $string;
foobar
This performs concatenation to the $input var. Whatever is coming in via STDIN is being assigned to $input.

Check for spaces in perl using regex match in perl

I have a variable how do I use the regex in perl to check if a string has spaces in it or not ? For ex:
$test = "abc small ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters";
So for this string it should check if any word in the string is not bigger than some x characters.
#!/usr/bin/env perl
use strict;
use warnings;
my $test = "ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters";
if ( $test !~ /\s/ ) {
print "No spaces found\n";
}
Please make sure to read about regular expressions in Perl.
Perl regular expressions tutorial - perldoc perlretut
You should have a look at the perl regex tutorial. Adapting their very first "Hello World" example to your question would look like this:
if ("ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters" =~ / /) {
print "It matches\n";
}
else {
print "It doesn't match\n";
}
die "No spaces" if $test !~ /[ ]/; # Match a space
die "No spaces" if $test =~ /^[^ ]*\z/; # Match non-spaces for entire string
die "No whitespace" if $test !~ /\s/; # Match a whitespace character
die "No whitespace" if $test =~ /^\S*\z/; # Match non-whitespace for entire string
To find the length of the longest unbroken sequence of non-space characters, write this
use strict;
use warnings;
use List::Util 'max';
my $string = 'abc small ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters';
my $max = max map length, $string =~ /\S+/g;
print "Maximum unbroken length is $max\n";
output
Maximum unbroken length is 61