날짜를 기준으로 파일을 분할하고 합계와 금액이 포함된 예고편을 추가하세요.

날짜를 기준으로 파일을 분할하고 합계와 금액이 포함된 예고편을 추가하세요.

소스 파일:

  • 제목은 다음으로 시작합니다.H
  • 예고편은 다음과 같이 시작됩니다.T
  • R로 시작하는 레코드
  • 구분 기호는 다음과 같습니다.|~^

입력 파일 샘플

  • R로 시작하는 입력 레코드에는 원본 소스 파일에 여러 필드가 있습니다. 여기서는 예제에서 5개 필드만 언급했습니다.

  • 트레일러 레코드의 세 번째 열은 레코드 수이고 다섯 번째 열은 금액 열(레코드의 세 번째 열 또는 행)의 합계입니다.

  • 분할 후 예고편은 개수 및 합계 열을 포함하는 다음 형식으로 새 파일에 추가되어야 합니다.

  • R로 시작하는 INPUT 레코드는 날짜 순서를 따르지 않습니다. 예를 들어 첫 번째 레코드는 2019-03-05로 기록되고 마지막 레코드도 같은 날짜입니다.

노트:

  • R로 시작하는 INPUT 레코드에는 여러 열의 날짜 필드가 포함되므로 세 번째 날짜 필드를 분할하는 것이 좋습니다.

  • 또한 부탁드립니다날짜 필드의 타임스탬프 무시;날짜만 고려하고 날짜만을 기준으로 분할을 수행할 수 있습니다. 이상적으로는 세 번째 열에 있는 동일한 날짜의 모든 거래를 새 파일로 이동하고 합계와 개수가 추가된 헤더/트레일러로 이동해야 합니다. ****편집******** 내 질문은 여전히 ​​동일하지만 금액 필드가 매우 큰 숫자인 경우(금액 필드 데이터 유형이 소수점이 최대 5점, 매번 (31,5)는 아니지만 소수점 이하 5자리의 금액이 있는 경우 최대 소수점 5자리까지 값이 적용됩니다.)

입력 파일:

H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^8|~^xxx|~^123670130.37256

예상 출력

파일 1: 다음 이름으로 저장해야 합니다.20190305.txt

H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^4|~^xxx|~^107707.068

파일 2: 다음 이름으로 저장해야 합니다.20190306.txt

H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
T|~^20200425|~^4|~^xxx|~^123562423.30456

답변1

마지막 편집으로 전체 질문을 변경했습니다.

이제 각 행에 대해 타임스탬프를 파일 이름으로 변환해야 합니다. 에서 까지
입니다 . 이것만으로도 꽤 많은 문자열 처리가 필요하며 이는 어떤 언어에서도 그리 빠르지 않습니다.2019-03-06T12:33:52.2720190306

이 작은 부분은 awk에서 수행할 수 있습니다.

awk 'BEGIN{FS="\\|~\\^";OFS="|~^"}
     $1=="R"{
              t=gensub(/-/, "","g",$3)
              s=gensub(/T.*/,"",1,t);
              $3=s
            }
     1
' "file" >"file.adj"

그런 다음 타임스탬프 날짜(원래 문제)를 기준으로 파일이 여전히 분할됩니다. 필요한 최소 변경 목록은 다음과 같습니다.

  • 입력의 각 줄을 지정된 파일($3으로 제공)에 복사합니다.
  • 완료되면 (각 파일에 대해) 줄 수를 계산합니다.
  • 그리고 필드의 값을 합산합니다 4.
  • 모든 입력 행이 처리된 후 꼬리를 각 파일에 인쇄합니다.

전체 프로세스는 다음과 같이 awk에서 수행할 수 있습니다.

awk 'BEGIN  { FS="\\|~\\^"; OFS="|~^" }
     $1=="H"{ header=$0; hdr=$2 }
     $1=="R"{
              t=gensub(/-/, "","g",$3)
              file=gensub(/T.*/,"",1,t);
              sum[file]+=$4
              if(count[file]==0){ print header >file }
              count[file]++
              print $0 >>file
            }
     END    {
              for( i in sum ){
                  print "T",hdr,count[i],"xxx",sum[i] >> i;
                  close(i)
                  }
            }
' "file"

Perl을 사용하여 소스 파일을 100만 번 반복하면 전체 파일이 단 49.32초 만에 처리되었습니다. 최소 메모리 사용량(일일 합계 및 개수만 메모리에 유지하면 됨) 이것은 나에게 꽤 빠른 것 같습니다.

답변2

해결책 은 다음과 같습니다 awk.

awk -F'\\|~\\^' '{ 
            if($1=="H"){ 
                head=$0
            }
            else if($1=="T"){
                foot=$1"|~^"$2
                foot4=$4
            }
            else{
                date=$3;
                sub("T.*","", date);
                data[date][NR]=$0;
                sum[date]+=$4; 
                num[date]++
            }
           }
           END{
            for(date in data){
                file=date".txt";
                gsub("-","",file); 
                print head > file; 
                for(line in data[date]){
                    print data[date][line] > file
                } 
                printf "%s|~^%.3f|~^%s|~^%.3f\n", foot, num[date], 
                                              foot4, sum[date] > file
            }
           }' file 

샘플 데이터를 실행하면 다음이 생성됩니다.

$ cat 20190305.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^4.000|~^xxx|~^107707.068

$ cat 20190306.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
T|~^20200425|~^4.000|~^xxx|~^123562423.305

그리고 awk가 느리다고 생각하시는 것 같아서 대용량 파일로 테스트해봤습니다. 테스트 파일을 생성하기 위해 다음 명령을 실행했습니다.

perl -e '@d=<>; print $d[0]; $str=join("",@d[1..$#d-1]); print $str x 3500000; print $d[$#d]' file > bigFile

이렇게 하면 28000002줄을 포함하는 1.9G 파일이 생성됩니다. 여기서 첫 번째 줄은 원본 파일의 헤더이고, 마지막 줄은 원본 파일의 바닥글이며, 줄 사이에는 원본 파일 내용이 350만 번 반복됩니다. 그런 다음 이 파일에 대해 awk를 실행합니다(이 작업을 수행하려면 RAM이 충분하므로 최소 618M의 여유 RAM이 필요합니다).

$ time awk -F'\\|~\\^' '{ if($1=="H"){head=$0} else if($1=="T"){foot=$1"|~^"$2; foot4=$4;} else{date=$3; sub("T.*","", date);data[date][NR]=$0;sum[date]+=$4;num[date]++;} }END{for(date in data){file=date;gsub("-","",file); sub("T.*",".txt",file); print head > file; for(line in data[date]){print data[date][line] > file} printf "%s|~^%s|~^%s|~^%s\n", foot, num[date], foot4, sum[date] > file } }' bigFile 

real    2m8.603s
user    2m0.610s
sys     0m6.795s

따라서 1.9G 데이터 28,000,002행을 2분 안에 처리할 수 있습니다. 이것은 꽤 빠르다(비록이삭의 해결책1m 30에서는 더 빠르고 메모리를 적게 사용하므로 UI에서 사용을 권장합니다. for쉘 루프로는 결코 이렇게 빨리 얻을 수 없을 것이라고 장담할 수 있습니다 . 그 문제에 대해서는 R for 루프도 사용할 수 없습니다.

관련 정보