2

処理のためにプレーンテキストに変換した表形式データのPDFファイルを受け取りました。

pdftotext -nopgbrk -layout file.pdf

これはかなりまともな仕事をしますが、列のフィールドを区切る/区切るためにスペースを使用し、「構造的な」レイアウトではなく視覚的なレイアウトを維持することに主に関心があるようです。つまり、一貫したまたは信頼できる区切り文字はありません。そこで、2つ以上のスペースをタブに変換します。

sed -i 's/[[:space:]]\{2,\}/\t/g' file.txt

を使用するcat -vteと、これはファイルにタブを配置するのに非常に効果的であることがわかります....ただし、2番目のフィールドにはいくつかの矛盾があります。

明確にするために、次の比較を参照してください。

正常/期待される結果:

79879 5.6 0.5 MG EN SQ TFK World Report 09-24-2004 Time for Kids Editors、ORD1915643
79880 5.5 0.5 MG EN SQ TFK World Report 10-01-2004 Time for Kids Editors、ORD1915643
79881 6.0 0.5 MG EN SQ TFK World Report 10-08-2004 Time for Kids Editors、ORD1915643
79882 5.5 0.5 MG EN SQ TFK World Report 10-22-2004 Time for Kids Editors、ORD1915643
79883 5.9 0.5 MG EN SQ TFK World Report 10-29-2004 Time for Kids Editors、ORD1915643

いくつかの奇妙な点と矛盾点:

72 5.2 3.0 MG EN LSラモーナと彼女の父クリアリー、ビバリーORD2111460
491 4.8 4.0 MG EN LSラモーナと彼女の母親クリアリー、ビバリーORD1748201
134 5.6 3.0 MG EN LSラモーナクインビー、8歳クリアリー、ビバリーORD1748201
29 4.7 5.0 MG EN LSバジル・E・コニグスブルク夫人の混合ファイルから、EL ORD1525579

「スマッシング」効果は、フィールド2またはフィールド3のいずれかで発生する可能性があることに注意してください... AND、フィールドの数は、「通常の」結果と1または2だけ異なります。

...だから、これを解決するために、私は次のようなものを試しました:

awk -F'\t' 'OFS="\t";$1 ~ /^[[:digit:]]/{print $1,gensub(/[[:space:]]/,"\t","g",$2),$3,$4,$5,$6,$7}' file.txt

これは、それぞれ、または少なくともほとんどの行を2倍にし、フィールドを切り取るようです。

編集 これは機能しているようです...これまでのところ、まだテスト中です。

awk -F'\t' '{$2 = gensub( /[[:space:]]/, "\t", "g", $2 );
             $3 = gensub( /[[:space:]]/, "\t", "g", $3 )}
             {OFS="\t";print}' file.txt

awkを使用してこの問題を解決する簡単な方法はありますか?

アップデート

スペースタブ変換の直前の状態を表すサンプルを要求する人もいます。以下は、前のサンプルがドキュメント内にある場所の近くのサンプルを表しています。ほぼ同じように見えます...一方[下]が間隔を空けて、もう一方[上]がタブ付きであることを除いて。pdftotextが以下のさまざまなサンプルの列2を処理する方法に注意してください...場合によっては分割され、場合によっては単一の列が作成されます。

サンプル1:

    72 5.2 3.0 MG EN RPラモーナと彼女の父クリアリー、ビバリーORD0630871
孤児です
   491 4.8 4.0 MG EN RPラモーナと彼女の母親クリアリー、ビバリーORD0785414
孤児でもあります
   186 4.8 4.0 MG EN RPラモーナフォーエバークリアリー、ビバリーORD0630871
永遠に孤児

サンプル2:

  79871 5.7 0.5 MG EN SQ TFK World Report 03-18-2005 Time for Kids Editors、ORD1915643
  79872 5.8 0.5 MG EN SQ TFK World Report 04-01-2005 Time for Kids Editors、ORD1915643
  79873 6.0 0.5 MG EN SQ TFK World Report 04-08-2005 Time for Kids Editors、ORD1915643

更新2

エドの提出物に以下の変更を加えました。単純化できると思いますが、機能します。孤立した回線を考慮に入れる必要があります。

$1 ~ /^[[:digit:]]+/{
   for (i=1;i<=6;i++)
      printf "%s\t", $i

   n = split($0,tmp,/  +/)

   for (i=2;i>=0;i--)
      printf "%s\t", tmp[n-i]

   print ""
}
$1 ~ /^[^[:digit:]]+/ {print $0}

多分これはもっときれいです:

{
        if ($1 ~ /^[[:digit:]]+/) {
                for (i=1;i<=6;i++)
                printf "%s\t", $i

                n = split($0,tmp,/  +/)

                for (i=2;i>=0;i--)
                printf "%s\t", tmp[n-i]

                print ""
        }
        else print $0;
}
4

5 に答える 5

5

元のawkスクリプトは、にOFS="\t"評価されるためtrue、各行が2倍になるように見えます。したがって、現在の行が出力されます。BEGIN{}繰り返しを避けるために、これをブロックに入れます。

gawk -F'\t' 'BEGIN{OFS=FS} $1 ~ /^[[:digit:]]/ {print $1,gensub(/[[:space:]]/,"\t","g",$2),$3,$4,$5,$6,$7}' file.txt

gensub()はの一部でgawkあるため、移植性がないことに注意してください。あなたはこれで移植的に同じことを達成することができます:

awk -F'\t' 'BEGIN{OFS=FS} $1 ~ /^[[:digit:]]/ {gsub(/[[:space:]]/,"\t",$2); print $1,$2,$3,$4,$5,$6,$7}' file.txt

そうは言っても...あなたのアップデートで、元のデータは十分にフォーマットされているので、おそらくそのまま処理することができます。列2と列4の間にスペースが1つしかないこと、またはフィールド区切り文字として複数のスペースを使用することもできます。それにもかかわらず、それは予測可能な入力形式です。

最初の6つのフィールドでは、入力は「任意の空白」で区切られ、最後の3つのフィールドでは、「2つ以上のスペース」で区切られているようです。そのことを念頭に置いて、次のawkを使用して入力データを解析できます。

#!/usr/bin/awk -f

BEGIN {
  FS="  +";
  fmt="----\n1=%s\n2=%s\n3=%s\n4=%s\n5=%s\n6=%s\n7=%s\n8=%s\n9=%s\n";
}

{
  # Grab the right-hand fields, separated by FS
  a[7]=$(NF-2); a[8]=$(NF-1); a[9]=$NF;

  # Then trim the line and grab initial fields, separated by whitespace
  sub(/^ +/, "");
  split($0, easy, /[[:space:]]+/);
  for(i=1;i<=6;i++) {
    a[i]=easy[i+1];
  }

  printf(fmt, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
}

これは、最後から2番目のフィールドと最後のフィールドの間の区切りに常に複数のスペースがあることを前提としています(質問で指定した入力データに示されているように)。これが安全な仮定でない場合、あなた/私たちはこれを回避するためにコーディングすることができます。

必要に応じて出力を調整します。

于 2012-10-31T18:23:19.913 に答える
3

データを破壊している可能性のあるsedコマンドの出力から始めるのではなく、そのsedコマンドを実行する前にデータを投稿して、そこから始めましょう。PDF変換ツールは「視覚的なレイアウト」を保持しているとおっしゃっているので、正しい解決策はおそらくgawkのFIELDWIDTHS機能を使用することであり、フィールドの幅に基づいてPDFコンバーターの出力を解析することであると思われます。フィールドセパレータを表すのに必要なスペースの数。

編集:これは比較のためのmatch()ベースのソリューションですが、実際には@ghotiが正しく、ソリューションはこれよりも単純だと思います:

$ cat file
    72   5.2 3.0 MG       EN   RP     Ramona and Her Father     Cleary, Beverly    ORD0630871
   491   4.8 4.0 MG       EN   RP     Ramona and Her Mother     Cleary, Beverly    ORD0785414
  79872  5.8  0.5  MG  EN   SQ    TFK World Report 04-01-2005  Time for Kids Editors,  ORD1915643
  79873  6.0  0.5  MG  EN   SQ    TFK World Report 04-08-2005  Time for Kids Editors,  ORD1915643
$
$ cat tst.awk
BEGIN {
   whl = "([[:digit:]]+)"
   dec = "([[:digit:]]+[.][[:digit:]]+)"
   wrd = "([^ ]+)"
   rst = "(.*)"
   s   = "[ ]+"
   fmt = whl s dec s dec s wrd s wrd s wrd s rst
}
{
   match($0,fmt,arr)
   split(arr[7],tmp,/  +/)
   arr[7] = tmp[1]
   arr[8] = tmp[2]
   arr[9] = tmp[3]

   for (i=1;i<=9;i++)
      printf "<%s>", arr[i]
   print ""
}
$
$ awk -f tst.awk file
<72><5.2><3.0><MG><EN><RP><Ramona and Her Father><Cleary, Beverly><ORD0630871>
<491><4.8><4.0><MG><EN><RP><Ramona and Her Mother><Cleary, Beverly><ORD0785414>
<79872><5.8><0.5><MG><EN><SQ><TFK World Report 04-01-2005><Time for Kids Editors,><ORD1915643>
<79873><6.0><0.5><MG><EN><SQ><TFK World Report 04-08-2005><Time for Kids Editors,><ORD1915643>

編集:ええ、これはもっと簡単な解決策です。最初の6つのフィールドを印刷してから、残りをマルチスペースセパレーターで分割します。

$ cat tst2.awk
{
   for (i=1;i<=6;i++)
      printf "<%s>", $i

   n = split($0,tmp,/  +/)

   for (i=2;i>=0;i--)
      printf "<%s>", tmp[n-i]

   print ""
}
$
$ awk -f tst2.awk file
<72><5.2><3.0><MG><EN><RP><Ramona and Her Father><Cleary, Beverly><ORD0630871>
<491><4.8><4.0><MG><EN><RP><Ramona and Her Mother><Cleary, Beverly><ORD0785414>
<79872><5.8><0.5><MG><EN><SQ><TFK World Report 04-01-2005><Time for Kids Editors,><ORD1915643>
<79873><6.0><0.5><MG><EN><SQ><TFK World Report 04-08-2005><Time for Kids Editors,><ORD1915643>
于 2012-10-31T14:24:55.860 に答える
2

の代わりに{print $1,gensub(/[[:space:]]/,"\t","g",$2),$3,$4,$5,$6,$7}、次を試してください。

{ $2 = gensub( /[[:space:]]/, "\t", "g", $2 ); print }
于 2012-10-31T13:33:35.470 に答える
1

これを試してみてください:

column -t file.txt > newfile.txt
于 2012-10-31T01:36:05.650 に答える
1

実際にスペースを入れることができるのは、最後から2番目と3番目の列だけだと思いますか?

私はPythonのこのビットのようなものを試してみます:

import re
import sys

for line in sys.stdin:
    start = line.rstrip().split(None, 6)
    end = start.pop().rsplit(None, 1)
    mid = re.split('\s\s+', end.pop(0), maxsplit=1)
    print '\t'.join(start + mid + end)

編集:OK、coreutils / textutilsツールを使い続けたい場合は、上記のPythonとほぼ同じことを行うsedスクリプトを次に示します。

#!/bin/sed -f
s/^ *//
s/ \+/\t/
s/ \+/\t/
s/ \+/\t/
s/ \+/\t/
s/ \+/\t/
s/ \+/\t/
s/ \+\([^ ]\+\) *$/\t\1/
s/  \+/\t/

または、ワンライナーとして:

sed -e 's/^ *//; s/ \+/\t/; s/ \+/\t/; s/ \+/\t/; s/ \+/\t/; s/ \+/\t/; s/ \+/\t/; s/ \+\([^ ]\+\) *$/\t\1/; s/  \+/\t/'
于 2012-10-31T01:49:18.500 に答える