Split () для символов новой строки и пробела?

Я хочу 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 в классе символов, и я бы предположил, что — это пробел. Я что-то упускаю?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
106
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

мой код разбивается на новую строку (хорошо)

Ваш код не разбивается на новую строку; это только так кажется из-за того, как вы печатаете вещи. Ваш массив содержит один элемент, а не два. В середине элемента есть новая строка, и вы просто печатаете 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;
split ' ', $arr, безусловно, самый элегантный выбор, но split /[\s\n]+/, $arr может быть немного более понятным для нас, новичков.
Tom Williams 17.11.2022 14:11

@TomWilliams Только за несколько секунд до того, как вы узнаете, что означает ' ', что вы можете прочитать в perldoc split. Кроме того, это распространяет ложь: что \s не содержит \n. Ничего хорошего из этого не выйдет.

TLP 19.11.2022 10:52

@TomWilliams, я не согласен. [\s\n] — это ужасный способ писать \s. Это означает, что \s не соответствует \n, что неверно, сбивает с толку и вводит в заблуждение. /// Думаете, \s соответствует только пробелу? Это неправильно. Как говорится в ответе, он соответствует любому из 25 пробельных символов. Сюда входят горизонтальные пробелы (\h, 18) и вертикальные пробелы (\v, 7). Последнее включает в себя перевод строки, который также соответствует \n.

ikegami 20.11.2022 17:09

@TomWilliams Кроме того, split ' ' не эквивалентен split /\s+/, как объясняет мой ответ, поэтому нельзя просто использовать split /\s+/ (или split /[\s\n]+/), как вы предлагаете. /// И тебе лучше научиться split ' ' очень быстро. ' ' используется по умолчанию для первого аргумента, что приводит к таким конструкциям, как while (<>) { my @fields = split; ... }. Это также операция, выполненная qw. qw( ... ) эквивалентно split ' ', q( ... ). Они оба довольно распространены, поэтому делать вид, что их не существует, было бы плохой услугой.

ikegami 20.11.2022 17:12

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

Если вы хотите избежать этой ошибки в будущем и точно знать, что содержат ваши переменные, вы можете использовать основной модуль 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 — отличный инструмент для отладки ваших данных и полезный инструмент для изучения.

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