2010-02-03 5 views
0

큰 데이터 파일을 반복하면서 각 열의 변수 유형을 감지하는 경우 예를 들어 인튜어너 또는 플로트 등일 경우 완벽하게 작동하지만 , 지금은 여전히 ​​아주 기본적인 것이고 또 다른 아이디어를 추가하고 싶습니다. 변수의 선언은 데이터 세트의 두 번째 행을 기반으로합니다. 는 (. 첫번째는 헤더로서 사용된다) 여기서 코드의 시작 :데이터 집합을 반복하고 누락 된 값을 처리합니다.

#!/usr/bin/perl 

use warnings; 
use diagnostics; 
use Getopt::Std; 

getopts("i:s:t:") or die "bad options: $!"; 

if($opt_i) { 
open INFILE, "< $opt_i"; 
chomp($headerline = <INFILE>); 
$second = <INFILE>; 
} else { 
die "the input file has to be given\n"; 
} 

if($opt_t) { 
$tablename = $opt_t; 
} else { 
$tablename = $opt_i; 
$tablename =~ s/\.\w+//; 
} 

if($opt_s) { 
$sep = $opt_s; 
} else { 
$sep = ","; 
} 

$headerline =~ s/\"//g; 
$headerline =~ s/\./\_/g; 
@header = split/$sep/, $headerline; 

$second =~ s/\"//g ; 
@second = split/$sep/, $second; 
@terms = split/$sep/, $second; 
@types = split/$sep/, $second; 

지금은 작은 루프를 구현 하였다. 문제는 NULL로 선언 된 누락 된 값을 처리하는 방법을 모르겠다는 것입니다. 현재 루프는 변수 "$vartype[$j]"에 단순히 ""즉 아무 것도 지정하지 않습니다. 나는 하나 개의 컬럼에 NULL 값을 가질 때마다 그 숫자 또는를 찾을 때까지 루프가 같은 열에서 다음 값을 읽고 그렇게되도록 내가 기존 루프에 다른 루프 구조를 구현할 수있는 방법을 그래서

$j = 0; 
while($j <= $#second) { 
if ($types[$j] =~ /NULL/) { 
$vartype[$j] = ""; 
} elsif($types[$j] =~ /[A-Za-z]/) { 
$vartype[$j] = "varchar"; 
} elsif ($types[$j] =~ /\./) { 
$vartype[$j] = "double"; 
} else { 
$vartype[$j] = "int"; 
} 
$j++; 
} 

워드.

내 데이터의 샘플은 예를 들면 다음과 같습니다

Country.Name  Time.Name AG.LND.AGRI.ZS NY.GDP.MKTP.CD NE.IMP.GNFS.ZS 
Brunei Darussalam 1960  NULL    1139121335.16 3.46 
Brunei Darussalam 1960  NULL    1677595756.64 0.9 
Brunei Darussalam 1960  NULL    1488339328.59 4.19 
Brunei Darussalam 1961  3.98    1869828587.8  3.14 
Brunei Darussalam 1961  3.98    2346769422.22 3.38 
Brunei Darussalam 1961  3.98    2363109706.3  3.17 

은 이미 루프에 대한 언급만을 변수의 유형을 결정하는 두 번째 행을 사용합니다.

이제 예를 들어 세 번째 열 (AG.LND.AGRI.ZS)에서 그는 첫 번째 실제 값 (이 경우 3.98)을 감지 할 때까지 열을 통과하도록 다른 루프를 구현하고 싶습니다. 현재 루프는 NULL로 표시된 누락 된 값을 인식하고 빈 값을 할당합니다. C.

for my $variable (@types) { 
    if ($variable =~ /NULL/) { 
    push(@vartype, undef); 
    } 
    elsif ($variable =~ /[A-Za-z]/) { 
    push(@vartype, "varchar"); 
    } 
    elsif ($variable =~ /\./) { 
    push(@vartype, "double"; 
    } 
    else { 
    push(@vartype, "int"); 
    } 
} 

같은

답변

1

나는 당신이 무엇을하려하는지 알아내는 데 어려움을 겪고 있습니다. 열의 내용을 기반으로 열 유형을 추측하려고한다고 가정 할 때 여기에이를 수행하는 방법이 있습니다. 중요한 것은 필드가 NULL 인 경우 아무 것도 설정하지 말고 유형을 이미 결정한 경우 필드를 건너 뛰고 모든 필드 유형이 결정되면 루프에서 빠져 나가는 것입니다.

#!/usr/bin/perl 

use strict; use warnings; 
use Scalar::Util qw(looks_like_number); 

my @names = split ' ', scalar <DATA>; 
my @types; 

while (<DATA>) { 
    chomp; 
    my @values = split/{2,}/; 

    for my $i (0 .. $#values) { 
     next if defined $types[$i]; 
     my $val = $values[$i]; 
     next if $val eq 'NULL'; 
     if ($val =~ /^[0-9]+\z/) { 
      $types[$i] = 'int'; 
     } 
     elsif ($val =~ /^[0-9.]+\z/ 
       and looks_like_number($val)) { 
      $types[$i] = 'double'; 
     } 
     else { 
      $types[$i] = 'varchar'; 
     } 
    } 
    last unless grep { not defined } @types; 
} 

print "$_\n" for @types; 


__DATA__ 
Country.Name  Time.Name AG.LND.AGRI.ZS NY.GDP.MKTP.CD NE.IMP.GNFS.ZS 
Brunei Darussalam 1960  NULL    1139121335.16 3.46 
Brunei Darussalam 1960  NULL    1677595756.64 0.9 
Brunei Darussalam 1960  NULL    1488339328.59 4.19 
Brunei Darussalam 1961  3.98    1869828587.8  3.14 
Brunei Darussalam 1961  3.98    2346769422.22 3.38 
Brunei Darussalam 1961  3.98    2363109706.3  3.17 

출력 :

varchar 
int 
double 
double 
double
+0

예, 그게 내가하려는 일입니다. 나는 데이터베이스에로드하고자하는 몇 가지 데이터 세트가 있고 각 열 유형을 자동으로 감지하는 perl 스크립트를 작성하는 것을 좋아합니다. 그 이유는 내가 각 데이터 세트를 열고 열을 직접 탐색 할 필요가 없다는 것입니다. 도움을 주셔서 감사합니다. 답변을 살펴 봅니다. – mropa

+0

@Sinan : Oesor는 Text :: CSV 모듈을 사용할 것을 제안했습니다. 이는 코드의 양과 권장 접근 방식을 줄이는 것입니까? – mropa

+0

@mropa'Text :: CSV'를 사용하든 그것이 명시된대로 문제에 어느 정도 직각을 이룹니다. 데이터 필드가 탭으로 구분 된 경우 (분명히 여러 공백과 반대) 필드에 따옴표로 묶인 문자열이 포함될 수 있으므로이를 사용하면 더 쉽게 사용할 수 있습니다. 그래도 코드의 양은 줄어들지 않습니다. 내 코드의 핵심은 필드 내용에서 필드 형식을 추론하는 논리를 보여주는 것입니다. –

2

정지 프로그래밍,하지만 펄을 위해, 당신은 정말 해시의 자료 구조에 관련 데이터를 저장해야합니다. 다음과 같이하십시오 :

my $data = [ { value => 'NULL', type => undef }, 
      { value => 'a string', type => 'varchar' }, 
      { value => 9.5, type => 'double'}, 
      { value => 30, type => 'int'}, 
      ]; 
+0

주전자, ;-) 냄비를 만난다. 'elsif' 또는'given/when'을 사용하십시오. http://perldoc.perl.org/perlsyn.html#Switch-statements –

+0

사실 나는 그것이 제가 찾고있는 것이 아니라고 생각합니다. 코드는 여전히 변수를 감지하고 분류를 지정하기 위해 데이터 세트의 두 번째 행만 사용합니다. 그렇다면 데이터 세트의 다른 행을 추가로 읽지 않아야합니까? – mropa

+0

제 방어도로 디스패치 테이블을 내 데이터 세트에 매핑하는 것이 훨씬 쉬우므로 거의 if-elsif-else 루프를 프로그래밍합니다. 그리고 제 플랫폼 중 하나가 5.8.8이므로 스위치를 피하십시오. :/ – Oesor

관련 문제