Is there a Perl-compatible regular expression to trim whitespace from both sides of a string?

前端 未结 13 958
醉话见心
醉话见心 2021-02-08 07:45

Is there a way to do this in one line?

$x =~ s/^\\s+//;
$x =~ s/\\s+$//;

In other words, remove all leading and trailing whitespace from a stri

相关标签:
13条回答
  • 2021-02-08 08:30
    $x =~ s/^\s+|\s+$//g;
    

    or

    s/^\s+//, s/\s+$// for $x;
    
    0 讨论(0)
  • 2021-02-08 08:31

    My first question is ... why? I don't see any of the single-regexp solutions to be any more readable than the regexp you started with. And they sure aren't anywhere near as fast.

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Benchmark qw(:all);
    
    my $a = 'a' x 1_000;
    
    my @x = (
             "    $a   ",
             "$a   ",
             $a,
             "    $a"
            );
    
    cmpthese(-5,
             {
                 single => sub {
                     for my $s (@x)
                     {
                         my $x = $s;
                         $x =~ s/^\s+|\s+$//g;
                     }
                 },
                 double => sub {
                     for my $s (@x)
                     {
                         my $x = $s;
                         $x =~ s/^\s+//;
                         $x =~ s/\s+$//;
                     }
                 },
                 trick => sub {
                     for my $s (@x)
                     {
                         my $x = $s;
                         s/^\s+//, s/\s+$// for $x;
                     }
                 },
                 capture => sub {
                     for my $s (@x)
                     {
                         my $x = $s;
                         $x =~ s/\A\s*(.*?)\s*\z/$1/
                     }
                 },
                 kramercap => sub {
                     for my $s (@x)
                     {
                         my $x = $s;
                         ($x) = $x =~ /^\s*(.*?)\s*$/
                     }
                 },
             }
            );
    

    gives results on my machine of:

                 Rate    single   capture kramercap     trick    double
    single     2541/s        --      -12%      -13%      -96%      -96%
    capture    2902/s       14%        --       -0%      -95%      -96%
    kramercap  2911/s       15%        0%        --      -95%      -96%
    trick     60381/s     2276%     1981%     1974%        --       -7%
    double    65162/s     2464%     2145%     2138%        8%        --
    

    Edit: runrig is right, but to little change. I've updated the code to copy the string before modification, which, of course, slows things down. I also took into account brian d foy's suggestion in another answer to use a longer string (though a million seemed like overkill). However, that also suggests that before you choose the trick style, you figure out what your string lengths are like - the advantages of trick are lessened with shorter strings. At all lengths I've tested, though, double wins. And it's still easier on the eyes.

    0 讨论(0)
  • 2021-02-08 08:31

    $x =~ s/(^\s+)|(\s+$)//g;

    0 讨论(0)
  • 2021-02-08 08:32

    Arguing from the heretical, why do it at all? All of the above solutions are "correct" in that they trim whitespace from both sides of the string in one pass, but none are terribly readable (expect maybe this one). Unless the audience for your code is comprised of expert-level Perl coders each of the above candidates should have a comment describing what they do (probably a good idea anyway). By contrast, these two lines accomplish the same thing without using lookaheads, wildcards, midichlorines or anything that isn't immediately obvious to a programmer of moderate experience:

    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    

    There is (arguably) a performance hit, but as long as you aren't concerned with a few microseconds at execution the added readability will be worth it. IMHO.

    0 讨论(0)
  • 2021-02-08 08:35
    $x =~ s/^\s*(.*?)\s*$/$1/;
    
    0 讨论(0)
  • 2021-02-08 08:40

    In zsh with PCRE mode active:

    function trim() {
        local out="$*"
        [[ "$out" =~ '^\s*(.*\S)\s*$' ]] && out="$match[1]" || out=''
        print -nr -- "$out"
    }
    
    0 讨论(0)
提交回复
热议问题