Forum Webscript.Ru
Программирование => Perl => Тема начата: Forza от 05 Августа 2004, 19:14:10
-
Имеются непонятные проблемы с функцией substr(), предназначенной в том числе и для вставки текста в строку.
Например, я хочу вставить текст, "раздвинув" символы вокруг. Я пишу:
substr ($lines[$i], $pos, 0) = \'a\'
or die ("length: " . length($lines[$i]) . ", pos: " . $pos)
Без die() Апач выдаёт следующую ошибку: substr outside of string at.... С die() он пишет то, что я и просил: length: 151, pos: 105 at....
Вопрос в том, как же substr может быть outside of string, если альтернативное сообщение об ошибке показывает, что позиция намного меньше длины строки.
С меньшими значениями $pos работает нормально.
-
perldoc perldiag
substr outside of string
(W substr),(F) You tried to reference a substr() that
pointed outside of a string. That is, the absolute
value of the offset was larger than the length of the
string. See "substr" in perlfunc. This warning is
fatal if substr is used in an lvalue context (as the
left hand side of an assignment or as a subroutine
argument for example).
-
NeoNox, я сразу понял, что Perl считает, что я с substr() "вылез" за границы строки.
Но я же привёл пример, что он в die() выводит то, что изменяемая позиция на ~50 символов меньше, чем размер строки!!!
Почему? :insane:
-
Forza какой у тебя Perl? или приведи свои данные переменных.
DB<1> $lines[$i] = \'abcd\'
DB<2> $pos = 1
DB<3> substr ($lines[$i], $pos, 0) = \'a\'
DB<4> print $lines[$i]
aabcd
-
NeoNox:
какой у тебя Perl?
Active Perl 5.8.
NeoNox:
приведи свои данные переменных
С этими переменными вне проги всё ок, а в проге они используются следующим образом (посмотри, пожалуйста, я постараюсь максимально понятно откомментировать).
Прога читает данные из текстового файла, организованнные в виде таблицы (разделители - пробелы), далее анализирует таблицу и выделяет в ней столбцы (сохраняет № позиции в строке для каждого столбца), далее каждый столбец должен быть выделен особым цветом с помощью тега .
my @lines;
#пример строки из исходного текстового файла
push (@lines, "1 Абдряшевская СОШ 453630, д. Абдряшево
1 да Зайнуллин нач. (34772)");
my @array;
/*Анализ файла убираем, сразу пишу те позиции столбцов, которые должны быть. Использую массив хешей, т.к. на самом деле помимо позиций столбцов надо хранить ещё другую информацию*/
push (@array, {pos=>0}, {pos=>5}, {pos=>24}, {pos=>47}, {pos=>56}, {pos=>72}, {pos=>87}, {pos=>99});
#массив цветов
my @colors = (\'green\',\'white\');
#перебираем все строки исходного файла
foreach $i (0..$#lines)
{
#перебираем все столбцы
foreach $j (0..$#array) {
#если это первый столбец, открываем тег
substr ($lines[$i], $array[$j]->{pos}, 0) = \'\'
if $j==0;
/*Если столбец не первый, надо закрыть предыдущий тег и открыть новый. К позиции столбца в текстовом файле надо добавить 37 (длина открывающего тега ) для предыдущего столбца и 44 (длина открывающего и закрывающего тегов ) для всех обработанных столбцов кроме предыдушего*/
my $pos = 37 + $array[$j]->{pos} + 44*($j-1);
my $old_line = $lines[$i];
substr ($lines[$i], $pos, 0, \'\')
or die ("length: ".length($lines[$i]).", pos: ".$pos.", : ".$j. "\\nline: \'".$lines[$i]."\'" ."\\nold_line: \'".$old_line."\', old_length: ".length($old_line))
if $j>=1;
}
$lines[$i] .= "";
#замену пробелов на пока уберём
$page .= tt($lines[$i]) . br();
}
print $page;
exit(0);
Как видно die() выводит отладочную информацию такую как содержимое и длина строки до и после substr(), а также позиция, на которую вставляется новый текст. Программа вылетает при $j=1, но при этом die() выдаёт, что строка с тегами была добавлена в исходную строку, т.е. $old_line отличается от $line[$i], а именно:
length: 187, pos: 42, j: 1
line: \'1 Абдряшевская СОШ 453630, д. Абдряшево 1 да Зайнуллин нач. (34772)\'
old_line: \'1 Абдряшевская СОШ 453630, д. Абдряшево 1 да
Зайнуллин нач. (34772)\', old_length: 143 at a.pl line 14.
Как ещё можно "окружить" тегами часть строки, если я знаю значение начальной и конечной позиции? s/// не предлагать, т.к. значения столбцов не уникальны для строки.
-
у меня этот код работает на.
я бы тебе посоветовал вывести в отладку переменные
$array[$j]->{pos}
$pos
вероятно на твоих реальных данных результат может быть иным.
-
код:
#!/usr/bin/perl
my @lines;
#пример строки из исходного текстового файла
push (@lines, "1 Абдряшевская СОШ 453630, д. Абдряшево
1 да Зайнуллин нач. (34772)");
my @array;
push (@array, {pos=>0}, {pos=>5}, {pos=>24}, {pos=>47}, {pos=>56}, {pos=>72}, {pos=>87}, {pos=>99});
#массив цветов
my @colors = (\'green\',\'white\');
#перебираем все строки исходного файла
foreach $i (0..$#lines)
{
#перебираем все столбцы
foreach $j (0..$#array) {
#если это первый столбец, открываем тег
substr ($lines[$i], $array[$j]->{pos}, 0) = \'\'
if $j==0;
my $pos = 37 + $array[$j]->{pos} + 44*($j-1);
my $old_line = $lines[$i];
substr ($lines[$i], $pos, 0, \'\') if $j>=1;
}
$lines[$i] .= "";
#замену пробелов на пока уберём
$page .= $lines[$i];
}
print $page;
exit(0);
результат:
1 Абдряшевская СОШ 453630, д. Абдряшево
1 да Зайнуллин нач. (34772)
-
perl -v
This is perl, v5.8.0 built for i686-linux
-
NeoNox:
я бы тебе посоветовал вывести в отладку переменные
$array[$j]->{pos}
$pos
$pos и так есть в отладке. См. первую строку: length: 187, pos: 42, j: 1.
А $array[$j]->{pos} не нужен, т.к. на его основе высчитывается $pos, который в дальнейшем используется и показывается в отладке.
NeoNox:
вероятно на твоих реальных данных результат может быть иным.
Дело в том, что у меня и с этой одной строкой, которую я привёл в примере, ничего не получается. :-(
Как раз сообщение об ошибке от die(), которое я указал внизу предыдущей мессаги, и относится именно к этому примеру.
Мда, странно всё.
Попробую тогда по-иному: доставать из $lines[$i] куски строки, обрамлять их тегами и результат сразу же записывать в $page.
-
Если я правильно понял задачу, то все делается значительно проще
use strict;
my $format = \'a5a19a23a9a16a15a12a7\';
my @colors = (\'green\',\'white\');
my $i = 0;
while ( ) {
print map { \'\'.$_->[1]."\\n" }
map { [$_ =~ s/ +$//g,$_]}
unpack($format, $_);
}
__DATA__
1 Абдряшевская СОШ 453630, д. Абдряшево 1 да Зайнуллин нач. (34772)