13

If I declared a variable $myString with the value '3 ' (notice the white space). Is there any function to remove the white space for the return value. A little like SomeFun($myString) then return '3' (without white space).

#!C:\Perl\bin\perl.exe
use strict;
use warnings;
use Data::Dumper; 

my $fh = \*DATA; 

print Dumper parse_constant_spec( $fh ); 


# Parse a constant spec file. 
# Pass in a handle to process. 
# As long as it acts like a file handle, it will work. 
sub parse_constant_spec { 
    my $fh = shift; 

    my %spec; 

    # Until file is done: 
        # Read in a whole block 
    while( my $block = read_block($fh) ) { 

        # Parse the and return key/value pairs for a hash. 
        my %constant = parse_block( $block ); 

        # Store a ref to the hash in a big hash of all blocks, keyed by constant_name. 
        $spec{ $constant{const_name} } = \%constant; 

    } 

    # Return ref to big hash with all block data 
    return \%spec; 
} 

# Read a constant definition block from a file handle. 
# void return when there is no data left in the file. 
# Otherwise return an array ref containing lines to in the block.  
sub read_block { 
    my $fh = shift; 

    my @lines; 
    my $block_started = 0; 

    while( my $line = <$fh> ) { 

        $block_started++ if $line =~ /^constant/; 

        if( $block_started ) { 

            last if $line =~ /^\s*$/; 

            push @lines, $line; 
        } 
    } 

    return \@lines if @lines; 

    return; 
} 


sub parse_block { 
    my $block = shift; 
    my ($start_line, @attribs) = @$block; 

    my %constant; 

    # Break down first line: 
    # First separate assignment from option list. 
    my ($start_head, $start_tail) = split /=/, $start_line; 

    # work on option list 
    my @options = split /\s+/, $start_head; 

    # Recover constant_name from options: 
    $constant{const_name} = pop @options; 
    $constant{options} = \@options; 

    # Now we parse the value/type specifier 
    @constant{'type', 'value' } = parse_type_value_specifier( $start_tail ); 

    # Parse attribute lines. 
    # since we've already got multiple per line, get them all at once. 
    chomp @attribs; 
    my $attribs = join ' ', @attribs; 

    #  we have one long line of mixed key = "value" or key = <TYPE VALUE>  

    @attribs = $attribs =~ /\s*(\w+\s+=\s+\w+\s+|\w+\s+=\s+".*?"|\w+\s+=\s+<.*?>)\s*/g; 

    for my $attrib ( @attribs ) { 
        warn "$attrib\n"; 
        my ($name, $value) = split /\s*=\s*/, $attrib; 

        if( $value =~ /^"/ ) {  
            $value =~ s/^"|"\s*$//g; 
        } 
        elsif( $value =~ /^</ ) { 
           $value = [ parse_type_value_specifier( $start_tail ) ]; 
        } 
        else { 
            warn "Bad line"; 
        } 

        $constant{ $name } = $value; 
    } 

    return %constant; 
} 

sub parse_type_value_specifier { 
    my $tvs = shift; 

    my ($type, $value) = $tvs =~ /<(\w+)\s+(.*?)>/; 

    return $type, $value; 
} 

__DATA__ 
constant fixup GemEstabCommDelay = <U2 20> 
    vid = 6 
    name = "ESTABLISHCOMMUNICATIONSTIMEOUT" 
    units = "s" 
    min = <U2 0> 
    max = <U2 1800> 
    default = <U2 20> 


constant fixup private GemConstantFileName = <A "C:\\TMP\\CONST.LOG"> 
    vid = 4 
    name = ""  units = "" 


constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG"> 
    vid = 0 
    name = "" 
    units = ""   

Output:

D:\learning\perl>hello1.pl
vid = 6
Bad line at D:\learning\perl\hello1.pl line 102, <DATA> line 8.
name = "ESTABLISHCOMMUNICATIONSTIMEOUT"
units = "s"
min = <U2 0>
max = <U2 1800>
default = <U2 20>
vid = 4
Bad line at D:\learning\perl\hello1.pl line 102, <DATA> line 13.
name = ""
units = ""
vid = 0
Bad line at D:\learning\perl\hello1.pl line 102, <DATA> line 18.
name = ""
units = ""
$VAR1 = {
          'GemAlarmFileName' => {
                                  'vid' => '0      ',
                                  'options' => [
                                                 'constant',
                                                 'fixup',
                                                 'private'
                                               ],
                                  'value' => '"C:\\\\TMP\\\\ALARM.LOG"',
                                  'name' => '',
                                  'type' => 'A',
                                  'const_name' => 'GemAlarmFileName',
                                  'units' => ''
                                },
          'GemEstabCommDelay' => {
                                   'vid' => '6      ',
                                   'options' => [
                                                  'constant',
                                                  'fixup'
                                                ],
                                   'value' => '20',
                                   'min' => [
                                              'U2',
                                              '20'
                                            ],
                                   'name' => 'ESTABLISHCOMMUNICATIONSTIMEOUT',
                                   'max' => [
                                              'U2',
                                              '20'
                                            ],
                                   'default' => [
                                                  'U2',
                                                  '20'
                                                ],
                                   'type' => 'U2',
                                   'units' => 's',
                                   'const_name' => 'GemEstabCommDelay'
                                 },
          'GemConstantFileName' => {
                                     'vid' => '4      ',
                                     'options' => [
                                                    'constant',
                                                    'fixup',
                                                    'private'
                                                  ],
                                     'value' => '"C:\\\\TMP\\\\CONST.LOG"',
                                     'name' => '',
                                     'type' => 'A',
                                     'const_name' => 'GemConstantFileName',
                                     'units' => ''
                                   }
        };

D:\learning\perl>

You could notice that 'vid' => '0 ', (notice the white space)

The code above from the answer. I am studying it. :-)

Thank you.

Community
  • 1
  • 1
Nano HE
  • 9,109
  • 31
  • 97
  • 137

12 Answers12

27
$myString =~ s/^\s*(.*?)\s*$/$1/;

This will trim whitespace from both sides.

from just the right:

$myString =~ s/\s*$//;
Gray
  • 115,027
  • 24
  • 293
  • 354
JAL
  • 21,295
  • 1
  • 48
  • 66
  • Hi Salsa. It works well. Followed your guide, `$value =~ s/\s*$//;` then call `print DEST_XML_FILE "\"$value\"";` – Nano HE Jan 08 '10 at 10:42
  • 3
    I had trouble with this.. I think it would be better to use a non greedy capture instead: (.*?) – Roman Sep 07 '10 at 18:19
  • Not sure if my way is right, but works for me. I want to remove all tabs in a file name I am getting from db. I used `$var=~s/\t//gs;` the code removes all \t form the string. [This post](http://stackoverflow.com/a/4547257/873891) helped me a lot. – Parik Tiwari Mar 07 '13 at 08:36
16

If your white space is just spaces, then the following code will remove all spaces:

$mystring =~ tr/ //ds;
Chip Uni
  • 7,454
  • 1
  • 22
  • 29
  • +1 . It works well. But i feel your script syntax is a little strange and it is hard to understand based on my knowledge :-) – Nano HE Jan 08 '10 at 12:22
  • 1
    This is the simplest solution. I agree the syntax is strange if you are not used to manipulating strings in perl. **tr** is used to replace characters in a string. As written above it says: replace a space `/ /` with nothing `//`. The following **ds** is a modifier to make the command complete but may not be necessary in this example. A good explanation can be found here [link](https://www.hscripts.com/tutorials/perl/functionforstrings/troperator.php) – Tereus Scott Mar 12 '17 at 15:57
11
sub trim($)
{
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}


print trim($myString)
GxG
  • 4,491
  • 2
  • 20
  • 18
  • Hi GxG. I tested with your code. `print DEST_XML_FILE trim("\"$value\"");` works well. otherwise `print DEST_XML_FILE trim("$value");` can't work. Would you please help me find why? I need use the 1st expression to add doublequote between the variable. – Nano HE Jan 08 '10 at 10:38
  • 1
    \" represents an escape sequence so if you want to put quotes you need to put \" otherwise it will be seen as a simple quoted text and will appear without the quotes – GxG Jan 08 '10 at 12:25
  • Hi GxG. it works when i declared another tempString. `my $tempString = trim($value);` then call `print DEST_XML_FILE "\"$tempString\"";` Thank you. – Nano HE Jan 08 '10 at 12:51
9

Try this:

# Delete leading/trailing whitespace.
$string =~ s/^\s+|\s+$//g;
John Feminella
  • 303,634
  • 46
  • 339
  • 357
  • /g can lose you :) specially for multiline string content. for one step better use: $string =~ s/^\s*(.*)\s*$/$1/; it is usable for multilines with /g option. – Znik Jul 14 '14 at 10:09
5

Another potential alternative solution is Text::Trim from CPAN, which will "remove leading and/or trailing whitespace from strings". It has a trim function which may suit your needs.

toolic
  • 57,801
  • 17
  • 75
  • 117
2
sub trim
{
    my $str = $_[0];
    $str=~s/^\s+|\s+$//g;
    return $str;
}

print trim(" 4 ");
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • Hi ghostdog74. I tested with your code. `print DEST_XML_FILE trim("\"$value\"");` works well. otherwise `print DEST_XML_FILE trim("$value");` can't work. Would you please help me find why? I need use the 1st expression to add doublequote between the variable. – Nano HE Jan 08 '10 at 10:34
  • 2
    It's actually faster to remove the leading and trailing whitespace in separate substitutions. That alternation screws it all up. :) – brian d foy Jan 08 '10 at 10:36
  • 1
    @Nano, the alternation works as expected. trimming ending and leading spaces. that's all it does. You should do whatever you want to $value before passing it to trim() function. Otherwise, show an example of what $value is, and then describe what you want to see after trimming. – ghostdog74 Jan 08 '10 at 11:34
  • @ghostdog74. I updated the whole script and it's output. Would you please do more dissection about the $value. Thank you. :-) – Nano HE Jan 08 '10 at 12:42
  • @ghostdog74. it works when i declared another tempString. `my $tempString = trim($value);` then call `print DEST_XML_FILE "\"$tempString\"";` – Nano HE Jan 08 '10 at 12:50
  • $string =~ s/^\s*(.*)\s*$/$1/; works better. you can add /g for trimming all lines. But $str=~s/^\s+|\s+$//g; won't work good for multiline $str content. – Znik Jul 14 '14 at 10:16
2

Here's a subroutine that will allow you to remove leading and trailing whitespace from a string while also removing excesss whitespaces from within the string and replacing it with a single spaces.

-- routine

sub unspace { my @stringer = @_ ? @_ : $; $ = join( ' ', split(' ')) for @stringer; return wantarray ? @stringer : "@stringer"; }

-- usage

$MySpacedString = ' String with tabs double-spaces and other whitespace areas. '; $MyCleanString = unspace($MySpacedString);

DoctorLouie
  • 2,699
  • 1
  • 18
  • 23
2

Remove all spaces in a string:

$string =~ s/ //g;
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
1

Just looking over your program, I found 3 spots that could be improved or fixed.

I apologize if my code doesn't format well. :-(

In your function parse_block(...), there are 3 items that need attention.

@attribs = $attribs =~ /\s*(\w+\s+=\s+\w+\s+|\w+\s+=\s+".*?"|\w+\s+=\s+<.*?>)\s*/g;

To eliminate the white space after vid => '6 ', just don't include the \s+ at the end of your first sub-regex.

Write it as:

@attribs = $attribs =~ /\s*(\w+\s+=\s+\w+|\w+\s+=\s+".*?"|\w+\s+=\s+<.*?>)\s*/g;  

$value = [ parse_type_value_specifier( $start_tail ) ];  

You want this instead:

$value = [ parse_type_value_specifier( $value ) ]; 

(Note that the parameter to the function should be $value and not $start_tail.) You probably didn't notice this.

In the loop for @attributes, the 'else' in the if/else condition excutes when the 'value' has a plain value, (no "" or <...> items in 'value').

Update: Changed parameter in

parse_type_value_specifier(...)
to $value. It was (incorrectly) stated as $attrib.
Chris Charley
  • 6,403
  • 2
  • 24
  • 26
0

Remove spaces from variable $test (eq rtrim(ltrim(@sStr)) from Transact SQL:

$test =~s/^\s*(\S*)\s*$/$1/;
Brett Gregson
  • 5,867
  • 3
  • 42
  • 60
0

If you are willing to use a CPAN module then String::Util, or the somewhat more economical Text::Trim would be possible choices.

Trimming strings is one of those bike sheds that everyone likes to build! See the short perlmaven tutorial by @szabgab for a small sample of TIMTOWDI fun.

Community
  • 1
  • 1
G. Cito
  • 6,210
  • 3
  • 29
  • 42
0

I suggest that you make use of the Text::Trim module, which provides ltrim, rtrim, and trim, all of which will trim the parameters passed, or $_ if you give no parameters. It's not a core module so it may need installing

Borodin
  • 126,100
  • 9
  • 70
  • 144