Могу ли я использовать распаковку Perl, чтобы разбить строку на переменные? - PullRequest
3 голосов
/ 08 октября 2009

У меня есть имя файла изображения, которое состоит из четырех частей:

  1. $Directory (каталог, в котором находится изображение)
  2. $Name (для художественного сайта это ссылка на название картины #)
  3. $File (имя файла изображения минус расширение)
  4. $Extension (расширение изображений)
$example 100020003000.png

Который я хочу соответственно разбить:

$dir=1000 $name=2000 $file=3000 $ext=.png

Мне было интересно, является ли substr лучшим вариантом для разбивки входящего $example, поэтому я могу делать что-то с 4 переменными, такими как проверка / проверка ошибок, получение подробного имени из присвоения $Name или что-то еще. Я нашел этот пост:

распаковывается быстрее чем substr? Итак, у моих новичков подход «каменный инструмент»:

my $example = "100020003000.png";
my $dir = substr($example, 0,4);
my $name = substr($example, 5,4);
my $file = substr($example, 9,4);
my $ext = substr($example, 14,3); # will add the the  "." later #

Так, я могу использовать распаковку, или, может быть, даже другой подход, который был бы более эффективным?

Я также хотел бы избегать загрузки каких-либо модулей, если для этого не потребуется меньше ресурсов по какой-либо причине. Моды - это отличный инструмент, который я люблю, но, думаю, здесь не нужен.

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

Спасибо всем на stackoverflow.com!

Ответы [ 5 ]

12 голосов
/ 08 октября 2009

Абсолютно:

my $example = "100020003000.png";
my ($dir, $name, $file, $ext) = unpack 'A4' x 4, $example;

print "$dir\t$name\t$file\t$ext\n";

Выход:

1000    2000    3000    .png
5 голосов
/ 08 октября 2009

Я бы просто использовал для этого регулярное выражение:

my ($dir, $name, $file, $ext) = $path =~ m:(.*)/(.*)/(.*)\.(.*):;

Или, чтобы соответствовать вашему конкретному примеру:

my ($dir, $name, $file, $ext) = $example =~ m:^(\d{4})(\d{4})(\d{4})\.(.{3})$:;
3 голосов
/ 08 октября 2009

Использование unpack хорошо, но поскольку элементы имеют одинаковую ширину, регулярное выражение также очень простое:

my $example = "100020003000.png";
my ($dir, $name, $file, $ext) = $example =~ /(.{4})/g;
1 голос
/ 08 октября 2009

Это не распаковка, но, поскольку у вас есть группы из 4 символов, вы можете использовать ограниченный сплит с захватом:

my ($dir, $name, file, $ext) = grep length, split /(....)/, $filename, 4;

Это довольно запутанно, так что я, вероятно, не буду его использовать, но захват в сплите - часто пропускаемая способность.

Итак, вот объяснение того, что делает этот код:

Шаг 1. split с захватом скобок добавляет значения, захваченные шаблоном, в его выходной поток. Поток содержит смесь полей и разделителей.

qw( a 1 b 2 c 3 ) == split /(\d)/, 'a1b2c3';

Шаг 2. split с 3 аргументами ограничивает, сколько раз строка разбивается.

qw( a b2c3 ) == split /\d/, 'a1b2c3', 2;

Шаг 3. Теперь, когда мы используем шаблон разделителя, который почти соответствует чему угодно /(....)/, мы получаем кучу пустых (длиной 0) строк. Я пометил разделители D символами, а поля F:

 ( '', 'a', '', '1', '', 'b', '', '2' ) == split /(.)/, 'a1b2';
   F    D   F    D   F    D   F    D

Шаг 4. Итак, если мы ограничим количество полей до 3, мы получим:

 ( '', 'a', '', '1', 'b2' ) == split /(.)/, 'a1b2', 3;
   F    D   F    D   F  

Шаг 5. Собрав все это вместе, мы можем сделать это (я использовал расширение .jpeg, чтобы расширение было длиннее 4 символов):

 ( '', 1000, '', 2000, '', 3000, '.jpeg' ) = split /(....)/, '100020003000.jpeg',4;
   F   D     F   D     F   D     F       

Шаг 6. Шаг 5 почти идеален, все, что нам нужно сделать, это удалить пустые строки, и мы в порядке:

(1000, 2000, 3000, '.jpeg') = длина grep, split /(....)/, '100020003000.jpeg', 4;

Этот код работает, и это интересно. Но это не более компактно, чем любое другое решение. Я не тестировал, но был бы очень удивлен, если бы он выиграл какие-либо призы за скорость или эффективность памяти.

Но настоящая проблема в том, что слишком сложно быть хорошим для реального кода. Использование split для захвата разделителей (и, может быть, одного последнего поля), в то время как выбрасывание данных поля просто слишком странно. Это также хрупко: если одно поле меняет длину, код нарушается и должен быть переписан.

Итак, на самом деле этого не делают.

По крайней мере, это дало возможность изучить некоторые менее известные особенности split.

0 голосов
/ 08 октября 2009

И substr, и unpack смещают ваше мышление к фиксированной компоновке, в то время как решения регулярных выражений больше ориентированы на гибкую компоновку с разделителями.

Пример, который вы привели, казался фиксированной версткой, но каталоги обычно отделяются от имен файлов разделителем (например, косая черта для файловых систем в стиле POSIX, обратная косая черта для MS-DOS и т. Д.) для обоих; решение регулярного выражения для разделения каталога и имени файла (или даже каталога / имени / расширения), а затем подход фиксированной длины для части имени сам по себе.

...