Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Не могу найти как исправить


Автор: worsvch 28.5.2009, 09:02
#!/perl -w

use strict;
use Encode qw(from_to);

system('cls');

my @str;
my $x = 0;
my @tags = ("Surname","Name","Age");
my @klassf = ("Фамилия","Имя","Возраст");

sub parseStr {
    my $klsf = shift(@_);
    my $match = shift(@_); 
    my $var = shift(@_);
    if ($str[$x] =~ m/<$var>(\W+)<\/$var>/) {    
       from_to($klsf,"cp1251","cp866");
       print "$klsf: $match\n";
    }
    elsif ($str[$x] =~ m/<$var>(\d+)<\/$var>/) {    
       from_to($klsf,"cp1251","cp866");
       print "$klsf: $match\n";
    }        
}

open XML, "< test.xml" or die "can't find file test.xml";
 while (<XML>) {
       push @str, $_;
       from_to($str[$x],"cp1251","cp866");    
       for (my $y = 0;$y <= 2;$y++) {
           parseStr($klassf[$y],$1,$tags[$y]);
       }
       $x++;       
 }
close XML;

Результат выходит такой:

Use of uninitialized value $match in concatenation (.) or string at c:\...\test.pl line 19, <XML> line 3.
Фамилия:
Use of uninitialized value $match in concatenation (.) or string at c:\...\test.pl line 19, <XML> line 4.
Имя:
Use of uninitialized value $match in concatenation (.) or string at c:\...\test.pl line 23, <XML> line 5.
Возраст:

А вот xml:
<?xml version="1.0" encoding="windows-1251"?>
<root>
 <Surname>Иванов</Surname>
 <Name>Иван</Name>
 <Age>23</Age>
</root>

Все файлы тестовые но скоро придется делать скрипт для настоящих, поэтому и прошу вас помочь разобраться

Автор: amg 28.5.2009, 09:41
Ой, лень разбираться, но в в подобных случаях лучше использовать хэш, а не массивы. Вкратце, так:
Код
my %tags = (Surname=>'Фамилия', Name=>'Имя' ,Age=>'Возраст');
my %result;

open XML, "<", "test.xml" or die "Can't open file test.xml: $!\n";
while (<XML>) {
  $result{$1} = $2 if m/<(\w+)>(.*?)<\/\1>/ && exists $tags{$1};
}
close XML;

print "$tags{$_}: $result{$_}\n" foreach keys %result;


Автор: shurf 28.5.2009, 09:59
Ага, а я разобрался в этом коде. Вот так работает:

Код

#!/perl -w

use strict;
use Encode qw(from_to);

system('cls');

my @str;
my $x = 0;
my @tags = ("Surname","Name","Age");
my @klassf = ("Фамилия","Имя","Возраст");

sub parseStr {
    my $klsf = shift(@_);
    my $match = shift(@_); 
    my $var = shift(@_);
    if ($str[$x] =~ m/<$var>(\W+)<\/$var>/) {    
       from_to($klsf,"cp1251","cp866");
       $match = eval "$match";
       print "$klsf: $match\n";
    }
    elsif ($str[$x] =~ m/<$var>(\d+)<\/$var>/) {    
       from_to($klsf,"cp1251","cp866");
       $match = eval "$match";
       print "$klsf: $match\n";
    }        
}

open XML, "< test.xml" or die "can't find file test.xml";
 while (<XML>) {
       push @str, $_;
       from_to($str[$x],"cp1251","cp866");    
       for (my $y = 0;$y <= 2;$y++) {
           parseStr($klassf[$y],'$1',$tags[$y]);
       }
       $x++;       
 }
close XML;


Вторым параметром parseStr надо передавать не переменную, строку.
А потом эту строку выполнять как выражение с помощью eval

Автор: worsvch 1.6.2009, 08:28
Цитата(shurf @ 28.5.2009,  09:59)
Ага, а я разобрался в этом коде. 

Вторым параметром parseStr надо передавать не переменную, строку.
А потом эту строку выполнять как выражение с помощью eval

Я попробовал сделать как Вы сказали, вместо данных, во всех строках выходит $1. А с eval делал, вообще какая-то чушь выходит. Может делал чего неправильно?  smile 

Автор: mvsgt 1.6.2009, 09:56
Переписывайте скрипт целиком. Работать в реальной системе он не будет. Например, parseStr($klassf[$y],$1,$tags[$y]); - очень странная строка, столько ошибок может породить...  Вообще XML лучше парсить стандартными средствами.

$match = eval "$match";  - это вообще перл...


Автор: gcc 1.6.2009, 13:48
Код

#use strict;

Автор: shurf 1.6.2009, 22:48
Цитата(mvsgt @  1.6.2009,  08:56 Найти цитируемый пост)
$match = eval "$match";  - это вообще перл...

Ну да, не ассемблер.

Человек попросил исправить программу...

Цитата(worsvch @  1.6.2009,  07:28 Найти цитируемый пост)
Я попробовал сделать как Вы сказали, вместо данных, во всех строках выходит $1. А с eval делал, вообще какая-то чушь выходит. Может делал чего неправильно?

Какую чушь? Может быть что-то не так с кодировками? Я проверял под linux - выводит в cp866.

$1 выводит, если не использовать $match = eval "$match", или использовать, но с одинарными кавычками.

Автор: shamber 1.6.2009, 23:28
Цитата(shurf @  1.6.2009,  22:48 Найти цитируемый пост)
Ну да, не ассемблер.

я думаю, тут перл совсем не язык программирования smile

Автор: worsvch 2.6.2009, 17:47
Цитата(shurf @ 1.6.2009,  22:48)
Цитата(worsvch @  1.6.2009,  07:28 Найти цитируемый пост)
Я попробовал сделать как Вы сказали, вместо данных, во всех строках выходит $1. А с eval делал, вообще какая-то чушь выходит. Может делал чего неправильно?

Какую чушь? Может быть что-то не так с кодировками? Я проверял под linux - выводит в cp866.

$1 выводит, если не использовать $match = eval "$match", или использовать, но с одинарными кавычками.

С кодировками никаких проблем, в консоли все на русском языке выходит.
Я имел ввиду, что вместо данных из xml файла выходит $1. Перепроверю код еще раз, может чего не усмотрел

Добавлено через 4 минуты и 44 секунды
Цитата(shamber @ 1.6.2009,  23:28)
Цитата(shurf @  1.6.2009,  22:48 Найти цитируемый пост)
Ну да, не ассемблер.

я думаю, тут перл совсем не язык программирования smile

Вот Вам смешно smile А вот хотелось бы увидеть Ваш совет или даже лучше образец кода, как совет человека продвинутого в программировании на языке perl.

Автор: DaemonSuw 2.6.2009, 19:06
parseStr($klassf[$y],$1,$tags[$y]); откуда берется переменная $1? 

Автор: worsvch 2.6.2009, 19:13
Цитата(DaemonSuw @ 2.6.2009,  19:06)
parseStr($klassf[$y],$1,$tags[$y]); откуда берется переменная $1?

  if ($str[$x] =~ m/<$var>(\W+)<\/$var>/) - переменная $1 - берется из этого шаблона, по идее она должна быть равна следующим значениям, выдранным из xml-файла:
Иванов
Иван
23

Автор: KSURi 2.6.2009, 19:55
$1 - лексическая переменная, со всеми вытекающими

Автор: worsvch 2.6.2009, 20:13
Цитата(KSURi @ 2.6.2009,  19:55)
$1 - лексическая переменная, со всеми вытекающими

Что это означает?  smile 

Автор: shurf 2.6.2009, 23:46
Цитата(worsvch @  2.6.2009,  16:47 Найти цитируемый пост)
Я имел ввиду, что вместо данных из xml файла выходит $1. Перепроверю код еще раз, может чего не усмотрел

Раз выводится $1, значит не работал eval.

eval "$match" или eval $match возвращает значение выражения, хранящегося в переменной $match.
В данном случае eval должен вернуть значение переменной $1

eval '$match' или eval{$match} возвращает значение переменной $match
То есть строку '$1'.

У меня код работает правильно. Я проверял под Linux, perl v5.8.8

PS Попробуй отключить режим strict, как предложил gcc

Автор: KSURi 3.6.2009, 09:10
Цитата(worsvch @  2.6.2009,  20:13 Найти цитируемый пост)
Что это означает?  smile  

Код

$ perl
{
  'string' =~ /(.+)/;
  print $1,$/;
}
print $1||'<undef>',$/
^D
string
<undef>
$


perldoc perlvar

Автор: mvsgt 3.6.2009, 13:36
Цитата(worsvch @  2.6.2009,  17:47 Найти цитируемый пост)
Вот Вам смешно smile А вот хотелось бы увидеть Ваш совет или даже лучше образец кода, как совет человека продвинутого в программировании на языке perl. 


Мой совет - полностью исключить использование глобальных переменных всех видов, пока не научитесь писать без них.
eval "lalala" тоже. И выставляя скрипт, писать что он должен сделать.

Вот критика исходной программы, может быть поможет:
Цитата(worsvch @  28.5.2009,  09:02 Найти цитируемый пост)
#!/perl -w

use strict;
use Encode qw(from_to);

system('cls'); 
идеологически неправильно. Лучше вызывать cls && perl -w script.pl - эффект тот же

my @str;
my $x = 0;
my @tags = ("Surname","Name","Age");
my @klassf = ("Фамилия","Имя","Возраст");

Переменные объявлены до функции. С одной стороны они для неё доступны как глобальные, с другой стороны они доступны как замыкания, что может породить неожиданные эффекты.

sub parseStr {
    my $klsf = shift(@_); 
Запись my $var=shift; является устоявшейся и более понятной.
    my $match = shift(@_); 
    my $var = shift(@_);
    if ($str[$x] =~ m/<$var>(\W+)<\/$var>/) {    
Что-то мне подсказывает, что Вы хотели использовать $1, но не использовали. Или ниже именно отсюда?
       from_to($klsf,"cp1251","cp866");
       print "$klsf: $match\n";
Совет: для отладки использовать warn, или даже что-тоиз Carp - в больших скриптах будет удобнее.
    }
    elsif ($str[$x] =~ m/<$var>(\d+)<\/$var>/) {    
       from_to($klsf,"cp1251","cp866");
       print "$klsf: $match\n";
    }        
Не понятен результат, который Вы получаете - перекодировка и print всегда при совпадениях, возможно тут ошибка.
}

open XML, "< test.xml" or die "can't find file test.xml";
 while (<XML>) {
       push @str, $_;
       from_to($str[$x],"cp1251","cp866");    
       for (my $y = 0;$y <= 2;$y++) {
           parseStr($klassf[$y],$1,$tags[$y]);
Что тут делает $1 ? Может быть, предполагалось использовать её из регекспа в parseStr?
       }
       $x++;       
 }
close XML;


Автор: DaemonSuw 3.6.2009, 15:30
Цитата

\w  Match "word" character (alphanumeric plus "_")
\W  Match non-word character

$1 - лучше заменить на объявленную переменную так как

Код

sub hello_world
{
  'string' =~ /(.+)/;
  print $1,$/;
}

hello_world;
print $1||'<undef>',$/


Цитата

string
<undef>

Автор: worsvch 4.6.2009, 12:33
Всё, всем спасибо. Заработало:

Код

#!/perl -w

use strict;
use Encode qw(from_to);

my @str;
my $x = 0;
my @tags = ("Surname","Name","Age");
my @klassf = ("Фамилия","Имя","Возраст");

sub parseStr {
    my $klsf = shift;
    my $match = shift; 
    my $var = shift;
    if ($str[$x] =~ m/<$var>(\W+)<\/$var>/) {    
       from_to($klsf,"cp1251","cp866");
       print "$klsf: $1\n";
    }
    elsif ($str[$x] =~ m/<$var>(\d+)<\/$var>/) {    
       from_to($klsf,"cp1251","cp866");
       print "$klsf: $1\n";
    }        
}

open XML, "< test.xml" or die "can't find file test.xml";
 while (<XML>) {
       push @str, $_;
       from_to($str[$x],"cp1251","cp866");    
       for (my $y = 0;$y <= 2;$y++) {
           parseStr($klassf[$y],'$1',$tags[$y]);
       }
       $x++;       
 }
close XML;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)