Python:使用正则表达式捕获模式中的子模式

时间:2018-03-06 13:33:27

标签: python regex

免责声明:这是我的第一篇文章。随意给我反馈,以及我应该或不应该如何格式化这个问题。谢谢!

我希望通过捕获匹配日期格式后跟冒号的模式来从文本块中提取数据。我已成功使用正则表达式来捕获信息,包括观察日期,冒号以及下一个日期之前的任何文本。

例如:
1999-01-01:观察到10只鸟。

我遇到的问题是我的一些数据包含站点名称,后面跟着观察日期和第一个冒号之后的观察数据中的冒号。这个子模式的名称:数据'在观察日期之后的区块内可能会发生零次或多次。

例如:
1999-01-01:BS-001:观察到5只鸟。一切都很健康。 BS-002:观察到5只鸟,其中一些健康状况不佳。

我应该使用什么模式捕获日期格式和冒号后面的所有文本,包括潜在的网站名称,冒号和相关数据,直到下一个观察日期之前?

我目前使用以下模式按日期和观察提取简单观察数据(其中没有多个网站):

pattern = re.compile(r'(\d\d\d\d\-*\s*\&*\d+\-*\d*:[A-Za-z0-9\s\,\(\)\;\"\-]*\.*)')  

上面的代码让我可以提取各种形式的观察日期。使用句点作为模式的一部分是棘手的,因为观察数据可能是一个或多个句子。

以下是我尝试搜索和拆分的文字示例。每个新匹配应以观察日期开始,因此在下面的数据中应返回3个匹配项(2013-04-13:数据,2017-01-01:数据和2018-07-04:数据):

  

2013-04-13:BS-440:在春季池塘栖息地观察到10个卵块。   观察者注意到,AMJE群体中有3个有坚固的果冻,类似于3周龄   AMMA质量,但"更多"在外面(膜和胚胎间距)   群众是AMJE般的)。 BS-443:在春季观察到3个卵块   游泳池栖息地。由于光线不足,可能遗漏了一些蛋块   条件。 Smith-019:在春季池塘栖息地观察到250个卵块。   观察者仅搜索邻接道路的部分(游泳池的SW边缘)。   观察到许多AMJE群体附着于草本植被和草本植物   很难区分彼此。 AMJE鸡蛋计数是一个   搜索范围内的粗略估计。 2017-01-01:23个人   观测到的。卵块不存在。 2018-07-04:BS-440:全部   个人在长假周末休养了一段时间。

理想情况下,输出看起来像这样:

  

2013-04-13:BS-440:在春季池塘栖息地观察到10个卵块。   观察者注意到,AMJE群体中有3个有坚固的果冻,类似于3周龄   AMMA质量,但"更多"在外面(膜和胚胎间距)   群众是AMJE般的)。 BS-443:在春季观察到3个卵块   游泳池栖息地。由于光线不足,可能遗漏了一些蛋块   条件。 Smith-019:在春季池塘栖息地观察到250个卵块。   观察者仅搜索邻接道路的部分(游泳池的SW边缘)。   观察到许多AMJE群体附着于草本植被和草本植物   很难区分彼此。 AMJE鸡蛋计数是一个   搜索范围内的粗略估计。

     2017-01-01:观察到23个人。鸡蛋块不存在。

     

2018-07-04:BS-440:所有人都为繁殖而休息   长假周末。

4 个答案:

答案 0 :(得分:2)

您可以尝试替换所有空格,然后使用两个换行符替换日期:

s = re.sub(r'\s+(?=\d{4}-*\s*&*\d+-*\d*:)', "\n\n", s)

这样您就不会匹配字符串开头的第一个日期。

如果您不确定每个日期前面都有空格,您也可以这样写:

s = re.sub(r'\s*(?!^)(?=\d{4}-*\s*&*\d+-*\d*:)', "\n\n", s)

答案 1 :(得分:2)

基本上,您可能希望将文本分成以日期开头并在日期或文本结尾之前结束的字段。这是一种可能性:

\d{4}-\d\d-\d\d:           # date with colon
.*?                        # the minimal amount of any characters required to match
(?=                        # positive lookahead (match text but don't consume it)
   \d{4}-\d\d-\d\d:        # date with colon
  |                        # or
   $                       # end of text
)                          # end lookahead

re.findall()

一起使用
findall(r'\d{4}-\d\d-\d\d:.*?(?=\d{4}-\d\d-\d\d:|$)', mytext)

针对上面的示例文字运行:

['2013-04-13: BS-440: 10 egg masses observed in vernal pool habitat.
  Observer noted 3 of the AMJE masses had firm jelly, akin to a 3-wk
  old AMMA mass, but "bumpier" on outside (membrane and embryo-spacing
  in the masses were AMJE-like). BS-443: 3 egg masses observed in
  vernal pool habitat. A few egg masses may have been missed due to
  poor light conditions. Smith-019: 250 egg masses observed in
  vernal pool habitat. Observer searched only portions abutting the 
  road (SW margin of pool). Many AMJE masses observed attached
  to herbaceous vegetation and difficult to differentiate from
  one another. AMJE egg-mass count is a rough estimate within
  area searched. ',
 '2017-01-01: 23 individuals observed. Egg masses were not present. ',
 '2018-07-04: BS-440: All individuals took a break from breeding for
  the long holiday weekend.']

答案 2 :(得分:2)

您可以使用split()和正则表达式(?=\d{4}-\d{2}-\d{2})

output = re.compile(" (?=\d{4}-\d{2}-\d{2})").split(text)

Code demo

答案 3 :(得分:1)

您可以使用pattern.split

pattern = re.compile(r'(\d{4}-\d{2}-\d{2})')
parts = pattern.split(string)

这会产生

['', '2013-04-13', ': BS-440: 10 egg masses observed...', ...]

如果pattern包含捕获括号,则其内容将与输入字符串的拆分部分交错。因为字符串的开头与日期匹配,所以第一部分为空。所以''.join(parts[1:3])产生第一个条目,依此类推。