使用java正则表达式时如何避免捕获重叠模式?

时间:2016-03-31 15:01:18

标签: java regex

在下面的POS标记句子(以及类似的句子)中使用正则表达式来捕获只有两个单词的名词名词复合词(即\p{Alnum}+_NN[PS]? \p{Alnum}[PS]?)并避免捕获作为较大词的一部分的双字匹配短语。

I_PRP will_MD never_RB go_VB to_IN sun_NN devil_NN auto_NN again_RB but_CC my_PRP$ family_NN members_NNS will_MD ._.

我特别希望捕捉family_NN members_NN但不是sun_NN devil_NNdevil_NN auto_NN

目前我使用以下正则表达式并带有正向前瞻:

"(?=\\b([\\p{Alnum}]+)_(NN[SP]?)\\s([\\p{Alnum}]+)_(NN[SP]?)\\b)."

问题是除了family_NN members_NNS之外,它还会捕获sun_NN devil_NNdevil_NN auto_NN

1 个答案:

答案 0 :(得分:1)

你需要一个前瞻这里的后视镜。

基本上,对于某些模式P,您希望当且仅当PP之前或之后没有P时,(?<!P)PP(?!P) 才会匹配。

粗略的方式,前瞻和后视操作员:

(?<!...)

(?!...)...分别是正则表达式中的负向前瞻和负前瞻锚,其中P代表正则表达式。

如果我们将[\p{AlNum}]+_NN[PS]? 作为:

private static final String P = "[\\p{AlNum}]+_NN[PS]?";
private static final String RE = "(?<!" + P + ")"
    + "\\s+(" + P + "\\s+" + P + ")\\s+(?!" + P + ")";
private static final Pattern PATTERN = Pattern.compile(RE);

并考虑空格,然后一个解决方案的草图,允许每个标记之间的空格,看起来像:

reflect

然而,这只是一幅草图。

鉴于输入的复杂性,您可能想要做更多,所以不确定正则表达式是否是您最终寻找的工具。