2

大きなログ ファイル (約 500 MB) を解析したい。これが仕事に適したツールでない場合は、お知らせください。

このように構成された内容のログファイルがあります。各セクションには、追加のキーと値のペアを含めることができます。

requestID: saldksadk
time: 92389389
action: foobarr
----------------------
requestID: 2393029
time: 92389389
action: helloworld
source: email
----------------------
requestID: skjflkjasf3
time: 92389389
userAgent: mobile browser
----------------------
requestID: gdfgfdsdf
time: 92389389
action: randoms

ログ内の各セクションのデータを処理する簡単な方法があるかどうか疑問に思っていました。セクションは複数の行にまたがる可能性があるため、文字列を単純に分割することはできません。たとえば、次のような簡単な方法はありますか。

for(section in log){
   // handle section contents
}
4

5 に答える 5

3

サンプル テキストを「test.txt」というファイルに保存しました。それを開く:

File.foreach('test.txt').slice_before(/^---/).to_a

戻り値:

[
  ["requestID: saldksadk\n", "time: 92389389\n", "action: foobarr\n"], 
  ["----------------------\n", "requestID: 2393029\n", "time: 92389389\n", "action: helloworld\n", "source: email\n"], 
  ["----------------------\n", "requestID: skjflkjasf3\n", "time: 92389389\n", "userAgent: mobile browser\n"], 
  ["----------------------\n", "requestID: gdfgfdsdf\n", "time: 92389389\n", "action: randoms\n"]
]

各サブ配列をフィルターに通すことで、先頭の「---」を取り除くことができます。

blocks = File.foreach('test.txt').slice_before(/^---/).map { |ary|
  ary.shift if ary.first[/^---/]
  ary.map(&:chomp)
}

実行後blocksは次のとおりです。

[
  ["requestID: saldksadk", "time: 92389389", "action: foobarr"],
  ["requestID: 2393029", "time: 92389389", "action: helloworld", "source: email"],
  ["requestID: skjflkjasf3", "time: 92389389", "userAgent: mobile browser"],
  ["requestID: gdfgfdsdf", "time: 92389389", "action: randoms"]
]

もう少し微調整:

blocks = File.foreach('test.txt').slice_before(/^---/).map { |ary|
  ary.shift if ary.first[/^---/]
  Hash[ary.map{ |s| s.chomp.split(':') }]
}

となり、次のblocksようになります。

[
  {"requestID"=>" saldksadk", "time"=>" 92389389", "action"=>" foobarr"},
  {"requestID"=>" 2393029", "time"=>" 92389389", "action"=>" helloworld", "source"=>" email"},
  {"requestID"=>" skjflkjasf3", "time"=>" 92389389", "userAgent"=>" mobile browser"},
  {"requestID"=>" gdfgfdsdf", "time"=>" 92389389", "action"=>" randoms"}
]
于 2013-06-07T03:24:13.567 に答える
1

それを行うための非常に基本的な方法で、シンプルで効率的です。

blocks = []
current_block = {}

sep_range = 0..3
sep_value = "----"

split_pattern = /:\s*/

File.open("filename.txt", 'r') do |f|
  f.each_line do |line|
    if line[sep_range] == sep_value
      blocks << current_block unless current_block.empty?
      current_block = {}
    else
      key, value = line.split(split_pattern, 2)
      current_block[key] = value
    end
  end
end

blocks << current_block unless current_block.empty?

指摘すべき重要な点は、ループ内で不要な重複オブジェクト (範囲、テスト文字列、分割正規表現パターン) を作成することを避け、代わりにループが始まる前にそれらを定義することです。これにより、時間とメモリが少し節約されます。500MB のファイルでは、これはかなりの量になる可能性があります。

于 2013-06-07T03:39:12.870 に答える