大きな文字列の一致数をすばやく計算

大きな文字列の一致数をすばやく計算

1行にスペースがなく、他の行もないテキストデータがたくさんあります。実際の流れは0.2Gb/sです。ここただし、この操作では、発生回数を計算するのが空行を計算するよりも困難です。ゲームは

585e0000fe5a1eda480000000d00030007000000cd010000

サンプルデータのサブセットは次のとおりです。ここと言う2015.6.30_data.txt完全なバイナリデータここと言う0002.生。試合は1回発生しました。2015.6.30_data.txtしかし、データ全体では10倍です。0002.生一行に。経由でtxtデータを準備しましたxxd -ps 0002.raw > /tmp/1 && fold -w2 /tmp/1 > /tmp/2 && gsed ':a;N;$!ba;s/\n//g' /tmp/2 > /tmp/3。実装は速いほど良いです。列に大きな文字列を準備するには、これを使用できますxxd -ps 0002.raw > /tmp/1 && fold -w2 /tmp/1 > /tmp/2。現在の速度はゲームあたり0.0012秒です。これはデータファイル全体で10ゲームあたり0.012秒なので遅いです。

Grepはこれを行ごとに実行するため、カウントできません。 Vimでは、%s/veryLongThing//gn作業を完了するだけでは十分ではありません。このコマンドはwc文字、バイト、行のみを提供するので、適切なツールではありませんが、他のものと組み合わせることは可能です。それはおそらくGNU FindとSedの組み合わせでしょう。しかし、すべての実装が複雑すぎるようです。

Mikeservの返信結果

$ cat 1.7.2015.sh 
time \
    ( export ggrep="$(printf '^ \376Z\36\332H \r \3 \a \315\1')" \
             gtr='\1\3\a\r\36HZ^\315\332\376'
             LC_ALL=C
      gtr -cs "$gtr" ' [\n*]' |
      gcut -sd\  -f1-6       |
      ggrep -xFc "$ggrep"
    ) <0002.raw

$ sh 1.7.2015.sh 
1

real    0m0.009s
user    0m0.006s
sys 0m0.007s

-----------

$ cat 1.7.2015.sh 
time \
    (  set      x58 x5e x20 x20 xfe x5a x1e xda \
                x48 x20 x20 x20 x0d x20 x03 x20 \
                x07 x20 x20 x20 xcd x01 x20 x20
        export  ggrep="$(shift;IFS=\\;printf "\\$*")"    \
                gtr='\0\1\3\a\r\36HXZ^\315\332\376'      \
                LC_ALL=C i=0
        while [ "$((i+=1))" -lt 1000 ]
        do    gcat 0002.raw; done            |
        gtr -cd "$gtr" |gtr 'X\0' '\n '      |
        gcut -c-23    |ggrep -xFc "$ggrep"
    ) 

$ sh 1.7.2015.sh 
9990

real    0m4.371s
user    0m1.548s
sys 0m2.167s

すべてのツールはGNU coreutilsであり、コードに提供するすべてのオプションがあります。ただし、GNU devtoolsとは異なる場合があります。 Mikeservはコードを990回実行し、10のイベントを持つため、合計9990のイベントが正確です。

スーパー文字列の一致数を効率的に計算するには?

答え1

GNUの実装grep(最新バージョンは完全な(ほとんど互換性のある)書き換えですが、ほとんどの最新のBSDにもあります)は-o出力オプションをサポートします。みんな一致する部品。

LC_ALL=C grep -ao CDA | wc -l

これにより、すべての発生回数が計算されます。

LC_ALL=C grep -abo CDA

バイトオフセットで探します。

LC_ALL=Cgrep高価なUTF-8解析を試みないでください(固定ASCII文字列検索では、grep独自にUTF-8解析を最適化できるはずですが)。バイナリについて考えるように-a言うのは別のGNUismです。grep

答え2

そのため、16進文字列をバイトで印刷しましたが、NULを<spaces>に置き換えました。(主にスキーマでNULを取得する方法がわからないためですgrep:

time \
    (  set      x58 x5e x20 x20 xfe x5a x1e xda \
                x48 x20 x20 x20 x0d x20 x03 x20 \
                x07 x20 x20 x20 xcd x01 x20 x20
        export  grep="$(shift;IFS=\\;printf "\\$*")"    \
                tr='\0\1\3\a\r\36HXZ^\315\332\376'      \
                LC_ALL=C i=0
        while [ "$((i+=1))" -lt 1000 ]
        do    cat 0002.raw; done     |
        tr -cd "$tr" |tr 'X\0' '\n ' |
        cut -c-23    |grep -xFc "$grep"
    )

そこにある変数は、16進文字列のバイト値の8進エスケープ/ ASCII文字で構成されています。なぜなら、その報酬を取り除きtrたいからです。次に、一致しようとする最長行があるバイトであることを確認し、X文字をewlineに変換し、NULを<spaces>に置き換えて、文字列が常に行のタイトルになるようにしました。tr-dgrep-c-23cuttr\n

catここでは、パイプラインで元のバイナリを999回実行しました。ファイルに10個の一致があるため、結果は次のようになります。

9990
1.06s user 0.94s system 65% cpu 3.054 total

今私もテストしてみました。

time \
    (  set      x58 x5e x20 x20 xfe x5a x1e xda \
                x48 x20 x20 x20 x0d x20 x03 x20 \
                x07 x20 x20 x20 xcd x01 x20 x20
        export  LC_ALL=C i=0 grep="$(IFS=\\;printf "\\$*")"
        while [ "$((i+=1))" -lt 1000 ]
        do    cat 0002.raw;  done    |
        tr '\0 ' ' \0'   |
        grep -aFo "$grep"| wc -l
    )

私はそこを使用していますが、テストで完全に使用して削除してもwc -l実行時間に影響を与えないようです。とにかく数は同じです。結果は次のとおりです。-caFowc

9990
1.56s user 1.46s system 82% cpu 3.648 total

今、これら2つのコマンドセットは同じではありません。不要なバイトを最初に絞ると、より速く実行されるように見えますが、これはカウントを取得できますが、tr2番目の例ではスイッチを追加して-bオフセットを取得できないことを意味します。grep

time \
   (    set     x58 x5e x20 x20 xfe x5a x1e xda \
                x48 x20 x20 x20 x0d x20 x03 x20 \
                x07 x20 x20 x20 xcd x01 x20 x20
        export  LC_ALL=C i=0 grep="$(IFS=\\;printf "\\$*")"
        while [ "$((i+=1))" -lt 1000 ]
        do    cat 0002.raw;  done    |
        tr '\0 ' ' \0'     |
        grep -baFo "$grep" | sed -n l
   )

...

241133568:X^  \376Z\036\332H   \r \003 \a   \315\001  $
241157720:X^  \376Z\036\332H   \r \003 \a   \315\001  $
241181872:X^  \376Z\036\332H   \r \003 \a   \315\001  $
241206024:X^  \376Z\036\332H   \r \003 \a   \315\001  $
241230176:X^  \376Z\036\332H   \r \003 \a   \315\001  $
241254328:X^  \376Z\036\332H   \r \003 \a   \315\001  $

1.59s user 1.41s system 85% cpu 3.496 total

だから、どんなものを選んでも、何をしたいのかによって変わると思います。数学的に計算するだけでtr -cd良いでしょう。毎回他の方法より0.5秒速いです。しかし、それほど一般的ではないので、喜んでサポートしている場合はgrep必要grep -baFoになるかもしれません。

関連情報