1

テキスト ファイルを読み取り、それに含まれるすべての機密情報 (パスワード、IP アドレスなど) をマスクし、出力を別のファイルに書き込む tcl スクリプトを実装しようとしています。

今のところ、このデータを* * または ##### に置き換え、ファイル全体を正規表現で検索して、マスクする必要があるものを見つけています。しかし、私のテキスト ファイルは 10 万行以上のテキストになる可能性があるため、これは非常に非効率的であることが判明しています。

これをより速く行うために利用できる組み込みの tcl 関数/コマンドはありますか? これを行うのに役立つ追加オプションを提供するアドオンパッケージはありますか?

注: 私は tcl 8.4 を使用しています (ただし、tcl の新しいバージョンでこれを行う方法がある場合は、それらを教えてください)

4

3 に答える 3

2

一般的に言えば、Tclから最高のパフォーマンスを引き出すには、コードをプロシージャに入れる必要があります。(ラムダ項やクラスメソッドなど、8.5および8.6にはさらにいくつかの関連オプションがありますが、これらはプロシージャに密接に関連しています。)他にもいくつか注意する必要があります。

  • 式を(expr {$a + $b}ではなくexpr $a + $b)中かっこで囲むと、はるかに効率的なコンパイル戦略が可能になります。
  • チャネルエンコーディングを慎重に選択してください。(そうすると、そのチャネルは文字ではなくバイトfconfigure $chan -translation binaryを転送します。ただし、8.4のバイト指向チャネルではあまり効率的ではありません。使用するとほとんどの利点が得られます。)gets-encoding iso8859-1 -translation lf
  • Tclはチャネルバッファリングを非常にうまく行います。
  • さまざまなバージョンのTclを使用してコードをベンチマークし、どれが最適に機能するかを確認することをお勧めします。テストのためだけに複数のTclインタープリターをインストールするという(マイナーな)面倒な作業をしたくない場合は、テストにtclkitビルドを使用してみてください。

行指向の変換を行う慣用的な方法は次のとおりです。

proc transformFile {sourceFile targetFile RE replacement} {
    # Open for reading
    set fin [open $sourceFile]
    fconfigure $fin -encoding iso8859-1 -translation lf

    # Open for writing
    set fout [open $targetFile w]
    fconfigure $fout -encoding iso8859-1 -translation lf

    # Iterate over the lines, applying the replacement
    while {[gets $fin line] >= 0} {
        regsub -- $RE $line $replacement line
        puts $fout $line
    }

    # All done
    close $fin
    close $fout
}

ファイルが十分に小さく、すべてがメモリに簡単に収まる場合は、一致-置換ループ全体がCレベルに引き上げられるため、これはより効率的です。

proc transformFile {sourceFile targetFile RE replacement} {
    # Open for reading
    set fin [open $sourceFile]
    fconfigure $fin -encoding iso8859-1 -translation lf

    # Open for writing
    set fout [open $targetFile w]
    fconfigure $fout -encoding iso8859-1 -translation lf

    # Apply the replacement over all lines
    regsub -all -line -- $RE [read $fin] $replacement outputlines
    puts $fout $outputlines

    # All done
    close $fin
    close $fout
}

最後に、正規表現は必ずしも文字列の照合を行うための最速の方法ではありません(たとえば、string matchはるかに高速ですが、はるかに制限されたタイプのパターンを受け入れます)。あるスタイルの置換コードを別のスタイルに変換し、それを非常に高速に実行することは、100%簡単ではありません(REは非常に柔軟です)。

于 2013-03-19T14:03:55.703 に答える
1

100K 行のファイルはそれほど多くありません (すべての行が 1K 文字の長さでない限り:) のでread、ファイル全体を var に入れ、その var を置換することをお勧めします:

set fd [open file r+]
set buf [read $fd]
set buf [regsub -all $(the-passwd-pattern) $buf ****]
# write it back
seek $fd 0; # This is not safe! See potrzebie's comment for details.
puts -nonewline $fd $buf
close $fd
于 2013-03-19T08:08:01.967 に答える
1

特に非常に大きなファイルの場合、前述のように、ファイル全体を変数に読み込むのは最善の方法ではありません。システムのメモリが不足するとすぐに、アプリのクラッシュを防ぐことはできません。改行で区切られたデータの場合、最も簡単な解決策は、1 行をバッファリングして処理することです。

例を挙げると:

# Open old and new file
set old [open "input.txt" r]
set new [open "output.txt" w]
# Configure input channel to provide data separated by line breaks
fconfigure $old -buffering line
# Until the end of the file is reached:
while {[gets $old ln] != -1} {
    # Mask sensitive information on variable ln
    ...
    # Write back line to new file
    puts $new $ln
}
# Close channels
close $old
close $new

Tcl で大きなファイルを処理するためのより良い方法は考えられません。より良い解決策を教えてください。しかし、Tcl は大きなデータ ファイルを処理するようには作られていませんでした。実際のパフォーマンスを得るには、スクリプト化されたプログラミング言語の代わりにコンパイル済みのプログラミング言語を使用できます。

編集:![eof $old] while ループに置き換えられました。

于 2013-03-19T08:18:29.250 に答える