2011-01-20 2 views
1

Perl 전문가 - 내 문제를 해결하기위한 시도가 많은 코드로 바뀌고 있습니다. PERL에서이 문제가 올바르게 처리되고있는 것처럼 보입니다. 여기 내 문제는 다음과 같습니다.Perl 텍스트 구문 분석 - 고정 된 구분 구조가 변경됨

나는 열 데이터 사이에 공백을 가변적으로 가질 수있는 텍스트 블록을 가지고 있습니다 (아래 예 참조). 간단한 분할을 사용했지만 문제는 이제 "코드"열에 데이터의 공백이 포함되어 있다는 것입니다 (마지막 열의 데이터 만 차지함). 상수가되는 것 (비록 내가 소스 구조에 접근 할 수 없거나 소스 구조를 제어 할 수 없지만)은 컬럼 사이에 최소 3 칸 (어쩌면 더 많을 수도 있지만 결코 적지 않을 수 있음)이라는 것입니다.

그래서 열 구분 기호 토큰이 "3 공백"이라고 가정하고 각각의 데이터를 내 실제 기둥 형 데이터로 잘라 내고 싶습니다.

COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 

저는 6 개의 변수로 값을 가져 오려고합니다.

참고 : COL0에는 값이 없을 수 있습니다. COL4는 데이터 공간을 포함 할 수 있습니다. COL5에는 값이 없거나 공백이있는 데이터가 포함될 수 있습니다. 고정 된 서식은 공백 (탭이나 다른 특수 문자 없음)으로 완료됩니다. 명확하게하기 위해 - 열의 크기가 일정하지 않습니다. 한 파일은 COL4를 13 자로하고, 다른 파일은 COL4를 21 자 너비로 가질 수 있습니다. 그렇지 않으면 다른 SO 회원이 진술 한 것처럼 엄격하지 않습니다.

+0

컬럼은 각 행 사이에 다른 오프셋에서 시작할 수? E..g. row1은'| 1 2 3 |'(3 칸)이고 row2는'| 11111 2 3''(또한 3 칸이지만 두 번째 열은 행 2의 첫 번째 값이 너무 넓기 때문에 첫 번째 행보다 큰 오프셋 4로 시작 함) – DVK

+0

아니요, 열 사이징은 각 행당 파일. 파일을 구별 할 수 있지만 파일 내에서 일관성이 있습니다. – Walinmichi

+0

열 머리글이 실제로 있습니까? – Svante

답변

2

이 같은 엄격한 원주 데이터를 처리하는 경우는, unpack 당신이 원하는 아마도 :

#!perl 

use strict; 
use warnings; 
use 5.010; 

use Data::Dumper; 

my $data = <<EOD; 
COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 
EOD 

my @lines = split '\n', $data; 
for my $line (@lines) { 
    my @values = unpack("a5 A7 A7 A7 A13 A*", $line); 
    print Dumper \@values; 
} 

이 원하는대로 @values 배열로 값을 덤프 나타납니다,하지만 그들은해야합니다 당신이 정리해야 할 선도적 인 공간.

+0

** 엄격한 ** 기둥 데이터가 아닌 것처럼 들리지만 약간의 비트가없는 코드 – DVK

+0

이 방법을 이용해 주셔서 감사합니다. 그러나 또 다른 문제는 열 크기가 다를 수 있다는 것입니다. 그래서 3 문자 토큰에 초점을 맞추려고했습니다. COL4는 항상 13 자 (COL4가 13 ~ 21 자의 데이터 파일이어야 함)가 아니기 때문입니다. – Walinmichi

0

나는 CanSpice가 이미 대답했다는 것을 알고 있지만 (아마도 더 나은 해결책 일 수있다.) "$ /"를 사용하여 입력 구분 기호를 설정할 수있다. 전역 변수이거나 부작용이 나타날 수 있으므로 로컬 범위 (아마도 하위)에서이 작업을 수행해야합니다. 예 :

local $/ = " "; 
$input = <DATAIN>; # assuming DATAIN is the file-handler 

멋진 작은 정규 표현식을 사용하여 공백을 제거 할 수 있습니다. 예를 들어 Wikipedia을 참조하십시오.

1

두 개의 패스를 사용합니다. 첫 번째는 각 행에 공백이있는 문자 열을 찾습니다. 그런 다음 해당 색인으로 분할하거나 압축을 풉니 다. 화이트 스페이스 트리밍은 이후에 수행됩니다.

귀하의 예 : 열은 모든 공간입니다 마지막 줄 쇼

COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 

000011100001110000111000011100000000001110000000000 

1의.

+0

그래서 열 제목을 사용하여 TEMPLATE를 정의한 다음 해당 값을 UNPACK에 전달 하시겠습니까? 나는 지금 그것을 시도 할 것이다. – Walinmichi

+0

@Walinmichi : 아니요, _all_ 줄을 사용하여 템플릿을 정의하십시오. – Svante

+0

이해가 안됩니다. 전체 파일에는 이러한 유형의 블록보다 많은 구조가 포함되어 있습니다. 나는 올바른 블록으로 나를 데려가는 코드를 가지고있다. 각 블록 아래에 "***** END *******"상수가 있기 때문에 블록의 끝을 알 수도 있습니다. – Walinmichi

3

열의 위치를 ​​알아 내야합니다. 정말 아주 역겨운 해킹, 당신은 전체의 파일 다음 문자열 또는 함께 라인을 읽을 수 있습니다

my @file = <file>; 
chomp @file; 

my $t = ""; 
$t |= $_ foreach(@file); 

$의 t는 항상 열에서 공백 문자가 있었다 열만에 공백 문자가 포함됩니다; 다른 열은 2 진 정크를 포함합니다.

이제
@cols = map length, @cols; 
my $format = join '', map "A$_", @cols; 

과정 :

my @cols = split /(?=[^ ]+)/, $t; 

우리는 실제로 폭이 열은 압축을 풀고() 형식을 생성하려면 : 지금이 아닌 공간을 일치 제로 폭 일치로 분할 파일! :

foreach my $line (@file) { 
    my($field, $field2, ...) = unpack $format, $line; 
    your code here... 
} 

(이 코드는 가볍게 테스트되었습니다.)

+0

내 텍스트 블록은 실제로 많은 블록이있는 큰 파일의 하위 집합입니다 (모두 다른 열 구조를 가짐). 내 블록의 시작과 끝을 알지만, 어떻게 한 줄로 들어갈 지 확신하지 못합니다. 줄을 연결할 수있을 것 같습니까? – Walinmichi

+0

나는 나를 위해이 일을 얻을 수 없습니다. PERL에 대한 제한된 지식으로 나는 어디에서 곤경에 처했는지 알 수 없었습니다. 나는 간단한 헤더를 사용하여 Svante와 vmpstr의 도움을 얻었으므로 헤더 제목이 알려진 상수라는 것을 깨달았다. 이를 사용하여 모든 열의 오른쪽 가장자리를 찾은 다음 그 사이의 공간을 substr로 찾을 수있었습니다. 일부 트림으로 동적 열 너비로 원하는 것을 얻을 수있었습니다. 이런 유형의 솔루션이 더 좋다고 확신하지만, PERL과 마찬가지로 짧은 시간에이 문제를 해결할 수 있도록 할당 할 수있었습니다. 모두에게 감사드립니다! – Walinmichi

관련 문제