-2

しばらくの間、1つの問題を解決しようとしていましたが、成功しませんでした。最初は些細な問題のように見えますが、私はそれを積み重ねてきました...

とにかく、次の問題を解決する必要があります。次の形式の行を含む非常に大きな CSV ファイルがあります。

NUMBER(9);NUMBER(1);NUMBER(9-10);NUMBER(2);NUMBER(1);...;NUMBER(2);NUMBER(1);STRING;DATE(DD.MM.YYYY);NUMBER(1351)

例えば:

517755369;1;0001303717;48;1;63;8;50;2;51;6;53;7;55;3;57;4;59;5;;;;;CALL;07.12.2012;1351

最初のツリー フィールドの後の各行には、1 ~ 10 のペアNUMBER(2);NUMBER(1)があり、その後に別の 3 つのフィールドが続きますSTRING;DATE(DD.MM.YYYY);NUMBER(1351)

そのファイルを次の構造のファイルに変換する必要があります。

517755369;1;0001303717;48;1;CALL;07.12.2012;1351
517755369;1;0001303717;63;8;CALL;07.12.2012;1351
517755369;1;0001303717;50;2;CALL;07.12.2012;1351
517755369;1;0001303717;51;6;CALL;07.12.2012;1351
517755369;1;0001303717;53;7;CALL;07.12.2012;1351
517755369;1;0001303717;55;3;CALL;07.12.2012;1351
517755369;1;0001303717;57;4;CALL;07.12.2012;1351
517755369;1;0001303717;59;5;CALL;07.12.2012;1351`

したがって、入力ファイルの各行は、元の行のNUMBER(2);NUMBER(1)ペアと同じ数の行に変換する必要があります。

入力ファイルのサンプルを次に示します。

517760344;2;000601301061;31;1;;;;;;;;;;;;;;;;;;;CALL;07.12.2012;1351
518855369;1;000601303717;48;1;63;8;50;2;51;6;53;7;55;3;57;4;59;5;;;;;CALL;07.12.2012;1351
519775067;1;000601300771;4;2;6;3;19;1;;;;;;;;;;;;;;;CALL;07.12.2012;1351
617773407;1;000603252922;13;1;17;2;27;3;;;;;;;;;;;;;;;CALL;07.12.2012;1351
717764779;1;000601304021;31;1;;;;;;;;;;;;;;;;;;;CALL;07.12.2012;1351`

一般に、 sedまたはawk (または入力ファイルに対して実行できるperlスクリプト)で使用できる正規表現が必要です。元の入力ファイルには、およそ 1 ~ 150 万のレコードがあります。このタスクはできるだけ早く終了する必要があります (変換には最大 5 分かかります)。

ありがとう

4

4 に答える 4

2

@Kenosis からのアイデアですが、仕様の解釈は異なります。

use strict;
use warnings;

while (<DATA>) {
    chomp;
    my @fields = split /;/;
    my $f = 3;
    while ($fields[$f]) {
      print join( ';', @fields[0 .. 2, $f, $f + 1, -3 .. -1]), "\n";
      $f += 2;
    }
}

__DATA__
517760344;2;000601301061;31;1;;;;;;;;;;;;;;;;;;;CALL;07.12.2012;1351
518855369;1;000601303717;48;1;63;8;50;2;51;6;53;7;55;3;57;4;59;5;;;;;CALL;07.12.2012;1351
519775067;1;000601300771;4;2;6;3;19;1;;;;;;;;;;;;;;;CALL;07.12.2012;1351
617773407;1;000603252922;13;1;17;2;27;3;;;;;;;;;;;;;;;CALL;07.12.2012;1351
717764779;1;000601304021;31;1;;;;;;;;;;;;;;;;;;;CALL;07.12.2012;1351

出力:

perl 14528210.pl
517760344;2;000601301061;31;1;CALL;07.12.2012;1351
518855369;1;000601303717;48;1;CALL;07.12.2012;1351
518855369;1;000601303717;63;8;CALL;07.12.2012;1351
518855369;1;000601303717;50;2;CALL;07.12.2012;1351
518855369;1;000601303717;51;6;CALL;07.12.2012;1351
518855369;1;000601303717;53;7;CALL;07.12.2012;1351
518855369;1;000601303717;55;3;CALL;07.12.2012;1351
518855369;1;000601303717;57;4;CALL;07.12.2012;1351
518855369;1;000601303717;59;5;CALL;07.12.2012;1351
519775067;1;000601300771;4;2;CALL;07.12.2012;1351
519775067;1;000601300771;6;3;CALL;07.12.2012;1351
519775067;1;000601300771;19;1;CALL;07.12.2012;1351
617773407;1;000603252922;13;1;CALL;07.12.2012;1351
617773407;1;000603252922;17;2;CALL;07.12.2012;1351
617773407;1;000603252922;27;3;CALL;07.12.2012;1351
717764779;1;000601304021;31;1;CALL;07.12.2012;1351
于 2013-01-25T19:37:51.547 に答える
2

おそらく、以下が役立つでしょう:

use strict;
use warnings;

while (<>) {
    chomp;
    print +( join ';', ( split /;/ )[ 0 .. 4, -3 .. -1 ] ) . "\n";

}

データの出力:

517760344;2;000601301061;31;1;CALL;07.12.2012;1351
518855369;1;000601303717;48;1;CALL;07.12.2012;1351
519775067;1;000601300771;4;2;CALL;07.12.2012;1351
617773407;1;000603252922;13;1;CALL;07.12.2012;1351
717764779;1;000601304021;31;1;CALL;07.12.2012;1351

使用法: perl file.csv >out.csv.

最初の 5 つのフィールドと最後の 3 つのフィールドが必要なようです。上記splitの s on ;、 re joins を使用し;て、変更されたレコードを出力します。

于 2013-01-25T19:08:45.367 に答える
1

これはうまくいくかもしれません(GNU sed):

sed -r 's/^(([^;]*;){3})(([0-9]+;){2})(([0-9]*;)*)(([^;]*;?){3})$/\1\3\7\n\1\5\7/;Ta;P;:a;D' file
  • s/^(([^;]*;){3})(([0-9]+;){2})(([0-9]*;)*)(([^;]*;?){3})$/\1\3\7\n\1\5\7/この置換コマンドは 2 つの文字列を作成します。1 つ目は目的の文字列の後に改行が続き、2 つ目は元の文字列から最初の数字のペアを除いたものです。So^(([^;]*;){3})は、最初の 3 つのフィールド、(([0-9]+;){2})最初の数値のペア(([0-9]*;)*)、残りの数値のペア、および(([^;]*;?){3})$最後の 3 つのフィールドを表します。
  • Ta置換コマンドが失敗した場合、ラベルにジャンプa
  • Pパターンスペースの最初の改行まで印刷します。
  • :aラベルa
  • D最初の改行まで削除し、次のサイクルを開始します。パターン スペースが空になるまで別の行を読み込まないでください。

したがって、本質的に、コマンドs/.../.../Dコマンドはループを呼び出すために使用され、置換コマンドが失敗してループが終了するまで、構築された文字列を出力します。残りの文字列は完全に削除され、次の行が開始されます。

于 2013-01-25T21:43:14.557 に答える
1

Text::CSVモジュールを使用したワンライナー形式のソリューションを次に示します。

perl -MText::CSV -lwe '$c = Text::CSV->new({
    sep_char=>';',
    eol=>$/
});                  
while($r = $c->getline(*STDIN)) { 
    my @a = splice @$r,0,3;            # remove 3 first elements
    my @c = splice @$r,-3;             # remove 3 last elements
    @$r = grep $_ ne '', @$r;          # remove empty elements
    while(@$r) {                       # while array is not empty
        $c->print(*STDOUT, [@a, splice(@$r,0,2),@c]);    # print all elements
    } }"

出力:

517755369;1;0001303717;48;1;CALL;07.12.2012;1351
517755369;1;0001303717;63;8;CALL;07.12.2012;1351
517755369;1;0001303717;50;2;CALL;07.12.2012;1351
517755369;1;0001303717;51;6;CALL;07.12.2012;1351
517755369;1;0001303717;53;7;CALL;07.12.2012;1351
517755369;1;0001303717;55;3;CALL;07.12.2012;1351
517755369;1;0001303717;57;4;CALL;07.12.2012;1351
517755369;1;0001303717;59;5;CALL;07.12.2012;1351

したがって、基本的には、コメントで述べたように、最初の 3 つの要素と最後の 3 つの要素を削除して、別々の配列に格納します。空の要素を削除します。残りの要素をループし、必要に応じて印刷します。

于 2013-01-25T22:52:19.703 に答える