Я хочу split()
строку как для символов новой строки, так и для пробелов:
#!/usr/bin/perl
use warnings;
use strict;
my $str = "aa bb cc\ndd ee ff";
my @arr = split(/\s\n/, $str); # Split on ' ' and '\n'
print join("\n", @arr); # Print array, one element per line
Вывод таков:
aa bb cc
dd ee ff
Но я хочу вот что:
aa
bb
cc
dd
ee
ff
Итак, мой код разбивается на новую строку (хорошо), но не на пробелы. Согласно perldoc, пробел должен сопоставляться с \s
в классе символов, и я бы предположил, что — это пробел. Я что-то упускаю?
мой код разбивается на новую строку (хорошо)
Ваш код не разбивается на новую строку; это только так кажется из-за того, как вы печатаете вещи. Ваш массив содержит один элемент, а не два. В середине элемента есть новая строка, и вы просто печатаете aa bb cc\ndd ee ff
.
\s\n
означает: любой пробел, за которым следует новая строка, где пробел фактически включает \n
.
Изменение:
my @arr = split(/\s\n/, $str);
к:
my @arr = split(/\s/, $str);
Использование Data::Dumper дает понять, что массив теперь имеет 6 элементов:
use warnings;
use strict;
use Data::Dumper;
my $str = "aa bb cc\ndd ee ff";
my @arr = split(/\s/, $str);
print Dumper(\@arr);
Отпечатки:
$VAR1 = [
'aa',
'bb',
'cc',
'dd',
'ee',
'ff'
];
Приведенный выше код работает с введенной вами строкой ввода. Также принято разбивать на несколько последовательных пробелов, используя:
my @arr = split(/\s+/, $str);
Вы разделяете символ пробела, за которым следует перевод строки. Чтобы разделить, когда встречается любой из них, есть
split /[\s\n]/, $str
Но \s
включает \n
, так что это можно упростить.
split /\s/, $str
Но что, если у вас есть два пробела подряд? Вы можете разделить, когда встречается последовательность пробелов.
split /\s+/, $str
Вы можете предоставить специальный ввод, который делает то же самое, за исключением того, что он игнорирует начальные пробелы.
split ' ', $str
Так,
use v5.14;
use warnings;
my $str = "aa bb cc\ndd ee ff";
my @arr = split ' ', $str;
say for @arr;
@TomWilliams Только за несколько секунд до того, как вы узнаете, что означает ' '
, что вы можете прочитать в perldoc split
. Кроме того, это распространяет ложь: что \s
не содержит \n
. Ничего хорошего из этого не выйдет.
@TomWilliams, я не согласен. [\s\n]
— это ужасный способ писать \s
. Это означает, что \s
не соответствует \n
, что неверно, сбивает с толку и вводит в заблуждение. /// Думаете, \s
соответствует только пробелу? Это неправильно. Как говорится в ответе, он соответствует любому из 25 пробельных символов. Сюда входят горизонтальные пробелы (\h
, 18) и вертикальные пробелы (\v
, 7). Последнее включает в себя перевод строки, который также соответствует \n
.
@TomWilliams Кроме того, split ' '
не эквивалентен split /\s+/
, как объясняет мой ответ, поэтому нельзя просто использовать split /\s+/
(или split /[\s\n]+/
), как вы предлагаете. /// И тебе лучше научиться split ' '
очень быстро. ' '
используется по умолчанию для первого аргумента, что приводит к таким конструкциям, как while (<>) { my @fields = split; ... }
. Это также операция, выполненная qw
. qw( ... )
эквивалентно split ' ', q( ... )
. Они оба довольно распространены, поэтому делать вид, что их не существует, было бы плохой услугой.
Ваш вопрос исходит из неправильного анализа результата вашего кода. Вы думаете, что разделили на новую строку, хотя на самом деле ничего не разделяли и на самом деле просто печатаете новую строку.
Если вы хотите избежать этой ошибки в будущем и точно знать, что содержат ваши переменные, вы можете использовать основной модуль Data::Dumper:
use strict;
use warnings;
use Data::Dumper;
my $str = "aa bb cc\ndd ee ff";
my @arr = split(/\s\n/, $str); # split on whitespace followed by newline
$Data::Dumper::Useqq = 1; # show exactly what is printed
print Dumper \@arr; # using Data::Dumper
Вывод:
$VAR1 = [
"aa bb cc\ndd ee ff"
];
Как вы могли бы легко сказать, вы вообще не печатаете массив, а просто одно скалярное значение (внутри массива, потому что вы его туда поместили). Data::Dumper — отличный инструмент для отладки ваших данных и полезный инструмент для изучения.
split ' ', $arr
, безусловно, самый элегантный выбор, ноsplit /[\s\n]+/, $arr
может быть немного более понятным для нас, новичков.