2

我目前正在解析具有以下结构的日志文件:

1) 时间戳,前面是 # 字符,后面是 \n

2) 在该时间戳之后发生的任意 # 个事件,所有事件后跟 \n

3) 重复..

这是一个例子:

#100
04!
03!
02!
#1299
0L
0K
0J
0E
#1335
06!
0X#
0[#
b1010 Z$
b1x [$
...

请原谅看似神秘的值,它们是代表某些“事件”的编码。

注意:事件编码也可以使用 # 字符。

我想做的是计算在某个时间发生的事件的数量。

换句话说,在时间 100,发生了 3 个事件。

我正在尝试匹配两个时间戳之间的所有文本 - 并通过简单地计算匹配文本中包含的换行符数来计算事件数。

我正在使用 Python 的正则表达式引擎,并且正在使用以下表达式:

pattern = re.compile('(#[0-9]{2,}.*)(?!#[0-9]+)')

注意: {2,} 是因为我想要至少有两位数字的时间戳。

我匹配一个时间戳,继续匹配任何其他字符,直到达到另一个时间戳 - 结束匹配。

这返回的是:

#100
#1299
#1335

所以,我得到了时间戳——但没有任何事件数据——我真正关心的!

我认为这样做的原因是消极的后视是“贪婪的”——但我并不完全确定。

可能有一个完全不同的正则表达式可以让这变得更简单 - 接受任何建议!

任何帮助深表感谢!

-k

4

4 回答 4

2

我认为正则表达式不是这里工作的好工具。你可以只使用一个循环..

>>> import collections
>>> d = collections.defaultdict(list)
>>> with open('/tmp/spam.txt') as f:
...   t = 'initial'
...   for line in f:
...     if line.startswith('#'):
...       t = line.strip()
...     else:
...       d[t].append(line.strip())
... 
>>> for k,v in d.iteritems():
...   print k, len(v)
... 
#1299 4
#100 3
#1335 6
于 2012-09-17T01:43:07.280 回答
1

原因是点不匹配换行符,所以你的表达式只会匹配包含时间戳的行;比赛不会跨越多条线。您可以将“dotall”标志传递给,re.compile以便您的表达式将匹配多行。由于您说“事件编码”也可能包含一个#字符,因此您可能还想使用多行标志并^在开头锚定您的匹配项,以便它仅匹配#行首的 。

于 2012-09-17T01:23:32.010 回答
1

您可以逐行遍历数据并拥有一个仅存储与每个时间戳关联的事件数量的字典;不需要正则表达式。例如:

with open('exampleData') as example:
    eventCountsDict = {}
    currEvent = None
    for line in example:
        if line[0] == '#': # replace this line with more specific timestamp details if event encodings can start with a '#'
            eventCountsDict[line] = 0
            currEvent = line
        else:
            eventCountsDict[currEvent] += 1

print eventCountsDict

该代码为您的示例数据打印{'#1299\n': 4, '#1335\n': 5, '#100\n': 3}(不包括...)。

于 2012-09-17T01:24:24.940 回答
1

如果您坚持使用基于正则表达式的解决方案,我建议:

>>> pat = re.compile(r'(^#[0-9]{2,})\s*\n((?:[^#].*\n)*)', re.MULTILINE)
>>> for t, e in pat.findall(s):
...     print t, e.count('\n')
...
#100 3
#1299 4
#1335 6

解释:

(              
  ^            anchor to start of line in multiline mode
  #[0-9]{2,}   line starting with # followed by numbers
)
\s*            skip whitespace just in case (eg. Windows line separator)
\n             new line
(
  (?:          repeat non-capturing group inside capturing group to capture 
               all repetitions
    [^#].*\n   line not starting with #
  )*
)

您似乎误解了负前瞻的作用。紧随其后时.*,正则表达式引擎首先尝试使用尽可能多的字符,然后才检查前瞻模式。如果前瞻不匹配,它将逐个字符回溯,直到匹配为止。

但是,您可以将积极的前瞻与非贪婪的.*?. 在这里,.*?将使用字符,直到前瞻在行的开头看到 # 或整个字符串的结尾:

re.compile(r'(^#[0-9]{2,})\s*\n(.*?)(?=^#|\Z)', re.DOTALL | re.MULTILINE)
于 2012-09-20T12:11:37.850 回答