【问题标题】:Python - trying to capture the middle of a line, regex or splitPython - 试图捕获行的中间,正则表达式或拆分
【发布时间】:2013-05-10 21:23:10
【问题描述】:

我有一个包含一些姓名、电子邮件和其他内容的文本文件。我想捕获电子邮件地址。

我不知道这是拆分问题还是正则表达式问题。

以下是一些示例行:

[name]bill billy [email]bill.billy@hotmail.com [dob]01.01.81
[name]mark hilly [email]mark.hilly@hotmail.com [dob]02.11.80
[name]gill silly [email]gill.silly@hotmail.com [dob]03.12.79

我希望能够循环打印所有电子邮件地址。

谢谢。

【问题讨论】:

  • 获取电子邮件是您唯一想做的事情,还是可以想象您以后可能想对信息做更多的事情?如果是后者,我想你肯定想要 Blender 的答案。任何依赖普通split 来拆分字段的东西(就像这里的大多数答案一样)都不会适用于name;任何依赖splitting 围绕] 的东西都可能比正则表达式更复杂(尽管我很想被证明是错误的)。
  • 我想我以后可能想用这个名字使邮件更具体

标签: python regex split


【解决方案1】:

我会使用正则表达式:

import re

data = '''[name]bill billy [email]bill.billy@hotmail.com [dob]01.01.81
[name]mark hilly [email]mark.hilly@hotmail.com [dob]02.11.80
[name]gill silly [email]gill.silly@hotmail.com [dob]03.12.79'''

group_matcher = re.compile(r'\[(.*?)\]([^\[]+)')

for line in data.split('\n'):
    o = dict(group_matcher.findall(line))
    print o['email']
  • \[ 字面意思是 [
  • (.*?) 是一个非贪婪的捕获组。它“扩展”以捕获文本。
  • \] 字面意思是 ]
  • ( 是捕获组的开始。
  • [^\[] 匹配除 [ 之外的任何内容。
  • + 将最后一个模式重复任意次数。
  • ) 关闭捕获组。

【讨论】:

  • 是否有一些网站可以轻松描述 (r'[(.*?)]([^[]+)') 的工作原理,我想了解它,而不是简单地刻画它。但这很好!
  • @gjels:我不知道。请参阅我的编辑以获取简要说明。
  • @gjels:Python 的文档中有一个HOWTO,但它可能不是最适合初学者的教程;尝试为他人搜索。还可以获得一个正则表达式浏览器程序(每个平台都有数以千计的程序,加上一堆在线程序),这将帮助您玩转各种东西。只要确保你学习了 Python 语法——perl/PCRE 已经足够接近了,但是 grep、emacs 等则大不相同。
  • 我知道这已经晚了,但regex101.com 给出了很好的解释,并允许您测试您的正则表达式。
【解决方案2】:
for line in lines:
   print line.split("]")[2].split(" ")[0]

【讨论】:

  • @karthikr:我想你忘记了 '[name' 将是拆分中的第一个值。
  • @abarnert 他之前有一个不同的答案,我的评论是针对那个
【解决方案3】:

您可以将子字符串传递给split,而不仅仅是单个字符,所以:

email = line.partition('[email]')[-1].partition('[')[0].rstrip()

这比简单的split 解决方案有一个优势,它适用于值中可以包含空格的字段,以及具有不同顺序的行(即使它们将[email] 作为最后一个字段)等。

概括一下:

def get_field(line, field):
    return line.partition('[{}]'.format(field)][-1].partition('[')[0].rstrip()

但是,我认为它仍然比正则表达式解决方案更复杂。另外,它一次只能搜索一个字段,而不是一次搜索所有字段(不会使其变得更加复杂)。要获得两个字段,您最终将解析每行两次,如下所示:

for line in data.splitlines():
    print '''{} "babysat" Dan O'Brien on {}'''.format(get_field(line, 'name'), 
                                                      get_field(line, 'dob'))

(当然,我可能误解了DOB 字段。)

【讨论】:

    【解决方案4】:

    可以按空格分割,然后搜索以[email]开头的元素:

    line = '[name]bill billy [email]bill.billy@hotmail.com [dob]01.01.81'
    items = line.split()
    for item in items:
        if item.startswith('[email]'):
            print item.replace('[email]', '', 1)
    

    【讨论】:

      【解决方案5】:

      假设你有一个带行的文件。

      import re
      
      f = open("logfile", "r")
      data = f.read()
      
      for line in data.split("\n"):
          match=re.search("email\](?P<id>.*)\[dob", line)
          if match:
                   # either store or print the emails as you like
                   print match.group('id').strip(), "\n"
      

      就是这样(试试吧,对于上面的 python 3 n,记住 print 是一个函数,可以进行这些更改)!

      样本数据的输出:

      bill.billy@hotmail.com  
      
      mark.hilly@hotmail.com  
      
      gill.silly@hotmail.com  
      
      >>> 
      

      【讨论】:

      • 如果你只是匹配这样的固定字符串,那么使用正则表达式并没有真正的优势。将此与 Blender 的答案进行比较,它可以为您提供所有字段的名称和值,而不仅仅是您硬编码的任何一个,并且更加健壮(例如,重新排序列,以便 email 出现在 dob 之后之前的)。
      • 我认为这是一个需要解决的具体问题,而不是一般问题。泛化扩展了“范围”,而健壮性就是“根据范围进行调整”。
      • 如果您只是想解决特定问题,匹配固定文本字符串,正则表达式不会在简单拆分之上添加任何内容,它只会无缘无故地使其变慢且可读性降低。例如,与 JaniSOF 的解决方案进行比较。
      猜你喜欢
      • 1970-01-01
      • 2020-12-11
      • 2021-10-07
      • 1970-01-01
      • 1970-01-01
      • 2018-08-19
      • 2012-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多