python 正则表达式匹配搜索字符串的每个索引不止一次
python regex match more than once per index of search string
我正在寻找一种方法来使 python re 模块或更新的 regex 模块的 finditer 函数匹配特定模式的所有可能变化,重叠或其他。我知道在不使用搜索字符串的情况下使用前瞻来获得匹配项,但我仍然只为每个索引获取一个正则表达式,而我可以获得多个。
我使用的正则表达式是这样的:
(?=A{2}[BA]{1,6}A{2})
所以在字符串中:
AABAABBAA
应该可以匹配:
AABAA
AABAABBAA
AABBAA
但目前它只会匹配其中的最后两个。我意识到这与 [BA]{1,6}
的贪婪有关。有没有办法让正则表达式匹配从最懒惰到最贪婪的所有可能模式?
这个正则表达式正确匹配了 3 个字符串:
AABAA AABAABBAA AABBAA
((^(AA){1}(BAA)$){1})|(((AA){1}(BB){1}(AA){1}$){1})
如果你想用 python 在字符串 "AABAABBAA" 中搜索这些子字符串,你可以使用方法 "search" :
re.search('AABAABB','AABAABBAA')
re.search('AABAABBAA','AABAABBAA')
re.search('AABBAA','AABAABBAA')
您将无法使用 finditer()
或任何正常的匹配导航方式。我管理它的唯一方法(在 Java,而不是 Python 中)是手动迭代源字符串的每个唯一子字符串(由起始位置和长度确定),将正则表达式应用于每个子字符串以正常方式(不使用环顾四周),并固定在两端。
Java 的匹配器 class 通过其 region()
方法提供了一种方便的方法。它使您可以假装源的任何子字符串实际上是整个内容,而不必生成大量新的 String 对象。 matches()
方法会自动在两端锚定匹配项,因此您根本不必修改正则表达式。
我很确定 Python 的 re
模块不支持这样的功能,但是另一个模块中可能有一些东西可以用来达到类似的效果(我是不流利 Python,所以这只是乐观)。我对 regex
模块更不熟悉,但它似乎支持所有其他风格的所有最甜蜜的功能,所以值得一看。
这是我的 Java 解决方案,如果您感兴趣的话:
public static void printAllMatches(String text, String regex)
{
System.out.printf("%s results:%n", text);
Matcher m = Pattern.compile(regex).matcher(text);
int end = text.length();
for (int i = 0; i < end; ++i)
{
for (int j = i + 1; j <= end; ++j)
{
m.region(i, j);
if (m.matches())
{
for (int k = 0; k < i; k++)
{
System.out.print(" ");
}
System.out.println(m.group());
}
}
}
}
输出:
AABAABBAA results:
AABAA
AABAABBAA
AABBAA
I realise it is to do with the greediness of the [BA]{1,6}. Is there a way to make the regex match everything from the laziest to the greediest possible pattern?
问题是双重的。
1. Regex engines will only match once at a character position.
2. There is not a regex construct of between lazy and greedy
it's either one or the other.
暂时跳过问题 1..,
问题2:
可能存在 {1,6}
1,2,3,4,5 或 6 个匹配
的情况
在给定位置的构造(字符)。
要解决该问题,您必须指定独立的 {1}、{2}、{3}、{4}、{5}、{6}
作为该位置的可选交替。
显然 range {1,6}
是行不通的。
就一个Range而言,可以指定找到
通过添加惰性修饰符的最小数量 {1,6}?
但这只会找到它能找到的最小数量,不多也不少。
最后,
问题 1:
当正则表达式引擎匹配时,它总是将当前位置向前推进
数量等于最后一场比赛的长度。
在匹配零长度断言的情况下,人为增加
向前一个字符的位置。
所以,鉴于这两个问题,可以用这些strengths/weaknesses来
想出一个解决方法,并且不得不忍受一些副作用。
解决方法:
将所有可能的选择放在一个位置作为要分析的断言。
一个位置的每个匹配项都将包含一个包含变体的组列表。
因此,如果您匹配了 6 个可能变体组中的 3 个变体,则具有值的组将是变体。
如果 none 个组有值,则在该位置未找到变体。
不会发生任何变体,因为 所有 断言都是可选的。
为了避免在这些特定位置进行不必要的匹配,final
条件 可用于不报告这些。 (即 (?(1)|(?(2)|(?!)))
等等)。
让我们以您的范围为例。
我们将在最后使用条件来验证匹配的组,
但没有它也可以完成。
_请注意,使用此 range 示例会导致与 identical
重叠
在最后一场比赛中的价值。这不确保在
处的唯一匹配
一个位置(下面的示例显示了如何避免这种情况)。
# (?=(A{2}[BA]{1,6}?A{2}))?(?=(A{2}[BA]{1,6}A{2}))?(?(1)|(?(2)|(?!)))
(?=
( # (1 start)
A{2}
[BA]{1,6}?
A{2}
) # (1 end)
)?
(?=
( # (2 start)
A{2}
[BA]{1,6}
A{2}
) # (2 end)
)?
(?(1)
| (?(2)
| (?!)
)
)
输出:
** Grp 1 - ( pos 0 , len 5 )
AABAA
** Grp 2 - ( pos 0 , len 9 )
AABAABBAA
-------------
** Grp 1 - ( pos 3 , len 6 )
AABBAA
** Grp 2 - ( pos 3 , len 6 )
AABBAA
相同,但没有 范围 问题。
在这里,我们明确定义了独特的结构。
记下每个位置的唯一值。
# (?=(A{2}[BA]{1}A{2}))?(?=(A{2}[BA]{2}A{2}))?(?=(A{2}[BA]{3}A{2}))?(?=(A{2}[BA]{4}A{2}))?(?=(A{2}[BA]{5}A{2}))?(?=(A{2}[BA]{6}A{2}))?(?(1)|(?(2)|(?(3)|(?(4)|(?(5)|(?(6)|(?!)))))))
(?=
( # (1 start)
A{2}
[BA]{1}
A{2}
) # (1 end)
)?
(?=
( # (2 start)
A{2}
[BA]{2}
A{2}
) # (2 end)
)?
(?=
( # (3 start)
A{2}
[BA]{3}
A{2}
) # (3 end)
)?
(?=
( # (4 start)
A{2}
[BA]{4}
A{2}
) # (4 end)
)?
(?=
( # (5 start)
A{2}
[BA]{5}
A{2}
) # (5 end)
)?
(?=
( # (6 start)
A{2}
[BA]{6}
A{2}
) # (6 end)
)?
(?(1)|(?(2)|(?(3)|(?(4)|(?(5)|(?(6)|(?!)))))))
输出:
** Grp 1 - ( pos 0 , len 5 )
AABAA
** Grp 2 - NULL
** Grp 3 - NULL
** Grp 4 - NULL
** Grp 5 - ( pos 0 , len 9 )
AABAABBAA
** Grp 6 - NULL
------------------
** Grp 1 - NULL
** Grp 2 - ( pos 3 , len 6 )
AABBAA
** Grp 3 - NULL
** Grp 4 - NULL
** Grp 5 - NULL
** Grp 6 - NULL
最后,你需要做的就是在每场比赛中,抓住捕获组
带有值,并将它们放入数组中。
我正在寻找一种方法来使 python re 模块或更新的 regex 模块的 finditer 函数匹配特定模式的所有可能变化,重叠或其他。我知道在不使用搜索字符串的情况下使用前瞻来获得匹配项,但我仍然只为每个索引获取一个正则表达式,而我可以获得多个。
我使用的正则表达式是这样的:
(?=A{2}[BA]{1,6}A{2})
所以在字符串中:
AABAABBAA
应该可以匹配:
AABAA
AABAABBAA
AABBAA
但目前它只会匹配其中的最后两个。我意识到这与 [BA]{1,6}
的贪婪有关。有没有办法让正则表达式匹配从最懒惰到最贪婪的所有可能模式?
这个正则表达式正确匹配了 3 个字符串:
AABAA AABAABBAA AABBAA
((^(AA){1}(BAA)$){1})|(((AA){1}(BB){1}(AA){1}$){1})
如果你想用 python 在字符串 "AABAABBAA" 中搜索这些子字符串,你可以使用方法 "search" :
re.search('AABAABB','AABAABBAA')
re.search('AABAABBAA','AABAABBAA')
re.search('AABBAA','AABAABBAA')
您将无法使用 finditer()
或任何正常的匹配导航方式。我管理它的唯一方法(在 Java,而不是 Python 中)是手动迭代源字符串的每个唯一子字符串(由起始位置和长度确定),将正则表达式应用于每个子字符串以正常方式(不使用环顾四周),并固定在两端。
Java 的匹配器 class 通过其 region()
方法提供了一种方便的方法。它使您可以假装源的任何子字符串实际上是整个内容,而不必生成大量新的 String 对象。 matches()
方法会自动在两端锚定匹配项,因此您根本不必修改正则表达式。
我很确定 Python 的 re
模块不支持这样的功能,但是另一个模块中可能有一些东西可以用来达到类似的效果(我是不流利 Python,所以这只是乐观)。我对 regex
模块更不熟悉,但它似乎支持所有其他风格的所有最甜蜜的功能,所以值得一看。
这是我的 Java 解决方案,如果您感兴趣的话:
public static void printAllMatches(String text, String regex)
{
System.out.printf("%s results:%n", text);
Matcher m = Pattern.compile(regex).matcher(text);
int end = text.length();
for (int i = 0; i < end; ++i)
{
for (int j = i + 1; j <= end; ++j)
{
m.region(i, j);
if (m.matches())
{
for (int k = 0; k < i; k++)
{
System.out.print(" ");
}
System.out.println(m.group());
}
}
}
}
输出:
AABAABBAA results:
AABAA
AABAABBAA
AABBAA
I realise it is to do with the greediness of the [BA]{1,6}. Is there a way to make the regex match everything from the laziest to the greediest possible pattern?
问题是双重的。
1. Regex engines will only match once at a character position.
2. There is not a regex construct of between lazy and greedy
it's either one or the other.
暂时跳过问题 1..,
问题2:
可能存在 {1,6}
1,2,3,4,5 或 6 个匹配
的情况
在给定位置的构造(字符)。
要解决该问题,您必须指定独立的 {1}、{2}、{3}、{4}、{5}、{6}
作为该位置的可选交替。
显然 range {1,6}
是行不通的。
就一个Range而言,可以指定找到
通过添加惰性修饰符的最小数量 {1,6}?
但这只会找到它能找到的最小数量,不多也不少。
最后,
问题 1:
当正则表达式引擎匹配时,它总是将当前位置向前推进
数量等于最后一场比赛的长度。
在匹配零长度断言的情况下,人为增加
向前一个字符的位置。
所以,鉴于这两个问题,可以用这些strengths/weaknesses来
想出一个解决方法,并且不得不忍受一些副作用。
解决方法:
将所有可能的选择放在一个位置作为要分析的断言。
一个位置的每个匹配项都将包含一个包含变体的组列表。
因此,如果您匹配了 6 个可能变体组中的 3 个变体,则具有值的组将是变体。
如果 none 个组有值,则在该位置未找到变体。
不会发生任何变体,因为 所有 断言都是可选的。
为了避免在这些特定位置进行不必要的匹配,final
条件 可用于不报告这些。 (即 (?(1)|(?(2)|(?!)))
等等)。
让我们以您的范围为例。
我们将在最后使用条件来验证匹配的组,
但没有它也可以完成。
_请注意,使用此 range 示例会导致与 identical
重叠
在最后一场比赛中的价值。这不确保在
处的唯一匹配
一个位置(下面的示例显示了如何避免这种情况)。
# (?=(A{2}[BA]{1,6}?A{2}))?(?=(A{2}[BA]{1,6}A{2}))?(?(1)|(?(2)|(?!)))
(?=
( # (1 start)
A{2}
[BA]{1,6}?
A{2}
) # (1 end)
)?
(?=
( # (2 start)
A{2}
[BA]{1,6}
A{2}
) # (2 end)
)?
(?(1)
| (?(2)
| (?!)
)
)
输出:
** Grp 1 - ( pos 0 , len 5 )
AABAA
** Grp 2 - ( pos 0 , len 9 )
AABAABBAA
-------------
** Grp 1 - ( pos 3 , len 6 )
AABBAA
** Grp 2 - ( pos 3 , len 6 )
AABBAA
相同,但没有 范围 问题。
在这里,我们明确定义了独特的结构。
记下每个位置的唯一值。
# (?=(A{2}[BA]{1}A{2}))?(?=(A{2}[BA]{2}A{2}))?(?=(A{2}[BA]{3}A{2}))?(?=(A{2}[BA]{4}A{2}))?(?=(A{2}[BA]{5}A{2}))?(?=(A{2}[BA]{6}A{2}))?(?(1)|(?(2)|(?(3)|(?(4)|(?(5)|(?(6)|(?!)))))))
(?=
( # (1 start)
A{2}
[BA]{1}
A{2}
) # (1 end)
)?
(?=
( # (2 start)
A{2}
[BA]{2}
A{2}
) # (2 end)
)?
(?=
( # (3 start)
A{2}
[BA]{3}
A{2}
) # (3 end)
)?
(?=
( # (4 start)
A{2}
[BA]{4}
A{2}
) # (4 end)
)?
(?=
( # (5 start)
A{2}
[BA]{5}
A{2}
) # (5 end)
)?
(?=
( # (6 start)
A{2}
[BA]{6}
A{2}
) # (6 end)
)?
(?(1)|(?(2)|(?(3)|(?(4)|(?(5)|(?(6)|(?!)))))))
输出:
** Grp 1 - ( pos 0 , len 5 )
AABAA
** Grp 2 - NULL
** Grp 3 - NULL
** Grp 4 - NULL
** Grp 5 - ( pos 0 , len 9 )
AABAABBAA
** Grp 6 - NULL
------------------
** Grp 1 - NULL
** Grp 2 - ( pos 3 , len 6 )
AABBAA
** Grp 3 - NULL
** Grp 4 - NULL
** Grp 5 - NULL
** Grp 6 - NULL
最后,你需要做的就是在每场比赛中,抓住捕获组
带有值,并将它们放入数组中。