【问题标题】:Matching any character and or undefined newlines with regex in python在python中使用正则表达式匹配任何字符和/或未定义的换行符
【发布时间】:2020-02-20 23:50:18
【问题描述】:

我必须在 python 中使用正则表达式解析一个日志 txt 文件。这是一个txt的示例(名为file):

20/01/18, 08:11 - 彼得:早上好

你好吗?

Peter 20/01/18, 09:00 - Caroline:我很好,谢谢。你呢?

20/01/18,09:01 - 彼得:很好

几天前我遇到了一些问题。

现在我很开心

你在工作吗?

20/01/18, 09:02 - Caroline:不,我得去超市买 蔬菜

20/01/18,09:12 - 彼得:太好了!

你现在在哪里?

我试图用这个正则表达式解析整个文本:

f = open(file, 'r', encoding='utf-8')
texts=re.findall('(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)',f.read())
f.close()

df= pd.DataFrame(texts,columns=['data','name','text'])

但是,在 python 中匹配一个或多个换行符时我遇到了问题(例如 Peter 在 09:01 的文本)。我也尝试在https://regex101.com/ 上工作以找到可能的解决方案,但我没有成功。

你能帮帮我吗?

【问题讨论】:

  • 你是这个意思吗? regex101.com/r/qLibiH/1
  • 顺便说一句,Peter 20/01/18, 09:00 - Caroline: I am fine thanks. You? 行似乎是输入数据中的错字。

标签: python regex findall logfile-analysis


【解决方案1】:

如果您想匹配以下文本直到新行开头的下一个日期,您可以使用负前瞻匹配所有不以类似日期模式开始的行:

(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*(?:\r?\n(?!\d+/\d+/\d).*)*)

关于最后一部分(.*(?:\r?\n(?!\d+/\d+/\d).*)*)

  • (捕获组3
    • .* 匹配除换行符以外的任何字符 0+ 次
    • (?:非捕获组
      • \r?\n匹配新行
      • (?!\d+/\d+/\d).*断言右边的不是日期格式
    • )*关闭非捕获组并重复0+次
  • )关闭群组

Regex demo

【讨论】:

    【解决方案2】:

    默认情况下,. 不会匹配换行符。您需要 use DOTALL mode 使其匹配换行符:

    re.findall('(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)', f.read(), re.DOTALL)
    

    有效:

    >>> import re
    >>> s="""
    ... 20/01/18, 09:01 - Peter: Good
    ... 
    ... I had some problems few days ago.
    ... 
    ... Now I am happy
    ... 
    ... Are you working?"""
    >>> re.findall('(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)', s, re.DOTALL)
    [('20/01/18, 09:01', 'Peter', 'Good\n\nI had some problems few days ago.\n\nNow I am happy\n\nAre you working?')]
    >>> _
    

    但这并不能解决匹配整个文本其余部分的问题!

    查看@the-fourth-bird 的答案以获得真正的解决方案。

    另一个。更明确的处理方法是逐行读取文件,并检查一行是否是续行。

    rx = re.compile('^(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)$') # Note the ^.
    texts = []
    for line in input_file:  # Files iterate line by line.
      new_match = rx.match(line)
      if new_match:
        texts.append(list(new_match.groups()))  # We want a list
      else:
        # We have a continuation line; append it to the last item of group.
        last = texts[-1]
        last[-1] += line  # Update in-place.
    

    这可能更容易推理。

    【讨论】:

    • re.MULTILINE. 执行nothing,它只会改变^$ 锚点的含义。你的意思是re.DOTALL
    猜你喜欢
    • 2015-10-05
    • 2012-01-08
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 2012-08-22
    相关资源
    最近更新 更多