複数ファイルの各行の文字列リストの計算

複数ファイルの各行の文字列リストの計算

250個の文字列があり、400個のファイルの各行(最大20,000行)に各文字列が表示される回数を数える必要があります。文字列の例:

journal
moon pig
owls

ファイルの例:

This text has journal and moon pig
This text has owls and owls

出力例:

1   0
1   0
0   2

編集:最初の列はファイルの最初の行から始まる文字列を計算し、2番目の列はファイルの2行目を表します。

動作するコードがありますが、非常に遅いようです。私はawkが作業をスピードアップできると確信していますが、私はそれを書くのに十分ではありません。

for file in folder/*
do
    name=$(basename "$file" .txt)
    linenum=1
    while read line
    do
        while read searches
        do
            ###count every time string appears on line and save
            count=$(echo $line | grep -oi "$searches" | wc -l)
            echo $count >> out/${name}_${linenum}.txt
        done < strings.txt
        linenum=$((linenum+1))
    done < $file
done

編集:こうして400回を貼り付けました。ここで、x は元のファイルの行数です。

paste out/file1_{1..x}.txt > out/file1_all.txt

スピードを上げる方法を知っている人はいますか?

答え1

もし

$ cat strings
journal
moon pig
owls

そして

$ cat file
I like to journal about owls and moon pigs.
owls are birds. moon pigs are not.
owls owls owls

その後、GNU awkを次のように使用できます。

gawk '
    NR == FNR { string[++n] = $0; next}
    {
        for (i=1; i<=n; i++)
            # gsub() return the number of replacements.
            # it is a convenient way to count instances of fixed strings.
            count[i][FNR] = gsub(string[i], string[i])
        if (FNR > max)
            max = FNR
    }
    END {
        for (i=1; i<=n; i++) {
            for (j=1; j<=max; j++)
                printf "%s\t", 0 + count[i][j]
            print ""
        }
    }
' strings file

出力

1   0   0
1   1   0
1   1   3

私はawkプログラムについてはまったく説明していません。把握できることを確認し、ご質問がある場合はお問い合わせください。

答え2

1行あたりの数の配列を取得し、各行を即座に処理するコアアルゴリズムは次のとおりです。

gawk ' NR == FNR { string[++n] = $0; next}
       { for (i=1; i<=n; i++) 
             printf("%s\t", gsub(string[i],""))
         print ""
       }
     ' strings file

これはgsubに基づいて行われた代替回数を提供します。

これにより、次のような出力が生成されます。

1   1   0   
0   0   2

これはあなたが要求した転置行列です。 awkで列と行を変更するのは少し複雑です。また、複数のファイルを処理することもできます。ファイル変更マークとして空白行を使用して、2つのスクリプトをリンク(パイプ)できます。同じファイルを2回処理します。

awk '
    NR == FNR { string[++n] = $0; next}
    FNR==1 && p == 1 { print "" }
    { for (i=1; i<=n; i++) printf("%s\t", gsub(string[i],""))
      print ""
      p = 1
    }
    END    { print "" }
' strings.txt    infile.txt    infile.txt |
awk '!/^$/{ 
       for(i=1;i<=NF;i++) f[NR-r][i]=$i ;
       if (maxf<NF) maxf = NF ;
       if (maxr<(NR-r)) maxr = NR-r ;
     } 
     /^$/{
         for(      i=1 ; i<=maxf ; i++ )
         {
             for(  j=1 ; j<=maxr ; j++ )
                 printf("%s\t",f[j][i])
             print ( "loop", maxf, maxr, r )
         }
     r=NR
     print ( "" )
     maxf=0
     maxr=0
     delete f
     }'

これは質問に対する答えを提供します。

1   0
1   0
0   2

1   0
1   0
0   2

関連情報