텍스트 파일의 숫자 필드 크기를 조정하는 방법

텍스트 파일의 숫자 필드 크기를 조정하는 방법

<Tab>다음과 같이 구분된 텍스트 파일이 있다고 가정해 보겠습니다 .

file name    size      owner    
file1.txt    12.345    root
file2.txt    0.172222  user1
file3.txt    2.46e2    user2
file4.txt    12345     root
file5.txt    21        user3
file6.txt    246.0     user1
file name    owner     last modified    last accessed
text4.txt    root      12.73            13.53
text5.txt    user3     15.3333          34
file1.txt    root      23               31.0032

파일은 여러 개의 "테이블"로 구성되며, 각 테이블은 헤더 행으로 시작하고 일부 데이터 행을 포함합니다. 일부 열은 숫자이지만 각 테이블은 서로 다른 숫자와 다양한 유형의 열을 가질 수 있습니다. 컬럼의 유형은 미리 알 수 없으며 테이블 헤더를 기반으로 판별할 수 없습니다.

표의 값은 다양한 형식으로 되어 있습니다. 정수, 부동 소수점 소수 또는 과학 표기법의 숫자일 수 있습니다.

내 질문은 이 테이블의 모든 숫자 필드를 동일한 형식으로 변환하는 방법입니다. 예를 들어 "%.2f"printf 형식 지정자를 사용하여 각 숫자 필드의 형식을 지정할 수 있습니다 . 물론, 숫자가 아닌 다른 필드는 변경되지 않은 상태로 유지되어야 합니다.

또한 이 파일에 포함된 모든 숫자 필드를 임의로 조정할 수 있기를 원합니다(예: 42를 더한 다음 7을 곱함).

내가 찾고 있는 솔루션은 현장 기반이어야 합니다. 전체 파일을 스캔해야 하며 각 필드에 대해 숫자인지 확인해야 합니다. 숫자인 경우 조정되고 형식화된 값을 인쇄해야 합니다. 그렇지 않으면 원본만 인쇄해야 합니다.

비슷한 일을 수행하는 데 사용될 수 있다는 것을 알고 있습니다 awk. 하지만 내 기억이 정확하다면 숫자의 내부 표현 awk에 사용되므로 double정밀도와 더 큰 값에 문제가 있을 수 있습니다. 따라서 이상적으로는 최소한 64비트 정수를 올바르게 처리할 수 있는 다른 것을 사용하고 싶습니다.

이것을 달성하는 쉬운 방법이 있습니까?

답변1

Scalar::Utillooks_like_number()perl 에는 필드가 숫자인지 감지하는 데 사용할 수 있는 유용한 함수가 있는 모듈(v5.8부터 perl에 포함됨)이 있습니다.

looks_like_number완벽하지는 않지만 꽤 좋습니다.

원하는 작업을 수행하는 간단한 Perl 프로그램의 간단한 개요는 다음과 같습니다.

#! /usr/bin/perl

use Scalar::Util qw(looks_like_number);

while(<>) {
  chomp;
  my @fields=split("\t");
  foreach my $f (0..scalar @fields-1) {
    if (looks_like_number($fields[$f])) {
      $fields[$f] += 42;
      $fields[$f] *= 7;
      $fields[$f] = sprintf("%.2f",$fields[$f]);
    }
  }
  print join("\t",@fields),"\n";
}

위의 예제 데이터를 입력으로 사용하면 다음이 인쇄됩니다.

file name   size    owner    
file1.txt   380.41  root
file2.txt   295.21  user1
file3.txt   2016.00 user2
file4.txt   86709.00    root
file5.txt   441.00  user3
file6.txt   2016.00 user1
file name   owner   last modified   last accessed
text4.txt   root    383.11  388.71
text5.txt   user3   401.33  532.00
file1.txt   root    455.00  511.02

다음은 모든 계산에 Math::BigFloat를 사용하여 소수점 이하 자릿수를 2자리로 반올림하는 또 다른 버전의 스크립트입니다.

#! /usr/bin/perl

use Scalar::Util qw(looks_like_number);
use Math::BigFloat;

while(<>) {
  chomp;
  my @fields=split("\t");
  foreach my $f (0..scalar @fields-1) {
    if (looks_like_number($fields[$f])) {
      my $BF = Math::BigFloat->new($fields[$f]);
      $BF->badd(42);
      $BF->bmul(7);
      $BF->ffround(-2);

      $fields[$f] = $BF->bstr();
    }
  }
  print join("\t",@fields),"\n";
}

입력 예:

file name   owner   last modified   last accessed
text4.txt   root    12.73   13.53
text5.txt   user3   15.3333 34
file6.txt   root    903709792518875002.42857142857142857142 903709792518875002
file7.txt   root    6659166111488656281486807152009765625   539422123247359763587428687890625

산출:

file name   owner   last modified   last accessed
text4.txt   root    383.11  388.71
text5.txt   user3   401.33  532.00
file6.txt   root    6325968547632125311.00  6325968547632125308.00
file7.txt   root    46614162780420593970407650064068359669.00   3775954862731518345112000815234669.00

관련 정보