Существует ли регулярное выражение, совместимое с Perl, для обрезки пробелов с обеих сторон строки?
-
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/;