2009-06-09 7 views
0

Webログを解析し、ログの各部分が有効であることを確認するRubyプログラムを作成しようとしています。私は、ログの要求文字列の場合に対処しようとすると、開始と終了の文字列のほかに二重引用符が追加されています。私は正規表現の形でWebログを作りました。なぜなら、各部分のmake変数を読む方が簡単だからです。ここで私がこれまで持ってWUTです:Webログ要求文字列の二重引用符を取り除く方法

isVal = true 
lines = lg.readlines 
logLine_regex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) - (\w*|-) \[(\d{2})\/(\w{3})\/(\d{4}):(\d{2}):(\d{2}):(\d{2})\s(-0400)\] (".*") (\d+) (\d+|-)$/ 

lines.each{ |line| 

    linePos = logLine_regex.match(line) 

    if linePos == nil 
     isVal = false 
    elsif linePos[0] != line.chomp 
     isVal = false 
    elsif !((0..255).include?(linePos[1].to_i)) 
     isVal = false 
    elsif !((0..255).include?(linePos[2].to_i)) 
     isVal = false 
    elsif !((0..255).include?(linePos[3].to_i)) 
     isVal = false 
    elsif !((0..255).include?(linePos[4].to_i)) 
     isVal = false 
    #linePos[5] = Username or hyphen 
    elsif !((1..31).include?(linePos[6].to_i)) 
     isVal = false 
    elsif !(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].include?(linePos[7])) 
     isVal = false 
    elsif !((0..9999).include?(linePos[8].to_i)) 
     isVal = false 
    elsif !((0..23).include?(linePos[9].to_i)) 
     isVal = false 
    elsif !((0..59).include?(linePos[10].to_i)) 
     isVal = false 
    elsif !((0..59).include?(linePos[11].to_i)) 
     isVal = false 
    #linePos[12] = -4000 
    #linePos[13] = request 
    elsif !((0..9999).include?(linePos[14].to_i)) 
     isVal = false 
    #linePos[15] = bytes 
    else 
     isVal = true 
    end 

} 

は、私は、彼らが追加されている場合は、二重引用符はバックスラッシュを付けることによって逃げることができることを知っているが、私はどのようにそれがRubyでコードにないアイデアを持っていません。助けてください??

+0

問題を表示するためにいくつかのログ行を掲載することができますか? q1、q2、q3、q4、日、月、年、時、分、秒、foo = logLine_regex.match(行)この形式は読みやすさのために考慮する必要があります。 – user60401

答えて

1

簡単なアプローチは、シンプルなトークンで正規表現を定義することです。ここでは、文字列の内容を0個以上のバックスラッシュクォートまたは非クォート文字のインスタンスに定義しました。

examples = [ 
    '"foo"', 
    '"foo\"bar\""', 
    'empty', 
    'one more "time"', 
    'the "last" man "standing"' 
] 

examples.each do |example| 
    puts "%s => %s" % [ example, example.match(/\"(?:\\"|[^"])*?\"/) ] 
end 

ここでは、さまざまな例でどのように動作するかを確認できます。

ログファイルの内容をデコードする戦略についての注意点として、一連の長時間の面倒なif文としての検証は、重大なパフォーマンスの低下を招く可能性があります。特定のフィールドの内容を検証するためのさまざまなアプローチを広範にベンチマークすることができます。たとえば、.to_iを実行し、次に低い値と高い値を比較するよりも、有効なすべての数値0.255のFixnum相当量をハッシュに格納するほうが効率的です。

0

まず第一に、あなたはすべてのそのポストの検証を行う必要はありませんので、BYTE_REだけその整数値が0〜255である文字列を受け付けますので、私たち

BYTE_RE = /(?:[012]?\d)?\d/ 
IP_RE = /#{BYTE_RE}(?:\.#{BYTE_RE}){3}/ 
DAY_RE = /0?[1-9]|[12]\d|3[01]/ 
MONTH_RE = /Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/ 
YEAR_RE = /\d{4}/ 
DATE_RE = %r!#{DAY_RE}/#{MONTH_RE}/#{YEAR_RE}! 
HOUR_RE = /[01]?\d|2[0-3]/ 
MIN_RE = /[0-5]\d/ 
SEC_RE = MIN_RE 
TIME_RE = /#{HOUR_RE}:#{MIN_RE}:#{SEC_RE}\s-400/ 
DATETIME_RE = /#{DATE_RE}:#{TIME_RE}/ 
STRING_RE = /"(?:\\.|[^\\"])*"/ 

logLine_regex = /^#{IP_RE} - (?:\w*|-) \[#{DATETIME_RE}\] #{STRING_RE} \d{4} (?:\d+|-)$/ 
isVal = lg.readlines.all? { |line| line =~ logLine_regex } 

、粉々にあなたの正規表現を打破してみましょう後でそれを検証する必要はありません。 これには000が含まれています。したがって、0にすることなく数値に制限する場合は、/\d|[1-9]\d|[12]\d\d/に変更してください。

DAY_REは、整数値が1-31の文字列のみを受け入れます。先頭のゼロを削除する場合は、/[1-9]|[12]\d|3[01]/を使用してください。 あなたの例では年を検証する必要はありません。正確に4桁であるため、0〜9999の範囲である必要があります。 それを検証するのを避けるために、ポジション14でも同じことができます。

HOUR_REは、整数値が0〜23の文字列のみを受け入れます。先行ゼロを受け入れない場合、/1?\d|2[0-3]/となります。 MIN_RESEC_RE 制限は、我々がSTRING_REを使用する文字列を検証し、そして0と

59の間の整数値を有するものとの文字列を受け入れました。私はこれを打ち破ります。

  • " - オープン引用
  • (?:...) - グループ化のための良好な非キャプチャー括弧、。
    • \\. - 任意のバックスラッシュ文字の組み合わせは - 文字列はエスケープと一致し\n\a\\、または\"
    • |のような - 直前のパターンや
    • [^\\"]次のいずれか - バックスラッシュまたはダブルクォート以外の任意の文字
  • * - 前記原子の0個以上
  • " - 近い引用

は、これはオープンダブルクォート、エスケープ文字や定期的な任意の数の文字、[閉じる引用符に一致します。

^を開始し、$ アンカーがそのの世話を閉じているので、正規表現によって確認された量は、全体のラインであることを確認する必要はありません。

私たちは事実の後ですべての検証を削除しました。すべての行が与えられた正規表現と と一致するかどうかだけを知りたいので、Enumerable#all?を使用できます.fがtrueなら、すべての行が の正規表現と一致する場合のみです。さらに、副次的なメリットとして、falseが返された場合は早期に終了します。つまり、この場合は少し早く を実行します。

関連する問題