Forum Webscript.Ru

Программирование => Perl => Тема начата: Forza от 05 Августа 2004, 19:14:10

Название: проблемы с substr()
Отправлено: 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 работает нормально.
Название: проблемы с substr()
Отправлено: NeoNox от 05 Августа 2004, 19:55:36
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).
Название: проблемы с substr()
Отправлено: Forza от 05 Августа 2004, 23:41:06
NeoNox, я сразу понял, что Perl считает, что я с substr() "вылез" за границы строки.
Но я же привёл пример, что он в die() выводит то, что изменяемая позиция на ~50 символов меньше, чем размер строки!!!  
Почему? :insane:
Название: проблемы с substr()
Отправлено: NeoNox от 06 Августа 2004, 00:16:47
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
Название: проблемы с substr()
Отправлено: Forza от 06 Августа 2004, 15:21:53
Цитировать
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/// не предлагать, т.к. значения столбцов не уникальны для строки.
Название: проблемы с substr()
Отправлено: NeoNox от 06 Августа 2004, 15:32:12
у меня этот код работает на.
я бы тебе посоветовал вывести в отладку переменные
$array[$j]->{pos}
$pos
вероятно на твоих реальных данных результат может быть иным.
Название: проблемы с substr()
Отправлено: NeoNox от 06 Августа 2004, 15:36:03
код:
#!/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)
Название: проблемы с substr()
Отправлено: NeoNox от 06 Августа 2004, 15:37:02
perl -v

This is perl, v5.8.0 built for i686-linux
Название: проблемы с substr()
Отправлено: Forza от 06 Августа 2004, 15:41:25
Цитировать
NeoNox:
я бы тебе посоветовал вывести в отладку переменные
$array[$j]->{pos}
$pos


$pos и так есть в отладке. См. первую строку: length: 187, pos: 42, j: 1.
А $array[$j]->{pos} не нужен, т.к. на его основе высчитывается $pos, который в дальнейшем используется и показывается в отладке.

Цитировать
NeoNox:
вероятно на твоих реальных данных результат может быть иным.

Дело в том, что у меня и с этой одной строкой, которую я привёл в примере, ничего не получается. :-(
Как раз сообщение об ошибке от die(), которое я указал внизу предыдущей мессаги, и относится именно к этому примеру.

Мда, странно всё.
Попробую тогда по-иному: доставать из $lines[$i] куски строки, обрамлять их тегами и результат сразу же записывать в $page.
Название: проблемы с substr()
Отправлено: vladsu от 07 Августа 2004, 03:48:13
Если я правильно понял задачу, то все делается значительно проще


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)