Распаковка Perl ("A4 / A *") длина + байты синтаксиса в форме регулярного выражения - PullRequest
3 голосов
/ 16 марта 2012

Как подробно описано в perlpacktut, вы можете использовать распакованную строку X / Y *, чтобы сначала получить длину потока байтов, а затем прочитать именно столько байтов.Однако я пытаюсь найти что-то подобное в регулярном выражении, скажем, с простыми числами и строками ASCII.Например, строка в закодированном виде имеет вид:

[length]:[bytes]
4:spam
4:spam10:green eggs

Я помню, как однажды смог сделать это, но только с использованием ?? {}, и у меня нет кодапрямо сейчасМожно ли это сделать без ?? {} (что является сверхэкспериментальным), используя одну из более новых 5.10 записей / обратных ссылок?

Очевидное выражение не работает:

/(\d+)\:(.{\1})/g
/(\d+)\:(.{\g-1})/g

Ответы [ 2 ]

3 голосов
/ 16 марта 2012

Делайте это с регулярным выражением с флагом /g и якорем \G, но в скалярном контексте. Это сохраняет позицию в строке сразу после последнего совпадения с образцом (или начала для первого). Вы можете идти вдоль струны таким образом. Получить длину, пропустить через двоеточие, а затем использовать substr, чтобы подобрать нужное количество символов. Вы можете присвоить pos, поэтому обновите его для символов, которые вы только что извлекли. redo что пока у вас больше нет совпадений:

use v5.10.1;

LINE: while( my $line = <DATA> ) {
    chomp( $line );
    {
    say $line;
    next LINE unless $line =~ m/\G(\d+):/g;  # scalar /g!
    say "\t1. pos is ", pos($line); 
    my( $length, $string ) = ( $1, substr $line, pos($line), $1 );
    pos($line) += $length; 
    say "\t2. pos is ", pos($line); 
    print "\tFound length $length with [$string]\n";
    redo;
    }
    }

__END__
4:spam6:Roscoe
6:Buster10:green eggs
4:abcd5:123:44:Mimi

Обратите внимание на край в последней строке ввода. Это 3: является частью строки, а не новой записи. Мой вывод:

4:spam6:Roscoe
    1. pos is 2
    2. pos is 6
    Found length 4 with [spam]
4:spam6:Roscoe
    1. pos is 8
    2. pos is 14
    Found length 6 with [Roscoe]
4:spam6:Roscoe
6:Buster10:green eggs
    1. pos is 2
    2. pos is 8
    Found length 6 with [Buster]
6:Buster10:green eggs
    1. pos is 11
    2. pos is 21
    Found length 10 with [green eggs]
6:Buster10:green eggs
4:abcd5:123:44:Mimi
    1. pos is 2
    2. pos is 6
    Found length 4 with [abcd]
4:abcd5:123:44:Mimi
    1. pos is 8
    2. pos is 13
    Found length 5 with [123:4]
4:abcd5:123:44:Mimi
    1. pos is 15
    2. pos is 19
    Found length 4 with [Mimi]
4:abcd5:123:44:Mimi

Я подумал, что для этого может быть модуль, и есть: Bencode . Это делает то, что я сделал. Это значит, что я проделал много работы даром. Всегда сначала смотрите на CPAN. Даже если вы не используете модуль, вы можете посмотреть на их решение:)

1 голос
/ 16 марта 2012

Нет, я не думаю, что это возможно без использования (??{ ... }), которое будет:

/(\d++):((??{".{$^N}"}))/sg
...