Работа с подстроками

Проблема

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

Решение

Функция substr предназначена для чтения и записи отдельных байтов строки:
$value = substr($string,   $offset,   $count);
$value = substr($string,   $offset);
substr($stnng,   $offset,   $count) = $newstring;
substr($string,   $offset) =          $newtail;
Функция unpack ограничивается доступом только для чтения, но при извлечении нескольких подстрок работает быстрее:
# Получить 5-байтовую строку, пропустить 3,
# затем две 8-байтовые строки, затем все остальное
($leading, $s1, $s2, $trailing) = 
unpack("A5 хЗ A8 A8 A*", $data);
# Деление на группы из пяти байт
@fivers = unpack("A5" x (length($string)/5), $string);

# Деление строки на отдельные символы
@chars = unpack("A1" x length($string), $string);

Комментарий

В отличие от многих языков, в которых строки представлены в виде массива байтов (или символов), в Perl они относятся к базовым типам данных. Это означает, что для работы с отдельными символами или подстроками применяется функция unpack или substr.
Второй аргумент функции substr (смещение) определяет начало интересующей вас подстроки; положительные значения отсчитываются от начала строки, а отрицательные — с конца. Если смещение равно 0, подстрока начинается с начала. Третий аргумент определяет длину подстроки.
$stnng = "This is what you have";
#		+012345678901234567890		Прямое индексирование (слева направо)
#		109876543210987654321-		Обратное индексирование (слева направо)
		0 соответствует 10,   20 и т.  д.
$first = substr($strinng,   0,   1);      # "Т"
$start = substr($string,	    5,   2);     # "is"
$rest  = substr($string,    13);          # "you have"
$last  = substr($string,    -1);          # "e"
$end   = substr($string,    -4);          # "have"
$piece = substr($strinng,   -8,   3);     # "you"
Однако функция substr позволяет не только просматривать части строки, но и изменять их. Дело в том, что substг относится к экзотической категории левосторонних функций, то есть таких, которым при вызове можно присвоить значение. К тому же семейству относятся функции vec, pos и keys (начиная с версии 5.004). При некоторой фантазии функции local и ту также можно рассматривать как левосторонние.
$string = "This is what you have";
print $string;
This  is  what  you  have
substr($string,   5,   2) = "wasn't";   # заменить "is" на "wasn't"
This wasn't  what  you   have
substr($string,   -12) = "ondrous";     # "This wasn't wondrous"
This   wasn't   wondrous
substr($string,   0,   1) = "";         # Удалить первый символ
his   wasn't   wondrous

substr($string,-10) = ""                # Удалить последние 10 символов
his   wasn't
Применяя оператор =" в сочетании с операторами s///, m// или tr///, можно заставить их работать только с определенной частью строки:
# =" применяется для поиска по шаблону
if (substr($string,   -10) =' /pattern/)  {
print "Pattern matches in last 10 characters\n";
}

# подставить "at" вместо "is",   ограничиваясь первыми пятью символами
substr($string,   0,   5) =" s/is/at/g;
Более того, подстроки даже можно поменять местами, используя с каждой стороны присваивания несколько вызовов substr:
# Поменять местами первый и последний символ строки
$а = "make a hat";
(substr($a,0,1),   substr($a,-1)) = (substr($a,-1),   substr($a,0,1));
print $a;
take  a  ham
Хотя функция unpack не является левосторонней, она работает значительно быстрее substr, особенно при одновременном извлечении нескольких величин. В отличие от substr она не поддерживает непосредственные смещения. Вместо этого символ "х" нижнего регистра с числом пропускает заданное количество байт в прямом направлении, а символ "X" верхнего регистра — в обратном направлении.
# Извлечение подстроки функцией unpack
$а = "То be or not to be";
$b = unpack("x6 A6", $a);      # Пропустить 6 символов, прочитать 6 символов
print $b;
or not
($b, $c) = unpack("x6 A2 X5 A2", $a);   # Вперед 6, прочитать 2;
                                        # назад 5, прочитать 2 
print  "$b\n$c\n";
or
be
Иногда строка «режется» на части в определенных позициях. Предположим, вам захотелось установить позиции разреза перед символами 8, 14, 20, 26 и 30 — в каждом из перечисленных столбцов начинается новое поле. В принципе можно вычислить форматную строку unpack - "А7 А6 А6 А4 А*", но программист на Perl по природе лепив и не желает попусту напрягаться. Пусть за него работает Perl. Воспользуйтесь приведенной ниже функцией cut2fmt
sub cut2fmt {
my(@positions) = @_;
my $template   = ' ' ;
my $lastpos   = 1;
foreach $place(@positions) {
$template .= "A" , ($place - $lastpos). " ";
$lastpos   = $place;
}
$template .= "А*";
return $template; 
}
$fmt = cut2fmt(8, 14, 20, 26, 30);
print "$fmt\n";
A7 A6 A6 A6 A4 A*
Возможности функции unpack выходят далеко за пределы обычной обработки текста. Она также о беспечивает преобразование между текстовыми и двоичными данными.

См. также

Описание функций unpack и substr



2013-09-10 17:05:19

Proverte kod v komentariyah gde pro list tam oshibki detskie




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: