連続した数値を含む数値リストのフィルタリング

連続した数値を含む数値リストのフィルタリング

多くのテキストファイルをフィルタリングしたいです。各ファイルには長い数字のリストが含まれています。ファイルは、各数字の連続した数字に基づいてフィルタリングする必要があります。

リストの例では、次のファイルのいずれかを構成します。

入力ファイルdata.log:

12365
91738
349874
128152639
1234
7654
08767
1234567

私の考えでは:

1 - 2つの連続した数字を含む数字でこのリストをフィルタリングします。予想される出力は次のとおりです。

12365
349874
128152639
1234
7654
08767
1234567

2〜3つの連続した数字を含む数字でこのリストをフィルタリングします。予想される出力は次のとおりです。

12365
349874
1234
7654
08767
1234567

3〜4つの連続した数字を含む数字でこのリストをフィルタリングします。予想される出力は次のとおりです。

1234
7654
1234567

4〜5つの連続した数字を含む数字でこのリストをフィルタリングすると、予想される出力は次のようになります。

1234567

数字内の連続した数字の順序が最小のものから最大のもの(例:1234...など)、または大きいものから小さいもの(例:54321)の場合は、出力に含める必要があります。

答え1

grepteeおよびを使用して、-ismsでいっぱいのトリッキーな小さな関数を作成しrevます。bash

dqs() { a=${2:-123456789} ; [ "$1" -ge 2 ] &&  
        grep -iF "$(eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} |
                    tee >(rev) )"
       }

テストを受けてください:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

仕組み:

printf目的の長さのシーケンスのリストを印刷します(例:123234など。)、teeミラーを取り付けます(つまり右から左へ、または後ろに)rev次に、grep -f <(...)そのリストの項目の標準入力を検索します。

このシーケンスのリストを作成するには通常、ループまたはseq両方が必要ですが、ここでは次のようにします。bash 配列表現, と結合部分文字列拡張、少し残った山水。ただし、bashインタプリタが必要な順序でこれらの操作を実行できないため、これは不可能です。だから私たちは正しい順序で仕事をするためにeval evalいくつかの戦略を使います。\\\bash

ここでは[ "$@" -gt 0 ] &&機能的には必要ありませんが、持っている方が安全です。それはそこにdqsあることを保証します1つだけ数値引数です。それ以外の場合はgrep実行されません。これはeval eval何もしません。邪悪な

ボーナス:2番目の引数を追加すると、他のシーケンスが123456789変更されてもコードは機能し続けます。たとえば、dqs 4 123456789ABCDEF4桁の16進数シーケンス(および逆順)が検索され、dqs 3 $(printf %s {a..z})3桁のアルファベットシーケンスが検索されます。

# search `man bash` for the three most popular words 
# that have 3 three char alphabetic runs
man bash | tr ' ' '\n' | sort | uniq -c | sort -gr  | 
dqs 3 $(printf '%s' {a..z}) | head -3

出力:

     92 first
     76 default
     38 environment

答え2

非常に大きなファイルが多いと、awkの正規表現の一致が遅くなる可能性があります。 1つのアプローチは、grepを使用して難しい作業を実行し、awkを使用して検索する文字列のリストを作成することです(これをハードコーディングしたくないからです)。つまり

$grep -E '12|98|23|87|34|76|45|65|56|54|67|43|78|32|89|21' data.log

2人のキャラクターに対してこれを行うことは可能ですが、最大9人のキャラクターに対して行うことができるようにしたいです。複数のパターン検索をサポートするには、grepを拡張するには-Eが必要です(12 | 98は2つのパターンです)。通常のol 'grepはこれを許可しません。

awkは文字列123456789を繰り返して連続セグメントを取り出すことができますが、前後に移動しようとしています。

$awk 'BEGIN {f=123456789 ; b=987654321 ; for(i=1;i<9;i++) print substr(f,i,2),substr(b,i,2)}'
12 98
23 87
34 76
45 65
56 54
67 43
78 32
89 21

長さが2にハードコードされないように何かを追加しましょう(-vn = 3はawkスクリプト内で変数n = 3を設定します)。

$awk -vn=3 'BEGIN {f=123456789 ; b=987654321 ; for(i=1;i<11-n;i++) print substr(f,i,n),substr(b,i,n)}'
123 987
234 876
345 765
456 654
567 543
678 432
789 321

そして(ほとんど!)出力レコード区切り記号(ORS)と出力フィールド区切り記号(OFS)

$awk -vn=3 'BEGIN {ORS="|" ; OFS="|" ; f=123456789 ; b=987654321 ; for(i=1;i<11-n;i++) print substr(f,i,n),substr(b,i,n)}'
123|987|234|876|345|765|456|654|567|543|678|432|789|321|

321以降の最後のパイプを削除する必要があります。それ以外の場合はgrepがすべてのエントリと一致するため、sed '.$//'を追加して、文字列の終わり($)の前の最後の文字を何もないものに置き換えます。

$awk -vn=3 'BEGIN {ORS="|" ; OFS="|" ; f=123456789 ; b=987654321 ; for(i=1;i<11-n;i++) print substr(f,i,n),substr(b,i,n)}' | sed 's/.$//'

これでシェルスクリプトに入れて、一般的な検索を行うことができます。

$cat t.sh
#!/bin/bash
grep -E `awk --assign n=$1 'BEGIN {OFS="|" ; ORS="|" ; f=123456789 ; b=987654321 ; for(i=1;i<11-n;i++) print substr(f,i,n),substr(b,i,n)}' | sed 's/.$//'` $2

$chmod 775 t.sh
$./t.sh 4 data.log
1234
7654
1234567

答え3

多くの大容量ファイルは、これをすばやく実行する必要があることを示しています。これは次のことを意味しますwhile readルーティングはできません。。ここで気づくべきことの1つは、各運動が(少なくとも)小さなパターンセットの1つと一致するように縮小できることです。本物またはなどのクイック使用grepまたは同様のツール。たとえば、5桁のシーケンスの場合:rgack

grep -e 12345 -e 23456 […] -e 65432 -e 54321

man grep詳細と使い方はこちらグレッグのウィキBashをすばやく学びましょう。

関連情報