python regex:捕获包含空格的多个字符串的部分

时间:2011-03-01 21:12:25

标签: python regex space repeat

我正在尝试从类似于

的字符串中捕获子字符串
'some string, another string, '

我希望结果匹配组为

('some string', 'another string')

我目前的解决方案

>>> from re import match
>>> match(2 * '(.*?), ', 'some string, another string, ').groups()
('some string', 'another string')

有效,但不切实际 - 我在这里展示的当然是复杂性与我在实际项目中所做的相比大大减少了;我想只使用一个'直的'(非计算)正则表达式模式。不幸的是,到目前为止我的尝试失败了:

这不匹配(结果为None),因为{2}仅应用于空间,而不是整个字符串:

>>> match('.*?, {2}', 'some string, another string, ')

在重复的字符串周围添加括号,结果中包含逗号和空格

>>> match('(.*?, ){2}', 'some string, another string, ').groups()
('another string, ',)

添加另一组parantheses确实解决了这个问题,但让我太过分了:

>>> match('((.*?), ){2}', 'some string, another string, ').groups()
('another string, ', 'another string')

添加非捕获修饰符会改善结果,但仍然会错过第一个字符串

>>> match('(?:(.*?), ){2}', 'some string, another string, ').groups()
('another string',)

我觉得我很亲近,但我似乎找不到合适的方式。

任何人都可以帮助我吗?我还没有看到任何其他方法吗?


在前几个回复后更新:

首先,非常感谢大家,非常感谢您的帮助! : - )

正如我在原帖中所说,为了描述实际的核心问题,我在我的问题中省略了很多复杂性。对于初学者来说,在我正在研究的项目中,我正在解析大量文件(目前每天数万个),这些文件在不同的基于行的格式的数字(目前为5,很快~25,可能在数百之后)中。还有XML,JSON,二进制和其他一些数据文件格式,但让我们保持专注。

为了应对多种文件格式并利用其中许多是基于行的事实,我创建了一个有点通用的Python模块,它将一个文件加载到另一个文件后,将regex应用于每一行返回带有匹配项的大型数据结构。这个模块是一个原型,生产版本需要一个C ++版本的性能原因,它将通过Boost :: Python连接,并可能将正则表达式方言的主题添加到复杂性列表中。

此外,没有2次重复,但是在当前零和70之间变化的数量(左右),逗号并不总是逗号,尽管我原先说的是,正则表达式的某些部分必须被计算在运行时;我只想说我有理由尝试减少“动态”数量并尽可能多地采用“固定”模式。

所以,总之:我必须使用正则表达式。


尝试重新措辞:我认为问题的核心归结为:是否存在Python RegEx表示法,例如:涉及花括号重复并允许我捕获

'some string, another string, '

('some string', 'another string')

嗯,这可能会把它缩小得太远 - 但是,你做的任何方式都是错的:-D


第二次尝试改写:为什么我在结果中看不到第一个字符串('some string')?为什么正则表达式产生匹配(表示必须有2个),但只返回1个字符串(第二个)?

即使我使用非数字重复,即使用+而不是{2},问题仍然存在:

>>> match('(?:(.*?), )+', 'some string, another string, ').groups()
('another string',)

此外,它不是返回的第二个字符串,它是最后一个字符串:

>>> match('(?:(.*?), )+', 'some string, another string, third string, ').groups()
('third string',)

再次感谢您的帮助,在尝试找出我真正想知道的内容时,永远不会让我惊讶于同行评审是多么有用......

6 个答案:

答案 0 :(得分:5)

除非你解释这个问题还有更多,否则我没有看到使用正则表达式的重点。使用基本字符串方法处理非常非常简单:

[s.strip() for s in mys.split(',') if s.strip()]

或者如果它必须是一个元组:

tuple(s.strip() for s in mys.split(',') if s.strip())

代码也更具可读性。请告诉我这是否适用。


编辑:好的,这个问题确实比最初看起来更多。但是出于历史目的而留下这个。 (猜猜我不是'纪律':))

答案 1 :(得分:4)

如上所述,我认为这个正则表达式工作正常:

import re
thepattern = re.compile("(.+?)(?:,|$)") # lazy non-empty match 
thepattern.findall("a, b, asdf, d")     # until comma or end of line
# Result:
Out[19]: ['a', ' b', ' asdf', ' d']

此处的关键是使用findall而不是match。您的问题的措辞表明您更喜欢match,但它不适合此处的工作 - 它旨在为每个相应的组( )返回一个字符串在正则表达式。由于您的“字符串数量”是可变的,因此正确的方法是使用findallsplit

如果这不是您所需要的,请提出更具体的问题。

编辑:如果您必须使用元组而不是列表:

tuple(Out[19])
# Result
Out[20]: ('a', ' b', ' asdf', ' d')

答案 2 :(得分:2)

import re

regex = " *((?:[^, ]| +[^, ])+) *, *((?:[^, ]| +[^, ])+) *, *"

print re.match(regex, 'some string, another string, ').groups()
# ('some string', 'another string')
print re.match(regex, ' some string, another string, ').groups()
# ('some string', 'another string')
print re.match(regex, ' some string , another string, ').groups()
# ('some string', 'another string')

答案 3 :(得分:1)

没有冒犯,但你显然有很多关于正则表达的知识,而你最终要学习的是正则表达式无法处理这项工作。我确定这个特定的任务对正则表达式是可行的,但那么呢?你说你有可能数百的不同文件格式要解析!您甚至提到了JSON和XML,它们与正则表达式根本不兼容。

帮自己一个忙:忘掉正则表达式并转而学习pyparsing。或者完全跳过Python并使用像ANTLR这样的独立解析器生成器。在任何一种情况下,您可能会发现大多数文件格式的语法都已编写过。

答案 4 :(得分:0)

  

我认为问题的核心在于沸腾   到:是否有Python RegEx   例如,涉及卷曲   支持重复并允许我   捕获'一些字符串,另一个字符串,   '?

我认为没有这样的符号。

但是正则表达式不仅仅是NOTATION的问题,也就是说用于定义正则表达式的RE字符串。这也是TOOLS的问题,即功能。

  

不幸的是,我不能将findall用作   来自最初问题的字符串   只是问题的一部分,   真正的字符串要长很多,所以   findall仅在我执行多个时才有效   正则表达式findalls / matches / searching。

你应该在不延迟的情况下提供更多信息:我们可以更快地理解什么是约束。因为在我看来,为了解决你所暴露的问题, findall()确实没问题:

import re

for line in ('string one, string two, ',
             'some string, another string, third string, ',
             # the following two lines are only one string
             'Topaz, Turquoise, Moss Agate, Obsidian, '
             'Tigers-Eye, Tourmaline, Lapis Lazuli, '):

    print re.findall('(.+?), *',line)

结果

['string one', 'string two']
['some string', 'another string', 'third string']
['Topaz', 'Turquoise', 'Moss Agate', 'Obsidian', 'Tigers-Eye', 'Tourmaline', 'Lapis Lazuli']

现在,由于您在问题中“省略了很多复杂性”, findall()可能无法保持这种复杂性。然后将使用 finditer(),因为它可以更灵活地选择匹配组

import re

for line in ('string one, string two, ',
             'some string, another string, third string, ',
             # the following two lines are only one string
             'Topaz, Turquoise, Moss Agate, Obsidian, '
             'Tigers-Eye, Tourmaline, Lapis Lazuli, '):

    print [ mat.group(1) for mat in re.finditer('(.+?), *',line) ]

给出了相同的结果,并且可以通过编写其他表达式代替 mat.group(1)

来进行复杂化

答案 5 :(得分:-1)

为了总结这一点,似乎我已经通过以“动态”方式构建正则表达式模式来使用最佳解决方案:

>>> from re import match
>>> match(2 * '(.*?), ', 'some string, another string, ').groups()
('some string', 'another string')

2 * '(.*?)

是我的意思是动态的。替代方法

>>> match('(?:(.*?), ){2}', 'some string, another string, ').groups()
('another string',)
由于(正如格伦和艾伦亲切地解释)

未能返回所需的结果

  

匹配时,捕获的内容会被覆盖   每次重复捕获   组

感谢大家的帮助! : - )