How can I replace multiple whitespace with a single space in Perl? - perl

Why is this not working?
$data = "What is the STATUS of your mind right now?";
$data =~ tr/ +/ /;
print $data;

Use $data =~ s/ +/ /; instead.
Explanation:
The tr is the translation operator. An important thing to note about this is that regex modifiers do not apply in a translation statement (excepting - which still indicates a range). So when you use
tr/ +/ / you're saying "Take every instance of the characters space and + and translate them to a space". In other words, the tr thinks of the space and + as individual characters, not a regular expression.
Demonstration:
$data = "What is the STA++TUS of your mind right now?";
$data =~ tr/ +/ /;
print $data; #Prints "What is the STA TUS of your mind right now?"
Using s does what you're looking for, by saying "match any number of consecutive spaces (at least one instance) and substitute them with a single space". You may also want to use something like
s/ +/ /g; if there's more than one place you want the substitution to occur (g meaning to apply globally).

You can also use tr with the "squash" option, which will remove duplicate replaced characters. See perlop for details.
my $s = "foo bar fubb";
$s =~ tr/ //s;

Perl 5.10 has a new character class, \h, the stands for horizontal whitespace which is nice for this sort of thing:
$s =~ s/\h+/ /g;

Related

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.

A Perl Program Which divides a String by spaces between them?

I want my program to divide the string by the spaces between them
$string = "hello how are you";
The output should look like that:
hello
how
are
you
You can do this is a few different ways.
use strict;
use warnings;
my $string = "hello how are you";
my #first = $string =~ /\S+/g; # regex capture non-whitespace
my #second = split ' ', $string; # split on whitespace
my $third = $string;
$third =~ tr/ /\n/; # copy string, substitute space for newline
# $third =~ s/ /\n/g; # same thing, but with s///
The first two creates arrays with the individual words, the last creates a different single string. If all you want is something to print, the last will suffice. To print an array do something like:
print "$_\n" for #first;
Notes:
Normally, regex capture requires parentheses /(\S+)/, but when the /g modifier is used, and parentheses are omitted, the entire match is returned.
When using capture this way, you need to assure list context on the assignment. If the left hand parameter is a scalar, you would force list context with parentheses: my ($var) = ...
I think like simple....
$string = "hello how are you";
print $_, "\n" for split ' ', $string;
#Array = split(" ",$string); then the #Array contain the answer
You need a split for dividing the string by spaces like
use strict;
my $string = "hello how are you";
my #substr = split(' ', $string); # split the string by space
{
local $, = "\n"; # setting the output field operator for printing the values in each line
print #substr;
}
Output:
hello
how
are
you
Split with regexp to account for extra spaces if any:
my $string = "hello how are you";
my #words = split /\s+/, $string; ## account for extra spaces if any
print join "\n", #words

Perl, pattern matching and metacharacters

I am trying to match two things which both are full of metacharacters that needs to be used as 'Literal' in my match pattern. \Q is suppose to quote all metacharacter in a string until \E...but it doesn't work.
Whats up with that?
this is the line that gives me trouble : if (/\Q$prev\E/ !~ /\Q$ww[0]\E/) {
Absent the use of =~ or !~,
/.../
is short for
$_ =~ m/.../
so
/\Q$prev\E/ !~ /\Q$ww[0]\E/
is short for
($_ =~ /\Q$prev\E/) !~ /\Q$ww[0]\E/
which is equivalent to one of the following depending on whether the left regex match succeeds or not:
"" !~ /\Q$ww[0]\E/
"1" !~ /\Q$ww[0]\E/
You simply want:
$prev !~ /\Q$ww[0]\E/ # $ww[0] doesn't contains $prev
If you actually want
$prev !~ /^\Q$ww[0]\E\z/ # $ww[0] isn't equal to $prev
then you can simplify that to
$prev ne $ww[0] # $ww[0] isn't equal to $prev
By the way, always use use strict; use warnings;. It may have identified a problem here (but not necessarily, depending on the value of $_).
It looks like you want to compare a string in $prev to one in $ww[0]. If this is the case, a regex match should look like this:
$result = $prev !~ /\Q$ww[0]\E/
$result will return 1 if $prev is not the same as whatever is in www[0], ignoring metacharacters.
However if that is all you wanted to do, you might as well use ne:
if ($prev ne $ww[0]){
#do this if $prev and $ww[0] are not the same
}
Also, as #toolic has mentioned, add the following line to the top of your script:
use warnings;
This will give you some feedback on possible problems in your scripts.

perl blank substitution in a string

I have this two kind of strings:
EVASA 2144
IN ELABORAZIONE 16278
I need some perl script to substitute all the blanks with just one.
The output I need is:
EVASA 2144
Any suggestion?
You can use a very simple regex:
#!/usr/bin/perl
use strict;
my $line = 'EVASA 2144';
# This is the line that actually does the work
$line =~ s/\s+/ /g;
print $line, "\n";
My suggestion would be that you spend some time reading the Regular Expression tutorial that is distributed with every modern version of Perl.
$a = "hello \t world";
$a =~ s/\s+/ /;
print $a;
if you may have multiple places in the string where you want the substitution to take place, use
$a = "hello \t world hi";
$a =~ s/\s+/ /g;
print $a;
You can also use the troperator with the s Option, this can do more things for you (transforming characters), probably faster than the regexp approach
$a =~ tr/ \t/ /s;
Explanation can be found in the perlop manpage:
perldoc perlop