特定の条件に基づいてファイルからテキストを抽出する

特定の条件に基づいてファイルからテキストを抽出する

次の履歴を含むファイルがあります。

434419\Teclu\Tudor\1501\9502
187650\Cosma\Sorin\1504\9253
239474\Teclu\Daniel\1502\5245
844936\Gaman\Mihai\1505\4074
942341\Avram\Tudor\1505\4543
137158\Gaman\Marius\1505\5244
531747\Francu\Daniel\1503\2226
382144\Teclu\Daniel\1501\9943
913409\Gaman\Mihai\1501\5473
901028\Avram\Mihai\1502\6169
382207\Dedu\Alex\1504\5428
726697\Gaman\Sorin\1502\5071
271503\Gaman\Ionut\1505\6643
147791\Dedu\Dragos\1503\4955
495572\Cosma\Alex\1505\9750
769482\Popescu\Sorin\1505\5472
410724\Marin\Mihai\1502\7317
381000\Marin\Daniel\1503\7321
251934\Popescu\Ionut\1504\8288
416161\Gaman\Mihai\1501\8245
523401\Gaman\Mihai\1504\3101
347491\Avram\Daniel\1504\2017
329372\Dedu\Sorin\1502\8528
509554\Popescu\Ionut\1502\7972

\で区切られたフィールド。最初のフィールドはID、2番目のフィールドは姓、3番目のフィールドは名前、4番目のフィールドは給与、5番目のフィールドは姓です。

1 つのパラメーター (つまり、姓) を使用して、ファイルの最初と最後の 10 行で、その名前を持つ人を検索するスクリプトを作成する必要があります。次に、これらの人物の中で最も給与の低い人を選択するか、同じ名前と給与の人が2人以上いる場合は、パフォーマンススコアを比較してスコアが高い人を選択します。この人の場合は、身分証明書を印刷する必要があります。

私は頭と尾のトリミングの組み合わせとより多くのコマンドを試しました。

{ head -n 10 file.txt ; tail -n 10 file.txt } | grep $NAME | sort -t '\' -r k 4

給与が低いものから高いものの順に並べておきましたが、給与が同じであれば次にはどうすべきかわかりません。

答え1

コマンドの先頭を保持します。

{ head -n 10 file.txt ; tail -n 10 file.txt; } |
grep $NAME | sort -t '\' -k 4 -k 5 |
awk -F'\\' '!wage{wage=$4;id=$1;next} wage==$4{id=$1} END{print id}'

これawkスクリプトは、デフォルトでユーザーが提供したアルゴリズムのテキスト記述を取得し、数式に入れます。

もちろん、パイプラインの最初の3つのコマンドをより多くのawkロジックに置き換えることもできます。たとえば、次のようになります。

$ myFun() {
    awk -F'\\' -v s=$2 -v l=`wc -l<$1` '
      $2==s&&(NR<11||NR>l-11)&&(!wage||wage>$4||(wage==$4&&$5>perf)){
        wage=$4; id=$1; perf=$5;
      }
      END{ print id; }' $1; }
$ myFun exampleData.dsv Teclu
382144
$ myFun exampleData.dsv Gaman
416161

コメント内のOPを参照してください: '$1'、 '$2'など、awkの変数は同じ名前のシェル変数とは無関係です。

答え2

TXR リース:

(defstruct person ()
  id last first wage score
  (:method equal (me)
    (list (- me.wage) me.score)))

(let* ((surname (pop *args*))
       (database (build (awk (:set fs "\\")     ;; backslash field sep
                             ((fconv i - - i i) ;; int, noconv, noconv, int, int
                              (add (new person
                                        id [f 0] last [f 1] first [f 2]
                                        wage [f 3] score [f 4])))))))
  (del [database 10..-10]) ;; drop all but first/last ten
  (let* ((select-surname (keep-if (op equal @1.last surname) database))
         (best (find-max select-surname)))
    (put-line (if best `best ID: @{best.id}` "notfound"))))

テスト:

$ txr process.tl nonexistent data
notfound
$ txr process.tl Teclu data
best ID: 382144
$ txr process.tl Gaman data
best ID: 416161
$ txr process.tl Popescu data
best ID: 509554
$ txr process.tl Francu data
best ID: 531747

(find-max select-surname)簡単な方法、つまり姓でフィルタ処理されたデータベースに関数を適用して最良のIDを見つけることができるのはなぜfind-maxですか。同等の代替 構造に対して定義されたメソッドperson

(:method equal (me)
  (list (- me.wage) me.score))

equalこのメソッドが存在すると、lessこの型のオブジェクトが以上の値と比較されるか、ハッシュ:equal-basedテーブルなどでハッシュされるたびにオブジェクトのメソッドがequal呼び出され、戻り値がその場で使用されます。したがって、ここで言うのは、personマイナス賃金(低いほど良い)と分数のリストを使用して2つの項目の平等を比較することです。そこで、リスト同等/不等の一般的なTXR Lispの意味が適用されます。

1> (greater '(1 1) '(1 0))
t
2> (greater '(1 1) '(1 2))
nil
3> (greater '(2 1) '(1 2))
t

対応する最初の要素が比較され、同じ場合、2番目の要素が比較される式です。

関連情報