Написать простой парсер:
sub parse {
my ($string_ref) = @_;
# check if the remaining string is a (x,y) group
if ($$string_ref =~ s/\A[(]//) {
my $first = parse($string_ref);
$$string_ref =~ s/\A[,]// or die "Expected a comma [,]";
my $second = parse($string_ref);
$$string_ref =~ s/\A[)]// or die "Expected a closing paren [)]";
return [$first, $second];
}
# check if we have a simple string
elsif ($$string_ref =~ s/\A([^,()]+)//) {
return $1;
}
else {
die "Expected [(] or [^,()]";
}
}
Это подпрограмма, которая называет себя для вложенных частей. Он ссылается на строку. Чтобы получить строку внутри этой ссылки, мы должны разыменовать ее: $$reference
. Чтобы создать ссылку, мы используем оператор \
: $reference = \$value
.
=~ s/.../.../
применяет замену на строку. В шаблоне \A
закрепляет в начале строки, тогда как [...]
- это класс символов . Поскольку вторая часть нашей подстановки пуста, соответствующая часть в начале строки удаляется.
Теперь my $str = "(((Q,(P,(O,(M,N)))),(B,A)),C)"; parse(\$str)
производит эту структуру данных:
[[["Q", ["P", ["O", ["M", "N"]]]], ["B", "A"]], "C"]
Следующая проблема заключается в придавить эту структуру данных в ваших строк. Снова мы можем написать рекурсивное решение, так как сглаживание всей структуры данных - это тот же процесс, что и выравнивание только части этой структуры данных.
sub flatten {
my ($data) = @_;
if (ref $data eq 'ARRAY') {
my ($first, $second) = @$data;
my ($first_str, @first_others) = flatten($first);
my ($second_str, @second_others) = flatten($second);
my $str = $first_str . $second_str;
my @others = (@first_others, @second_others, $str);
return $str, @others;
}
elsif (ref $data eq '') {
return $data;
}
else {
die "Unknown data type ", ref $data;
}
}
ref
встроенный возвращает тип ссылки. Если результатом является пустая строка, то значение не является ссылкой (в этом случае это была бы простая строка). Вышеприведенный код широко использует назначение списка: ($x, @y) = (1, 2, 3)
присваивает номера так, чтобы $x = 1
и @y = (2, 3)
. Это также работает, когда числа меньше - ($x, @y) = (1)
, @y
будет пустым. Также обратите внимание, что мы возвращаем либо одно значение (при выравнивании строки), либо несколько значений (при выравнивании содержимого паренов).
Применительно к этой структуре данных, мы получаем список:
(
"QPOMNBAC",
"MN",
"OMN",
"POMN",
"QPOMN",
"BA",
"QPOMNBA",
"QPOMNBAC",
)
Так как мы можем получить на выходе вы хотели?
use feature 'say';
my ($whole_string, @parts) = flatten(parse(\$str));
for my $i (0 .. $#parts) {
say $i + 1, "|", $parts[$i];
}
Который производит
1|MN
2|OMN
3|POMN
4|QPOMN
5|BA
6|QPOMNBA
7|QPOMNBAC
упорядочении внутри строки отличается хотели - вы, кажется, сортировали части в каждой почти круглые скобки в алфавитном порядке. Для этого нам нужно было что-то изменить внутри flatten
. Но, не зная, как именно вы хотите сортировать, это невозможно сделать.
Добро пожаловать в Stack Overflow! Пожалуйста, найдите минутку, чтобы прочитать [ask] документацию.Несмотря на то, что ваш вопрос касается темы, касающейся программирования, он просит нас полностью решить вашу проблему. Он также очень похож на домашнее задание. Нет ничего плохого в домашней работе, но вы должны думать об этом сами. Обманывать, позволяя кому-то решить проблему, укусит вас позже. Пожалуйста, подумайте о том, как это можно сделать. Просто подумайте о подходе/алгоритме и напишите это, если вы не можете сделать это в Perl. Мы ценим усилие здесь. :) – simbabque