【问题标题】:regex: parse opening closing parenthesis with other parenthesis in between正则表达式:解析左括号与其他括号之间
【发布时间】:2015-12-30 04:01:34
【问题描述】:

我有一个带有句子解析的字符串,并且想要从包含在左括号和右括号中的字符串中提取/解析。问题是还有其他相同类型的括号(在这种情况下是括号)也需要抓取。所以基本上我需要与NP 关联的正确数量的左大括号等于相同数量的右大括号。

在这个例子中:

x <- "(TOP (S (NP (NNP Clifford)) (NP (DT the) (JJ big) (JJ red) (NN dog)) (VP (VBD ate) (NP (PRP$ my) (NN lunch)))(. .)))"

假设我想将名词短语 (NP) 提取到下面的三个子字符串中:

(NP (NNP Clifford))
(NP (DT the) (JJ big) (JJ red) (NN dog))
(NP (PRP$ my) (NN lunch))

这可以推广到字符串的所有部分,比如我想抓住VP 括号,我可以遵循相同的逻辑。

【问题讨论】:

  • 嵌套多深?
  • 我不相信你可以在另一个 NP 中拥有一个 NP。但理论上括号可以无限嵌套,但我猜测实际上有 2-3 层深。 VP示例是嵌套示例:(VP (VBD ate) (NP (PRP$ my) (NN lunch)))
  • 我删除了我的解决方案,因为它没有计算括号。但它是否解决了您面临的问题?
  • @PierreLafortune 我赞成您的解决方案。我不会删除它。
  • 如果有帮助的话。让我知道。另一个用户正确地指出,它没有按要求计算括号。但如果它解决了问题,您可能不必计算它们。

标签: regex r


【解决方案1】:

平衡括号is not regular的语言,所以不能和基本的正则表达式匹配。您可以使用递归正则表达式来执行此操作(参见 hwnd 的答案),但我不推荐它,因为语法变得相当难看。相反,使用更简单的正则表达式、变量和程序控制流构建解析器。像这样的:

for each character:
    if it's a (, increment the nesting depth.
    if it's a ), decrement the nesting depth.
    if the nesting depth is exactly zero, we've reached the end of this expression.

或者,使用像 openNLP 这样的库,它已经能够为您进行这种解析。

【讨论】:

  • 您能否展示我如何使用openNLP 自动提取这些短语。不知何故,括号的平衡必须是可解析的,就好像我的 R 脚本中没有足够的大括号它知道并期望一个右大括号一样。知道什么时候没有右大括号的语法荧光笔也必须执行此任务。
  • @TylerRinker:完全可以解析。 使用正则表达式是不可能(合理地)这样做的。 openNLP has code for producing these parse trees in the first placemanipulating them,但我找不到 R 绑定的文档。不过,它们可能与 Java 接口非常相似。
  • 是的,我喜欢 Python 解析,并希望在 R 中获得这种能力。
【解决方案2】:

您可以使用 Avinash Raj 的新包:

library(dangas)
extract_all_a("(NP", "))", x, delim=TRUE)
[[1]]
[1] "(NP (NNP Clifford))"                     
[2] "(NP (DT the) (JJ big) (JJ red) (NN dog))"
[3] "(NP (PRP$ my) (NN lunch))"

Github 链接Here。安装使用:devtools::install_github("Avinash-Raj/dangas/dangas")


如果下载有问题,请尝试:

library(stringr)
str_extract_all(x, "\\(NP.*?\\)\\)")

更新

@Kevin 正确地告诉我我忽略了平衡括号请求。但是正如您在 cmets 中提到的,您可能不需要它来解决您的问题。如果有帮助请反馈,如果没有,我会删除。

【讨论】:

  • 这会捕获不以)) 结尾的表达式吗?它是否正确拒绝以)) 结尾但不平衡的表达式?
  • 测试一下。 @凯文。它匹配从第一个参数到第二个参数的范围。 delim=TRUE 指示它在匹配中包含参数。
  • 这不是 OP 要求的。他们想要平衡括号。
  • 它并不能安静地解决问题(正如 Kevin 指出的那样),但它可能对未来的用户很有用。 +1
【解决方案3】:

我不确定子字符串是否总是被定义,但在这种情况下你可以这样做:

regmatches(x, 
    gregexpr('(?x)
              (?=\\(NP)           # assert that subpattern precedes
                (                 # start of group 1
                \\(               # match open parenthesis
                    (?:           # start grouping construct
                        [^()]++   # one or more non-parenthesis (possessive)
                          |       # OR
                        (?1)      # found ( or ), recurse 1st subpattern
                    )*            # end grouping construct
                \\)               # match closing parenthesis
                )                 # end of group 1
             ', x, perl=TRUE))[[1]]

# [1] "(NP (NNP Clifford))"                     
# [2] "(NP (DT the) (JJ big) (JJ red) (NN dog))"
# [3] "(NP (PRP$ my) (NN lunch))"  

【讨论】:

  • 我知道如果可以做到你会想办法:-)
  • PS 我喜欢使用(?x) 来允许评论+1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-18
  • 1970-01-01
  • 2013-05-04
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多