11

有没有办法在一行中做到这一点?

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

换句话说,从字符串中删除所有前导和尾随空格。

4

13 回答 13

30

我的第一个问题是……为什么?我没有看到任何单正则表达式解决方案比您开始使用的正则表达式更具可读性。而且他们肯定没有那么快。

#!/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*$/
                 }
             },
         }
        );

在我的机器上给出以下结果:

             率单捕获 Kramercap 技巧双倍
单 2541/s -- -12% -13% -96% -96%
捕获 2902/s 14% -- -0% -95% -96%
kramercap 2911/s 15% 0% -- -95% -96%
技巧 60381/s 2276% 1981% 1974% -- -7%
双 65162/s 2464% 2145% 2138% 8% --

编辑:runrig 是对的,但变化不大。我已经更新了代码以在修改之前复制字符串,这当然会减慢速度。我还在另一个答案中考虑了 brian d foy 的建议,即使用更长的字符串(尽管一百万似乎过大了)。然而,这也表明,在你选择技巧风格之前,你要弄清楚你的弦长是什么样的——短弦会削弱技巧的优势。尽管如此,我已经测试了所有长度,双赢。而且它仍然更容易在眼睛上。

于 2008-10-08T20:48:56.463 回答
26
$x =~ s/^\s+|\s+$//g;

或者

s/^\s+//, s/\s+$// for $x;
于 2008-10-08T20:08:49.743 回答
8

有趣的是你应该提出这个!

我最近阅读了一篇文章,分析了十二种(!)不同修剪实现的性能

虽然本文专门使用 JavaScript 正则表达式实现,但它使用 Perl 语法,所以我认为它适合这个讨论。

于 2008-10-08T21:31:52.693 回答
8

Tanktalus 展示了非常小的琴弦的基准,但随着琴弦变大,问题会变得更糟。在他的代码中,我更改了顶部:

my $a = 'a' x 1_000_000;

my @x = (
  "   $a   ",
  "$a    ",
  $a,
  "    $a"
  );

我得到这些结果:

          Rate  single capture   trick  double
single  2.09/s      --    -12%    -98%    -98%
capture 2.37/s     13%      --    -98%    -98%
trick   96.0/s   4491%   3948%      --     -0%
double  96.4/s   4512%   3967%      0%      --

随着字符串变大,使用“trick”和“double”几乎相同,并且大多数人都采用的常见解决方案,“single”(包括我,因为即使我知道这一点,我也无法打破这个习惯),真的开始很烂。

每当您查看基准时,请考虑它告诉您的内容。要查看是否理解,请更改数据并重试。使数组变长,标量变大,等等。使循环、grep 或正则表达式在开头、中间和结尾查找内容。看看新结果是否符合您的预测。弄清楚趋势是什么。性能会变得越来越好,接近极限,达到峰值然后开始下降,还是其他?

于 2008-10-08T22:14:03.203 回答
5

从异端争论,为什么要这样做?所有上述解决方案都是“正确的”,因为它们在一次通过中从字符串的两侧修剪空白,但没有一个非常可读(可能是这个)。除非您的代码的受众是由专家级 Perl 编码人员组成,否则上述每个候选人都应该有一个评论来描述他们所做的事情(无论如何可能是个好主意)。相比之下,这两行代码完成了同样的事情,而无需使用前瞻、通配符、midichlorines 或任何对于中等经验的程序员来说并不明显的东西:

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

(可以说)性能会受到影响,但只要您不关心执行时的几微秒,增加的可读性将是值得的。恕我直言。

于 2008-10-08T21:11:47.883 回答
4

干得好:$x =~ s/\A\s*(.*?)\s*\z/$1/;

于 2008-10-08T20:06:06.877 回答
2

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

于 2008-10-08T20:06:19.577 回答
1

我通常这样做:

($foo) = $foo =~ /^\s*(.*?)\s*$/;

前导空格和尾随空格之间的所有内容都被分组并返回,因此我可以将其分配给同一个旧变量。

于 2008-10-08T23:02:20.750 回答
0

或这个:s/\A\s*|\s*\Z//g

于 2008-10-08T20:07:23.020 回答
0
s/^\s*(\S*\S)\s*$/$1/
于 2008-10-08T20:08:34.360 回答
0

在激活 PCRE 模式的 zsh 中:

function trim() {
    local out="$*"
    [[ "$out" =~ '^\s*(.*\S)\s*$' ]] && out="$match[1]" || out=''
    print -nr -- "$out"
}
于 2020-08-05T13:13:49.147 回答
-1
$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/;
于 2009-11-10T19:40:50.580 回答
-2
$x =~ s/^\s*(.*?)\s*$/$1/;
于 2008-10-08T20:07:04.393 回答