использование неинициализированного значения $ line в строке ne

Я пишу программу сопоставления с образцом на perl ... но получаю сообщение об ошибке ... Я видел все предыдущие сообщения по этому поводу, но не нашел решения ... Так как я новичок в perl, поэтому я не получаю точно что это за ошибка ..

use of uninitialized value $line in string ne at line .. and in line ...

Я прикрепляю сюда файл perl

use strict;

use warnings;

my $line = "";

open(OUTFILE, ">output.txt") or die ("cannot open file.\n");

if(open(file1,"match.txt") or die "Cannot open file.\n"){
    $line = <file1>;

    while ($line ne "") {
    if (defined($line) && (line =~ m/\sregion\s/i)) {
        print OUTFILE ("$line")};
        $line = <file1>;  # Problem Here
        if (defined($line) && ($line =~ /\svth\s/)) {
            print OUTFILE ("$line")
            };

        $line = <file1>;  # Problem Here
    }
}

Мой файл match.txt содержит этот тип данных ..

Some text here

   region     Saturati   Saturati     Linear   Saturati   Saturati

    id        -2.1741m   -2.1741m   -4.3482m    2.1741m    2.1741m 

    vth     -353.9140m -353.9141m -379.2704m  419.8747m  419.8745m

Some text here  

Пожалуйста, решите проблему .... спасибо


person user3318901    schedule 18.02.2014    source источник
comment
Вы можете потерять if (...) вокруг open(...) or die "...".   -  person Jim Davis    schedule 18.02.2014
comment
Сразу после цикла while есть пустое слово line, и вам также следует использовать форму open с тремя аргументами. Также вы должны вместо этого использовать дескриптор файла для file1   -  person hmatt1    schedule 18.02.2014


Ответы (3)


Причина, по которой вы видите эти ошибки, заключается в том, что переменная $line содержит undef. Причина, по которой он содержит undef, заключается в том, что вы присвоили ему значение из readline() (<file1>) после файл подошел к концу eof. Это описано в perldoc -f readline:

В скалярном контексте каждый вызов считывает и возвращает следующую строку до тех пор, пока не будет достигнут конец файла, после чего последующий вызов возвращает «undef».

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

while (<$fh>) {
    ...
}

Это будет перебирать все строки в файле, пока не достигнет конца файла, после чего, как вы теперь знаете, readline возвращает undef, а цикл while завершается.

Это также означает, что вам не нужно проверять каждую вторую строку, определено ли $line или пусто. Более того, вы можете объединить свои регулярные выражения в одно и, как правило, удалить много избыточного кода:

while (<>) {
    if (/\b(?:region|vth)\b/i) {
        print;
    }
}

Это основная функциональность, которая вам нужна, и здесь я использую некоторые идиомы Perl: оператор «ромб» <> будет читать из имен файлов, которые вы передаете сценарию в качестве аргумента, или из STDIN, если аргументы не указаны. Многие встроенные функции используют переменную $_ по умолчанию, если не указан аргумент, что и делает print, и условие цикла while.

Вы также можете заметить, что я использую границу слов \b вместо пробелов \s в регулярном выражении, а также использую чередование | с скобками без фиксации (?:...), что означает, что оно может соответствовать одной из этих строк.

С помощью этого упрощенного сценария вы можете:

perl script.pl match.txt > output.txt

Чтобы указать имена ваших файлов.

person TLP    schedule 18.02.2014

Если вы ничего не можете прочитать, ваша строка вернется неопределенной ... вот почему вы видите это сообщение.

Кроме того, возможно, лучше проверить, что вы сначала открываете входной файл, прежде чем создавать выходной файл, так что что-то вроде этого:

open(INFILE,  "<match.txt")  or die "Cannot open input file";
open(OUTFILE, ">output.txt") or die "cannot open output file";

my $line;
while($line = <INFILE>){
    ...
}

Perl завершит цикл, если $ line не определено или пустая строка.

person ctschuster    schedule 18.02.2014
comment
См. Это, чтобы открыть файл: stackoverflow.com/questions/318789/ - person hmatt1; 18.02.2014
comment
Вы не можете делать только while ($line), вам нужно while ($line = <file1>). Кроме того, вы открываете INFILE, но читаете из file1. Ваш оператор die должен содержать ошибку $!, а open должен содержать три аргумента с лексическим дескриптором файла open my $fh, "<", $file or die "Cannot open: $!"; - person TLP; 18.02.2014

На первый взгляд кажется, что вы пытаетесь просмотреть файл соответствия и распечатать все строки, которые соответствуют region или vth на output.txt.

Для этого я упростил вам код:

use strict;
use warnings;

open(my $out_fh, ">", "output.txt") || die ("Cannot open file.\n");
open(my $file1, "<", "match.txt") || die ("Cannot open file.\n");

while( <$file1> ) {
    if ( /\s(region|vth)\s/i) {
        print $out_fh $_;
    }
}

В этом вопросе более подробно рассматривается проверка того, определена ли переменная или пуста: Как в Perl кратко проверить, определена ли переменная $ и содержит ли она строку ненулевой длины?

Дополнительная информация об открытии файлов: Как лучше всего открыть и прочитать файл в Perl?

person hmatt1    schedule 18.02.2014
comment
Этот сейчас работает ... спасибо ... но я хочу знать, в чем была ошибка в моем коде ... - person user3318901; 18.02.2014
comment
Привет, Мэтт, я также хочу знать, что означает $ _ в строке печати - person user3318901; 18.02.2014
comment
Привет! while(<$file1>) будет проходить через каждую строку в файле, а внутри цикла while $_ будет значением этой строки. Он в основном заменяет вашу переменную $line. Вы также можете использовать while(my $line = <$file1>), если хотите вместо этого использовать переменную $line. - person hmatt1; 18.02.2014
comment
Я предполагаю, что основная ошибка в вашем коде заключается в том, что вы хотите my $line = <$file1> внутри оператора while, и вам это нужно только один раз. Вы также не хотите помещать open в оператор if. Ошибка, которую вы получили, была связана с указанными вами строками, и вам все равно эти строки не нужны. - person hmatt1; 18.02.2014
comment
еще одна вещь: значения могут быть напечатаны только после сопоставления с образцом .... например ... после области .. только saturat saturat linear и после vth только xy z .... Я не хочу печатать нанизанную область /vth.... подскажите, как это сделать .... спасибо .. - person user3318901; 18.02.2014
comment
Есть много способов сделать это. Вы можете использовать строку s/(region|vth)//; и поместить ее в оператор if, прежде чем печатать, чтобы удалить эти слова. После их удаления вы можете удалить ведущий пробел с помощью s/^\s+//;. Вы также можете использовать split для преобразования строки в массив, а затем распечатать из него то, что вам нужно. Вот небольшой учебник: comp.leeds.ac.uk/Perl/split.html Вы можете разделить на пробелы. - person hmatt1; 18.02.2014