Есть ли совместимое с Perl регулярное выражение для обрезания пробелов с обеих сторон строки?

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

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

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

Ответ 1

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

или

s/^\s+//, s/\s+$// for $x;

Ответ 2

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

#!/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 прав, но мало изменений. Я обновил код, чтобы скопировать строку перед изменением, что, конечно же, замедляет работу. Я также принял во внимание предложение brian d foy в другом ответе на использование более длинной строки (хотя миллион казался излишним). Однако это также говорит о том, что до того, как вы выберете стиль трюка, вы выясните, каковы ваши длины строк - преимущества трюка уменьшаются с более короткими строками. Во всяком случае, я тестировал, однако, двойные победы. И это еще проще на глазах.

Ответ 3

Забавно, что вы должны это принести!

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

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

Ответ 4

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 или regexes найти материал в начале, середине и конце. Посмотрите, соответствуют ли новые результаты вашему прогнозу. Выясните, что такое тренд. Улучшается ли производительность и лучше, приближается лимит, пик начинает начинать снижаться или что-то еще?

Ответ 5

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

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

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

Ответ 6

Здесь вы идете: $x =~ s/\A\s*(.*?)\s*\z/$1/;

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

Или это: s/\A\s*|\s*\Z//g

Ответ 10

s/^\s*(\S*\S)\s*$/$1/

Ответ 11

$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/;

Ответ 12

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