Perl удаление пробелов из элементов массива - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть массив, который содержит n количество элементов. Таким образом, могут быть шансы, что каждый элемент может иметь пробелы в начале или в конце. Поэтому я хочу убрать пространство одним выстрелом. Вот мой фрагмент кода, который работает, а который не работает (тот, который не работает, может обрезаться в конце, но не с передней стороны элемента).

Не работает:

....
use Data::Dumper;

my @a = ("String1", " String2 ", "String3 ");

print Dumper(\@a);

@a = map{ (s/\s*$//)&&$_}@a;

print Dumper(\@a);
...

Работает:

...
use Data::Dumper;

my @a = ("String1", " String2 ", "String3 ");

print Dumper(\@a);

my @b = trim_spaces(@a);

print Dumper(\@b);

sub trim_spaces
{
    my @strings = @_;
    s/\s+//g for @strings;
    return @strings;
}
...

Не знаю, в чем разница между этими двумя.

Если есть что-то лучше, пожалуйста поделись со мной !!

Ответы [ 2 ]

6 голосов
/ 27 апреля 2020

Ваш "неработающий пример" удаляет только пробелы с одного конца строки. Выражение s/^\s+|\s+$//g удалит пробелы с обоих концов.

Вы можете улучшить свой код, используя флаг /r для возврата измененной копии:

@a = map { s/^\s+|\s+$//gr } @a;

или, если необходимо :

@a = map { s/^\s+|\s+$//g; $_ } @a;
3 голосов
/ 27 апреля 2020

В этом блоке есть две проблемы:

{ (s/\s*$//)&& $_ }

Тривиальная проблема состоит в том, что он удаляет только завершающие пробелы, а не ведущие, которые, как вы сказали, вы хотели удалить.

Более коварной проблемой является вводящее в заблуждение использование &&. Если регулярное выражение в s/// не находит соответствия, оно возвращает undef; на левой стороне &&, это означает, что правая сторона никогда не выполняется, и undef становится значением всего блока. Это означает, что любая строка, которой не соответствует регулярное выражение, будет удалена и заменена на undef в массиве результатов, возвращаемом map, что, вероятно, не то, что вам нужно.

На самом деле это не будет произойдет с вашим регулярным выражением, как написано, потому что каждая строка соответствует \s*, а s/// по-прежнему возвращает true, даже если она на самом деле не изменяет строку. Но это зависит от регулярного выражения и неверного предположения.

В более общем случае ваш подход смешивает и сопоставляет два несовместимых метода изменения данных: изменение на месте (s///) и создание копии с некоторыми изменениями (map).

map функция предназначена для создания нового массива, элементы которого каким-то образом основаны на входном массиве; в идеале, он не должен изменять исходный массив в процессе. Но ваш код делает - даже если вы не присваивали результат отображения обратно @a, s/// изменяет строки внутри @a на месте. Фактически, вы можете удалить @a = из вашего кода и получить тот же результат. Это не считается хорошей практикой; map следует использовать для его возвращаемого значения, а не для побочных эффектов.

Если вы хотите изменить элементы массива на месте, ваше решение for на самом деле является способом go. Это дает понять, что вы делаете, и побочные эффекты в порядке.

Если вы хотите сохранить исходный массив и создать новый с примененными изменениями, вы должны использовать флаг /r в подстановках, который заставляет их возвращать полученную строку вместо изменения исходного на месте:

my @b = map { s/^\s+|\s+$//gr } @a;

Это оставляет @a в покое и создает новый массив @b с обрезанными строками.

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