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

StackOverflow https://stackoverflow.com/questions/184590

  •  06-07-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

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

или

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

s/^\s*(\S*\S)\s*$/$1/
$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/;
$x =~ s/^\s*(.*?)\s*$/$1/;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top