【问题标题】:Regular expression finditer: search twice on the same symbols正则表达式查找器:在相同的符号上搜索两次
【发布时间】:2016-08-12 11:16:57
【问题描述】:

我需要在文本中找到匹配项并获取其位置。例如,我必须在文本中找到“hello hello”。当文本是“hello hello world hello hello”时,没关系,我得到的位置是 0-11 和 18-29。但是当文本是“hello hello hello world”时,我只得到一个位置 - 0-11。但我必须找到两个(0-11 和 6-17)。我的意思是,我明白了

  1. 你好你好你好世界

但必须得到

  1. 你好你好你好世界

  2. 你好你好你好世界

在另一种情况下,我必须找到复杂的模式:“hello 1,2 beautiful 2,4 world”——这意味着“hello”和“beautiful”这两个词之间可能是一两个词,而两个词之间是“美丽”和“世界”2、3或4个字。我必须找到所有的组合。

这是模式:re.compile(u'(^|[\[\]\/\\\^\$\.\|\?\*\+\(\)\{\} !<>:;,#@])(hello)(([\[\]\/\\^\$\.\|\?\*\+\(\)\{\} !<>:;,#@%]+[a-zA-Zа-яА-Я$]+(-[a-zA-Zа-яА-Я$]+)*){1,2}[\[\]\/\\^\$\.\|\?\*\+\(\)\{\} !<>:;,#@%]*)(beautiful)(([\[\]\/\\^\$\.\|\?\*\+\(\)\{\} !<>:;,#@%]+[a-zA-Zа-яА-Я$]+(-[a-zA-Zа-яА-Я$]+)*){2,4}[\[\]\/\\^\$\.\|\?\*\+\(\)\{\} !<>:;,#@%]*)(world)($|[\[\]\/\\\^\$\.\|\?\*\+\(\)\{\} !<>:;,#@])')

而文字是“你好非常美丽美丽非常大的世界世界”。我可以得到唯一的一个组合,但需要得到 4 个:

  1. 你好非常美丽美丽非常大世界世界

  2. 你好非常美丽美丽非常大世界世界

  3. 你好非常美丽美丽非常大的世界世界

  4. 你好非常美丽美丽世界很大世界

当匹配项相互交叉时,如何获取匹配项的所有组合?

标志 re.DOTALL 没有帮助。

import re

patterns = [
    u'(hello)(( [a-z]+ *){1,2})(beautiful)(( [a-z]+ *){2,4})(world)',
    u'hello hello'
]
text = u'hello hello hello world hello very beautiful beautiful very big world world'
for p in patterns:
    print p
    c = re.compile(p, flags=re.I+re.U)
    for m in c.finditer(text):
        print m.start(), m.end()

结果是

>>> (hello)(( [a-z]+ *){1,2})(beautiful)(( [a-z]+ *){2,4})(world)
>>> 24 69
(need 24 69 and 24 69 and 24 75 and 24 75 - because there are two positions of the word "beautiful")
>>> hello hello
>>> 0 11
(need 0 11 and 6 17)

模式的真实例子是:

u"выйдите на улицы", u"избавить.* от", u"смотрите смотрите", u"смеят.*"

还有距离:

имени 0,3 ленина

целых 0,5 лет.*

целых 0,5 лет.* 0,1 назад

UPD

变体u'(?=(hello hello)) 有助于在单词之间没有距离的模式。但是如何在有距离的模式中使用它,例如(hello) (?:[a-zA-Zа-яА-Я]+ ){1,2}(beautiful) (?:[a-zA-Zа-яА-Я]+ ){2,4}(world)

【问题讨论】:

  • IMO 如果您的正则表达式看起来像这样,那么您可能应该选择另一种模式,或者可能跳过通过正则表达式执行它。
  • 问题不在当前的正则表达式中。它可以更简单,但问题不会消失。
  • 如果模式不重要,请举一个 simplesmall 示例,这样冗长而不清楚的问题会围绕您的实际问题产生烟幕跨度>
  • Find Overlapping Matches的可能重复

标签: python regex


【解决方案1】:

您的问题仍然不清楚您想做什么,但我会尝试一下:

正则表达式查找重复而不消耗:

([a-zA-Zа-яА-Я]+)(?= (\1))

正则表达式查找 hello beautifulworld 之间有特定数量的单词:

(hello) (?:[a-zA-Zа-яА-Я]+ ){1,2}(beautiful) (?:[a-zA-Zа-яА-Я]+ ){2,4}(world)

最终更新

你想要做的事情并不容易在一次运行中完全在正则表达式中完成。

更简单的是循环并执行不同的正则表达式:

for i in range(1,3):
    for j in range(2,5):
        regStr='(hello) (?:\w+ ){' + str(i) + '}(beautiful) (?:\w+ ){' + str(j) +'}(world)'

然后使用

再次检查重复项
([a-zA-Zа-яА-Я]+)(?= (\1))

【讨论】:

  • 是的,它适用于这个例子(正如我之前写的,如果单词介于两者之间,我必须找到具有预定数量的单词)。但这并不能解决我的问题 - 它匹配的问题。
  • 如果我有文本“你好你好你好世界你好非常美丽美丽非常大世界世界”并且必须找到“你好{1或2个字}美丽{2、3或4个字}世界” ,我需要得到 4 个匹配项: 1. hello hello hello world hello very beautiful beautiful very big world world 2. hello hello hello world 你好非常美丽美丽非常大世界世界3.你好你好你好世界你好非常美丽美丽非常大的世界世界 4.你好你好你好世界你好非常美丽美丽非常大的世界世界
  • 添加了最终更新,当您已经拥有强大的编程工具 (python)
  • 我明白了。谢谢!在我的项目中,我通过将文本按标记拆分并尝试将具有合适数字的标记与正则表达式匹配来做到这一点。它工作得很好而且很稳定,但是如果可以使用正则表达式来做这样的事情,也许它会工作得更快。
【解决方案2】:

我认为您可以尝试下面的表达式而不是正则表达式,看起来不太好,但可能会解决您的问题:

表达式:

 [pos for pos, char in enumerate(string) if string[pos:].find(pattern) == 0]

它给出了字符串中模式位置的列表输出。

In [43]: string = "hello very beautiful beautiful very big world world"
In [44]: pattern='hello'
In [45]: [pos for pos, char in enumerate(string) if string[pos:].find(pattern) == 0]
Out[45]: [0]
In [46]: pattern='very'
In [47]: [pos for pos, char in enumerate(string) if string[pos:].find(pattern) == 0]
Out[47]: [6, 31]
In [48]: pattern='world'
In [49]: [pos for pos, char in enumerate(string) if string[pos:].find(pattern) == 0]
Out[49]: [40, 46]
In [50]: pattern='very big'
In [51]: [pos for pos, char in enumerate(string) if string[pos:].find(pattern) == 0]
Out[51]: [31]

希望这会有所帮助。

【讨论】:

  • 不幸的是它没有帮助。主要原因是我必须找到如何将模式应用于整个文本并获取所有出现位置的方法。
猜你喜欢
  • 2019-08-12
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 2013-06-29
  • 1970-01-01
  • 2016-09-12
  • 2021-11-29
  • 2020-03-08
相关资源
最近更新 更多