Python中的多行匹配

Chr*_*ris 7 python regex

我已经阅读了所有可以找到的文章,甚至可以理解其中的一些文章,但作为一个Python新手,我仍然有点迷失并希望得到帮助:)

我正在编写一个脚本来解析特定于应用程序的日志文件中感兴趣的项目,每行都以一个我可以匹配的时间戳开头,我可以定义两个东西来识别我想要捕获的内容,一些部分内容和一个字符串将终止我想要提取的内容.

我的问题是多行,在大多数情况下,每个日志行都以换行符结束,但有些条目包含可能在其中包含新行的SQL,因此会在日志中创建新行.

所以,在一个简单的例子中,我可能会这样:

[8/21/13 11:30:33:557 PDT] 00000488 SystemOut     O 21 Aug 2013 11:30:33:557 [WARN] [MXServerUI01] [CID-UIASYNC-17464] BMXAA6720W - USER = (ABCDEF) SPID = (2526) app (ITEM) object (ITEM) : select * from item  where ((status != 'OBSOLETE' and itemsetid = 'ITEMSET1') and (exists (select 1 from maximo.invvendor where (exists (select 1 from maximo.companies where (( contains(name,'  $AAAA  ') > 0 )) and (company=invvendor.manufacturer and orgid=invvendor.orgid))) and (itemnum = item.itemnum and itemsetid = item.itemsetid)))) and (itemtype in (select value from synonymdomain where domainid='ITEMTYPE' and maxvalue = 'ITEM')) order by itemnum asc  (execution took 2083 milliseconds)
Run Code Online (Sandbox Code Playgroud)

这一切都显示为我可以匹配的一行:

re.compile('\[(0?[1-9]|[12][0-9]|3[01])(\/)(0?[1-9]|[12][0-9]|3[01])(\/)([0-9]{2}).*(milliseconds)')
Run Code Online (Sandbox Code Playgroud)

但是在某些情况下,SQL中可能存在换行符,因此我仍希望捕获它(并可能用空格替换换行符).我目前正在读取文件一行,这显然不会起作用,所以......

  1. 我是否需要一次处理整个文件?它们的大小通常为20mb.如何读取整个文件并遍历查找单行或多行块?
  2. 我如何编写一个多行RegEx,它可以匹配一行中的整个内容,也可以分布在多行中?

我的总体目标是对此进行参数化,以便我可以使用它来提取匹配起始字符串的不同模式(始终是行的开头),结束字符串(我想要捕获到的地方)的日志条目以及介于两者之间的值它们作为标识符.

在此先感谢您的帮助!

克里斯.

import sys, getopt, os, re

sourceFolder = 'C:/MaxLogs'
logFileName = sourceFolder + "/Test.log"
lines = []
print "--- START ----"
lineStartsWith = re.compile('\[(0?[1-9]|[12][0-9]|3[01])(\/)(0?[1-9]|[12][0-9]|3[01])(\/)([0-9]{2})(\ )')
lineContains = re.compile('.*BMXAA6720W.*')
lineEndsWith = re.compile('(?:.*milliseconds.*)')

lines = []
with open(logFileName, 'r') as f:
    for line in f:
        if lineStartsWith.match(line) and lineContains.match(line):
            if lineEndsWith.match(line) :
                print 'Full Line Found'
                print line
                print "- Record Separator -"
            else:
                print 'Partial Line Found'
                print line
                print "- Record Separator -"

print "--- DONE ----"
Run Code Online (Sandbox Code Playgroud)

下一步,对于我的部分行,我将继续阅读,直到找到lineEndsWith并将行汇编到一个块中.

我不是专家所以建议随时欢迎!

更新 - 所以我有它工作,感谢所有帮助指导事情的反应,我意识到它不漂亮我需要清理我的if/elif混乱并使其更有效但IT工作!谢谢你的帮助.

import sys, getopt, os, re

sourceFolder = 'C:/MaxLogs'
logFileName = sourceFolder + "/Test.log"

print "--- START ----"

lineStartsWith = re.compile('\[(0?[1-9]|[12][0-9]|3[01])(\/)(0?[1-9]|[12][0-9]|3[01])(\/)([0-9]{2})(\ )')
lineContains = re.compile('.*BMXAA6720W.*')
lineEndsWith = re.compile('(?:.*milliseconds.*)')

lines = []

multiLine = False

with open(logFileName, 'r') as f:
    for line in f:
        if lineStartsWith.match(line) and lineContains.match(line) and lineEndsWith.match(line):
            lines.append(line.replace("\n", " "))
        elif lineStartsWith.match(line) and lineContains.match(line) and not multiLine:
            #Found the start of a multi-line entry
            multiLineString = line
            multiLine = True
        elif multiLine and not lineEndsWith.match(line):
            multiLineString = multiLineString + line
        elif multiLine and lineEndsWith.match(line):
            multiLineString = multiLineString + line
            multiLineString = multiLineString.replace("\n", " ")
            lines.append(multiLineString)
            multiLine = False

for line in lines:
    print line
Run Code Online (Sandbox Code Playgroud)

aba*_*ert 3

\n

我需要一次性处理整个文件吗?它们的大小通常为 20mb。如何读取整个文件并迭代它以查找单行或多行块?

\n
\n\n

这里有两个选择。

\n\n

您可以逐块读取文件,确保将每个块末尾的任何“剩余”位附加到下一个块的开头,然后搜索每个块。当然,您必须通过查看您的数据格式是什么以及您的正则表达式可以匹配什么来找出什么算作“剩余”,理论上,多个块可能都算作剩余\xe2\x80\ xa6

\n\n

或者你也可以只使用mmap文件。mmap 的作用类似于字节(或类似于 Python 2.x 中的 str),并让操作系统根据需要处理调入和调出的分页块。除非您尝试处理绝对巨大的文件(32 位为千兆字节,64 位甚至更多),否则这是简单而高效的:

\n\n
with open(\'bigfile\', \'rb\') as f:\n    with mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) as m:\n        for match in compiled_re.finditer(m):\n            do_stuff(match)\n
Run Code Online (Sandbox Code Playgroud)\n\n

在旧版本的 Python 中,mmap它不是上下文管理器,因此您需要环绕contextlib.closing它(或者如果您愿意,可以直接使用显式close)。

\n\n
\n\n

我将如何编写一个多行正则表达式来匹配一行上的全部内容或分布在多行中?

\n\n

您可以使用该DOTALL标志,它使.匹配换行。您可以改为使用该MULTILINE标志并放入适当的$和/或^字符,但这会使简单的情况变得更加困难,而且很少有必要。这是一个示例DOTALL(使用更简单的正则表达式使其更加明显):

\n\n
>>> s1 = """[8/21/13 11:30:33:557 PDT] 00000488 SystemOut     O 21 Aug 2013 11:30:33:557 [WARN] [MXServerUI01] [CID-UIASYNC-17464] BMXAA6720W - USER = (ABCDEF) SPID = (2526) app (ITEM) object (ITEM) : select * from item  where ((status != \'OBSOLETE\' and itemsetid = \'ITEMSET1\') and (exists (select 1 from maximo.invvendor where (exists (select 1 from maximo.companies where (( contains(name,\'  $AAAA  \') > 0 )) and (company=invvendor.manufacturer and orgid=invvendor.orgid))) and (itemnum = item.itemnum and itemsetid = item.itemsetid)))) and (itemtype in (select value from synonymdomain where domainid=\'ITEMTYPE\' and maxvalue = \'ITEM\')) order by itemnum asc  (execution took 2083 milliseconds)"""\n>>> s2 = """[8/21/13 11:30:33:557 PDT] 00000488 SystemOut     O 21 Aug 2013 11:30:33:557 [WARN] [MXServerUI01] [CID-UIASYNC-17464] BMXAA6720W - USER = (ABCDEF) SPID = (2526) app (ITEM) object (ITEM) : select * from item  where ((status != \'OBSOLETE\' and itemsetid = \'ITEMSET1\') and \n    (exists (select 1 from maximo.invvendor where (exists (select 1 from maximo.companies where (( contains(name,\'  $AAAA  \') > 0 )) and (company=invvendor.manufacturer and orgid=invvendor.orgid))) and (itemnum = item.itemnum and itemsetid = item.itemsetid)))) and (itemtype in (select value from synonymdomain where domainid=\'ITEMTYPE\' and maxvalue = \'ITEM\')) order by itemnum asc  (execution took 2083 milliseconds)"""\n>>> r = re.compile(r\'\\[(.*?)\\].*?milliseconds\\)\', re.DOTALL)\n>>> r.findall(s1)\n[\'8/21/13 11:30:33:557 PDF\']\n>>> r.findall(s2)\n[\'8/21/13 11:30:33:557 PDF\']\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如您所看到的,第二个.*?与换行符匹配就像空格一样容易。

\n\n

如果您只是想将换行符视为空格,那么您也不需要;\'\\s\'已经捕捉到换行符了。

\n\n

例如:

\n\n
>>> s1 = \'abc def\\nghi\\n\'\n>>> s2 = \'abc\\ndef\\nghi\\n\'\n>>> r = re.compile(r\'abc\\s+def\')\n>>> r.findall(s1)\n[\'abc def\']\n>>> r.findall(s2)\n[\'abc\\ndef\']\n
Run Code Online (Sandbox Code Playgroud)\n