Есть ли способ сделать это в одной строке?
$x =~ s/^\s+//;
$x =~ s/\s+$//;
Другими словами, удалите из строки все начальные и конечные пробелы.
Есть ли способ сделать это в одной строке?
$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 прав, но мало изменений. Я обновил код, чтобы скопировать строку перед изменением, что, конечно же, замедляет работу. Я также принял во внимание предложение brian d foy в другом ответе на использование более длинной строки (хотя миллион казался излишним). Однако это также говорит о том, что до того, как вы выберете стиль трюка, вы выясните, каковы ваши длины строк - преимущества трюка уменьшаются с более короткими строками. Во всяком случае, я тестировал, однако, двойные победы. И это еще проще на глазах.
Забавно, что вы должны это принести!
Недавно я прочитал статью, анализирующую производительность двенадцати (!) различных реализаций обрезки.
Хотя в статье специально используется реализация JavaScript regex, она использует синтаксис Perl, поэтому я думаю об этом в связи с этим обсуждением.
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 найти материал в начале, середине и конце. Посмотрите, соответствуют ли новые результаты вашему прогнозу. Выясните, что такое тренд. Улучшается ли производительность и лучше, приближается лимит, пик начинает начинать снижаться или что-то еще?
Рассуждая от еретика, зачем вообще это делать? Все вышеперечисленные решения являются "правильными" в том смысле, что они обрезают пробелы с обеих сторон строки за один проход, но ни один из них не читается ужасно (предположим, что этот). Если аудитория вашего кода не состоит из кодов Perl на уровне эксперта, у каждого из вышеперечисленных кандидатов должен быть комментарий, описывающий, что они делают (вероятно, хорошая идея в любом случае). Напротив, эти две линии выполняют одно и то же без использования lookaheads, wildcards, midichlorines или всего, что не сразу очевидно для программиста с умеренным опытом:
$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/;