В Perl я могу рассматривать строку как байтовый массив? - PullRequest
6 голосов
/ 18 июня 2010

В Perl уместно ли использовать строку как байтовый массив, содержащий 8-битные данные?Вся документация по этой теме, которую я могу найти, сосредоточена на 7-битных строках.

Например, если я читаю некоторые данные из двоичного файла в $data

my $data;

open FILE, "<", $filepath;
binmode FILE;
read FILE $data 1024;

и хочу* вывести первый байт, substr($data,1,1) уместно?(опять же, предполагая, что это 8-битные данные)

Я пришел в основном из C-фона и привык передавать указатель char на функцию read().Моя проблема может заключаться в том, что я не понимаю, каково базовое представление строки в Perl.

Ответы [ 6 ]

6 голосов
/ 18 июня 2010

Прилагаемая документация для команды read, воспроизведенная здесь, содержит много информации, относящейся к вашему вопросу.

read FILEHANDLE,SCALAR,LENGTH,OFFSET

read FILEHANDLE,SCALAR,LENGTH

Пытается прочитать ДЛИНУ символов данных в переменную SCALAR из указанного FILEHANDLE.Возвращает количество фактически прочитанных символов, 0 в конце файла или undef, если произошла ошибка (в последнем случае также устанавливается $!).SCALAR будет увеличен или уменьшен, так что последний прочитанный символ является последним символом скаляра после чтения.

Можно указать OFFSET, чтобы поместить данные чтения в какое-то место строки, отличной от начала.,Отрицательное значение OFFSET указывает на размещение такого количества символов, считая в обратном направлении от конца строки.Положительное значение OFFSET, превышающее длину SCALAR, приводит к тому, что строка дополняется до требуемого размера байтами «\ 0» до добавления результата чтения.

Вызов фактически реализован в терминах любого Perlили системный вызов fread ().Чтобы получить истинный системный вызов read (2), см. «Sysread».

Обратите внимание на символов : в зависимости от состояния дескриптора файла (8-битные) байты или символычитать. По умолчанию все файловые дескрипторы работают с байтами, но, например, если файловый дескриптор был открыт со слоем ввода / вывода ": utf8" (см. "Open" и прагма "open", open), I / Oбудет работать с символами Unicode в кодировке UTF-8, а не с байтами. Аналогично для прагмы ": encoding": в этом случае почти любые символы могут быть прочитаны.

2 голосов
/ 18 июня 2010

См. perldoc -f pack и perldoc -f unpack , чтобы узнать, как обрабатывать строки как байтовые массивы.

1 голос
/ 31 октября 2012

Строки - это строки «символов», которые больше байта. 1 Вы можете хранить байты в них и манипулировать ими, как будто они являются символами, принимая substr с и т. Д. и пока вы просто манипулируете сущностями в памяти, все довольно красиво. Хранение данных странное, но это, в основном, не ваша проблема. 2

Когда вы пытаетесь читать и писать из файлов, тот факт, что ваши символы могут не отображаться в байтах, становится важным и интересным. Не говоря уже о раздражении. Это раздражение на самом деле немного усугубляется тем, что Perl пытается сделать то, что вы хотите, в обычном случае: если все символы в строке помещаются в байт, и вы оказались в ОС, отличной от Windows, у вас фактически нет делать что-то особенное для чтения и записи байтов. Однако Perl будет жаловаться, если вы сохранили символ размером не в байт и попытаетесь написать его, не давая понять, что с ним делать.

Это становится немного далеко, в основном потому, что кодирование - большая и запутанная тема. Позвольте мне оставить это там с некоторыми ссылками: Посмотрите на Encode (3perl) , open (3perl) , perldoc open и perldoc binmode для множества веселых и кровавых деталей.

Итак, краткий ответ: «Да, вы можете обращаться со строками, как если бы они содержали байты, если на самом деле они содержат байты, что вы можете убедиться, только читая и записывая байты».

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

2 : Для записи строки в Perl внутренне представлены структурой данных, называемой «PV», которая помимо символьного указателя знает такие вещи, как длина строки и текущее значение pos. 3

3 : Ну, он начнет хранить текущее значение pos, если станет интересным. Смотри также

use Devel::Peek;

my $x = "bluh bluh bluh bluh";
Dump($x);
$x =~ /bluh/mg;
Dump($x);
$x =~ /bluh/mg;
Dump($x);
1 голос
/ 18 июня 2010

Возможно, вы захотите использовать sysopen и sysread , если хотите прочитать байты из двоичного файла.

См. Также perlopentut .

Уместно ли это или необходимо, зависит от того, что именно вы пытаетесь сделать.

#!/usr/bin/perl -l

use strict; use warnings;
use autodie;

use Fcntl;

sysopen my $bin, 'test.png', O_RDONLY;
sysread $bin, my $header, 4;

print map { sprintf '%02x', ord($_) } split //, $header;

Вывод:

C:\Temp> t
89504e47
0 голосов
/ 31 октября 2012

Позвольте мне просто опубликовать небольшой пример обработки строки как двоичного массива - поскольку мне самому было трудно поверить, что нечто, называемое "substr", будет обрабатывать нулевые байты;но, по-видимому, это так - ниже приведен фрагмент сеанса терминала отладчика perl (с использованием как строкового, так и массива / списка):

$ perl -d

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

^D
Debugged program terminated.  Use q to quit or R to restart,
  use o inhibit_exit to avoid stopping after program termination,
  h q, h R or h o to get additional info.  

  DB<1> $str="\x00\x00\x84\x00"

  DB<2> print $str
�
  DB<3> print unpack("H*",$str) # show content of $str as hex via `unpack`
00008400
  DB<4> $str2=substr($str,2,2)

  DB<5> print unpack("H*",$str2)
8400
  DB<6> $str2=substr($str,1,3)

  DB<7> print unpack("H*",$str2)
008400

[...]

  DB<30> @stra=split('',$str); print @stra # convert string to array (by splitting at empty string)
�
  DB<31> print unpack("H*",$stra[3]) # print indiv. elems. of array as hex
00
  DB<32> print unpack("H*",$stra[2]) 
84
  DB<33> print unpack("H*",$stra[1]) 
00
  DB<34> print unpack("H*",$stra[0]) 
00
  DB<35> print unpack("H*",join('',@stra[1..3])) # print only portion of array/list via indexes (using flipflop [two dots] operator) 
008400
0 голосов
/ 18 июня 2010

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

Хотите преобразовать данные в массив Perl?Если так, то pack и unpack - хорошее начало.split также может пригодиться.

Хотите получить доступ к отдельным элементам строки, не распаковывая ее?Если это так, substr будет быстрым и сделает трюк для 8-байтовых данных.Если вам нужны другие битовые глубины, взгляните на функцию vec, которая отображает строку как битовый вектор.

Хотите отсканировать строку и преобразовать определенные байты в другие байты?Тогда конструкции s/// или tr/// могут быть полезны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...