Существует ли Perl-совместимое регулярное выражение для обрезки пробелов с обеих сторон строки? - PullRequest
11 голосов
/ 09 октября 2008

Есть ли способ сделать это в одну строку?

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

Другими словами, удалите все начальные и конечные пробелы из строки.

Ответы [ 12 ]

30 голосов
/ 09 октября 2008

Мой первый вопрос ... почему? Я не вижу ни одного решения с одним регулярным выражением, которое было бы более читабельным, чем регулярное выражение, с которого вы начали. И они точно не так быстро.

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

дает результаты на моей машине:

             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%        --

Редактировать : runrig прав, но с небольшими изменениями. Я обновил код, чтобы скопировать строку перед изменением, что, конечно, замедляет работу. Я также принял во внимание предложение Брайана Д Фоя в другом ответе использовать более длинную строку (хотя миллион казался излишним). Однако это также предполагает, что перед тем, как выбрать стиль трюка, вы должны выяснить, на что похожа длина вашей струны - преимущества трюка уменьшаются с помощью более коротких струн. Тем не менее, на всех длинах я проверил двойные победы. И это все еще легче на глазах.

26 голосов
/ 09 октября 2008
$x =~ s/^\s+|\s+$//g;

или

s/^\s+//, s/\s+$// for $x;
8 голосов
/ 09 октября 2008

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%      --

Поскольку строка становится больше, использование «трюка» и «двойника» становится практически одинаковым, а общее решение, к которому стремится большинство людей, - «одиночный» (включая меня, потому что я не могу избавиться от этой привычки, даже если Я знаю это), действительно начинает сосать.

Всякий раз, когда вы смотрите на эталонный тест, думайте о том, что он говорит вам. Чтобы понять, понимаете ли вы это, измените данные и повторите попытку. Делайте массивы длинными, большие скаляры и так далее. Заставьте циклы, greps или регулярные выражения находить вещи в начале, середине и конце. Посмотрите, соответствуют ли новые результаты вашему прогнозу. Выясните, какова тенденция. Производительность становится все лучше и лучше, приближается к пределу, достигает пика, затем начинает снижаться или что-то еще?

8 голосов
/ 09 октября 2008

Забавно, вы должны поднять это!

Недавно я прочитал статью, анализирующую производительность двенадцати (!) Различных реализаций триммера .

Хотя в статье специально используется реализация регулярных выражений JavaScript, в ней используется синтаксис Perl, поэтому я думаю, что это уместно для этого обсуждения.

5 голосов
/ 09 октября 2008

Рассуждая из еретика, зачем вообще это? Все вышеперечисленные решения являются «правильными» в том смысле, что они обрезают пробел с обеих сторон строки за один проход, но ни одно из них не является чрезвычайно читабельным (возможно, ожидайте этот ). Если аудитория вашего кода не состоит из Perl-кодеров экспертного уровня, у каждого из вышеперечисленных кандидатов должен быть комментарий, описывающий то, что они делают (вероятно, хорошая идея в любом случае). Напротив, эти две строки выполняют одно и то же без использования заглядываний, подстановочных знаков, мидихлоринов или чего-то, что не является очевидным для программиста со средним опытом:

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

Существует (возможно) снижение производительности, но если вы не озабочены несколькими микросекундами при выполнении, дополнительная читаемость будет стоить того. ИМХО.

4 голосов
/ 09 октября 2008

Вот, пожалуйста, $x =~ s/\A\s*(.*?)\s*\z/$1/;

2 голосов
/ 09 октября 2008

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

1 голос
/ 09 октября 2008

Я обычно делаю это так:

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

Все, что находится между начальными и конечными пробелами, группируется и возвращается, поэтому я могу присвоить его той же старой переменной.

0 голосов
/ 10 ноября 2009
$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/;
0 голосов
/ 09 октября 2008
s/^\s*(\S*\S)\s*$/$1/
...