2010-01-20 4 views
4

두 개의 명령 행 인수를받는이 Perl 스크립트를 작성했습니다 : 디렉토리와 연도. 이 디렉토리에는 텍스트 파일 또는 html 파일 톤이 있습니다 (연도에 따라 다름). 예를 들어,이 파일은 <number>rank.html과 2001 년에서 2212 년 사이의 파일을 포함하고 있습니다. 각 파일을 개별적으로 열고 html 파일의 제목에 참여하여 텍스트로 인쇄하고 싶습니다. 파일. 그러나 코드를 실행하면 첫 번째 파일 제목이 텍스트 파일에 인쇄됩니다. 그것은 첫 번째 파일 2001rank.html 만 열어 본 것 같습니다. 아래 코드를 게시하고 도움을 준 사람에게 감사드립니다. 나는 HTML 파일이 다른 알면서도, 모든 루프 전달 같은 일을 동일하게 설정됩니다 $column_namePerl 스크립트가 닫힌 후에도 같은 파일에서 계속 읽는 이유는 무엇입니까?

my $directory = shift or "Must supply directory\n"; 
my $year = shift or "Must supply year\n"; 

unless (-d $directory) { 
    die "Error: Directory must be a directory\n"; 
} 

unless ($directory =~ m/\/$/) { 
    $directory = "$directory/"; 
} 

open COLUMNS, "> columns$year.txt" or die "Can't open columns file"; 
my $column_name; 

for (my $i = 2001; $i <= 2212; $i++) { 

    if ($year >= 2009) { 
    my $html_file = $directory.$i."rank.html"; 
    open FILE, $html_file; 

    #check if opened correctly, if not, skip it 
    unless (defined fileno(FILE)) { 
     print "skipping $html_file\n"; 
     next; 
    } 

    $/ = "\n"; 
    my $line = <FILE>; 

    if (defined $line) { 
     $column_name = ""; 
     $_ = <FILE> until m{</title>}; 
     $_ =~ m{<title>CIA - The World Factbook -- Country Comparison :: (.+)</title>}i; 
     $column_name = $1; 
    } 
    else { 
     close FILE; 
     next; 
    } 
    close FILE; 
    } 
    else { 
    my $text_file = $directory.$i."rank.txt"; 
    open FILE, $text_file; 

    unless (defined fileno(FILE)) { 
     print "skipping $text_file\n"; 
     next; 
    } 

    $/ = "\r"; 
    my $line = <FILE>; 

    if (defined $line) { 
     $column_name = ""; 
     $_ = <FILE> until /Rank/i; 
     $_ =~ /Rank(\s+)Country(\s+)(.+)(\s+)Date/i; 
     $column_name = $3; 
    } 
    else { 
     close FILE; 
     next; 
    } 
    close FILE; 
    } 

    print "Adding $column_name to text file\n"; 
    print COLUMNS "$column_name\n"; 
} 

close COLUMNS; 

.

+2

어휘 파일 핸들을 사용하십시오. 왜'fileno'를 사용하여'open'의 성공을 확인하고 있습니까? –

+0

어떻게 성공을 확인해야합니까? – adhanlon

+2

오픈 콜 결과로 성공을 확인하십시오. 그러나 먼저 doc을 읽어야합니다. http://perldoc.perl.org/functions/open.html 항상! :) – sebthebert

답변

5

당신은 아마 당신이 당신의 파일 핸들 대신 전역에 대한 지역 lexicals를 사용하여 변환하면 엄격한 검사에 차례로뿐만 아니라, 훨씬 빨리이 문제를 디버깅 할 수 있습니다 :

use strict; 
use warnings; 

while (...) 
{ 
    # ... 
    open my $filehandle, $html_file; 

    # ... 
    my $line = <$filehandle>; 
} 

이 방법, 파일 핸들 (s)는 각 루프 반복 동안 범위를 벗어날 것이므로 정확하게 참조 된 내용과 위치를 더 명확하게 볼 수 있습니다. (힌트 :. 당신이 핸들이 종료됩니다 조건을 놓칠 수 있으므로이 잘못 주변의 다음 번 재사용)

open 및 파일 핸들과 함께 모범 사례에 대한 자세한 내용은 다음을 참조하십시오

몇 가지 다른 점 :

    ,
  • $_에 명시 적으로 할당하지 마십시오. 문제가 발생합니다. 데이터를 유지하기 위해 자신의 변수를 선언 : my $line = <$filehandle>
  • 오히려 등 $1, $2을 사용하는 대신 변수에 직접 경기를 당겨, 오직 당신이 실제로 필요로하는 부분에 대해 괄호를 사용 (위의 예에서와 같이) : my ($column_name) = ($line =~ m/Rank\s+Country\s+.+(\s+)Date/i);
  • 먼저 오류 조건을 넣으십시오. 따라서 코드의 대부분이 하나 이상의 (또는 그 이상의) 수준을 능가 할 수 있습니다. 이렇게하면 가독성이 향상됩니다. 알고리즘의 대부분이 화면에 동시에 표시 될 때 더 정확하게 시각화하고 오류를 잡을 수 있습니다.

위의 사항을 적용한 경우 오류가 있음을 확인할 수 있습니다. 나는이 마지막 편집을하는 동안 그것을 발견했지만, 스스로 발견한다면 더 많이 배울 것이라고 생각합니다. (나는 snooty가 되려고하지 않고있다, 이것에 나를 신뢰해라!)

+0

제안을 주셔서 감사합니다, 나는 그것을 시도했지만 여전히 올바르게 작동하지 않습니다. 파일 핸들이 사용하는 파일을 볼 수있는 방법이 있습니까? – adhanlon

+0

@ Silmaril89 : 마지막 편집을 참조하십시오. – Ether

+0

$ line에 라인이 있다면 $ column_name에 직접 일치하는 것을 어떻게 얻을 수 있습니까? – adhanlon

0

당신은 grep를 고려 했느냐?

grepgrep 제목이 포함 된 HTML의 줄만 출력 한 다음 grep의 출력을 처리합니다.

파일 처리 코드를 작성할 필요가 없으므로 간단합니다. 그 제목으로 원하는 것을 말하지 않았습니다. 목록 만 있으면 코드를 작성하지 않아도됩니다.귀하의 처리가 HTML 및 텍스트 파일 비슷

grep -ri title <directoryname> 
2

, 그래서 당신의 인생을 쉽게 공통 부분을 밖으로 요인 :

같은 것을 시도하십시오

sub scrape { 
    my($path,$pattern,$sep) = @_; 

    unless (open FILE, $path) { 
    warn "$0: skipping $path: $!\n"; 
    return; 
    } 

    local $/ = $sep; 

    my $column_name; 
    while (<FILE>) { 
    next unless /$pattern/; 
    $column_name = $1; 
    last; 
    } 

    close FILE; 

    ($path,$column_name); 
} 

을위한이 특정하게 두 가지 유형의 입력 :

sub scrape_html { 
    my($directory,$i) = @_; 

    scrape $directory.$i."rank.html", 
     qr{<title>CIA - The World Factbook -- Country Comparison :: (.+)</title>}i, 
     "\n"; 
} 

sub scrape_txt { 
    my($directory,$i) = @_; 

    scrape $directory.$i."rank.txt", 
     qr/Rank\s+Country\s+(.+)\s+Date/i, 
     "\r"; 
} 

다음 주 프로그램은 간단합니다.

my $directory = shift or die "$0: must supply directory\n"; 
my $year  = shift or die "$0: must supply year\n"; 

die "$0: $directory is not a directory\n" 
    unless -d $directory; 

# add trailing slash if necessary 
$directory =~ s{([^/])$}{$1/}; 

my $columns_file = "columns$year.txt"; 
open COLUMNS, ">", $columns_file 
    or die "$0: open $columns_file: $!"; 

for (my $i = 2001; $i <= 2212; $i++) { 
    my $process = $year >= 2009 ? \&scrape_html : \&scrape_txt; 

    my($path,$column_name) = $process->($directory,$i); 

    next unless defined $path; 

    if (defined $column_name) { 
    print "$0: Adding $column_name to text file\n"; 
    print COLUMNS "$column_name\n"; 
    } 
    else { 
    warn "$0: no column name in $path\n"; 
    } 
} 

close COLUMNS or warn "$0: close $columns_file: $!\n"; 

글로벌 파일 핸들을 닫을 때 얼마나주의해야하는지주의하십시오. 매개 변수로 $fh 전달 또는 해시에 때우는

open my $fh, $path or die "$0: open $path: $!"; 

같이 어휘 파일 핸들을 사용하십시오 훨씬 좋네요. 또한 어휘 파일 핸들은 범위를 벗어날 때 자동으로 닫힙니다. 다른 누군가가 이미 사용하고있는 핸들을 밟을 기회가 없습니다.

관련 문제