【问题标题】:R regex lookbehind with a long expression带有长表达式的 R 正则表达式
【发布时间】:2020-02-24 00:38:16
【问题描述】:

我有一个来自 pdf 提取的长字符。下面是一个 MWE:

MWE <- "4 BLABLA\r\n Table 1. Real GDP\r\n Percentage changes\r\n 2016 2017 \r\nArgentina -2.5 2.7\r\nAustralia 2.6 2.5\r\n BLABLA \r\n Table 2. Nominal GDP\r\n Percentage changes\r\n 2011 2012\r\nArgentina 31.1 21.1\r\nAustralia 7.7 3.3\r\n"

我想把它分成一个列表,每个元素都是一个表格。 I can do that 与:

MWE_1 &lt;- as.list(strsplit(MWE, "(?&lt;=[Table\\s+\\d+\\.\\s+(([A-z]|[ \t]))+\\r\\n])"))

> MWE_1
[[1]]
[1] "4 BLABLA\r\n "                                                                                 
[2] " Percentage changes\r\n 2016 2017 \r\nArgentina -2.5 2.7\r\nAustralia 2.6 2.5\r\n BLABLA 5\r\n "
[3] " Percentage changes\r\n 2011 2012\r\nArgentina 31.1 21.1\r\nAustralia 7.7 3.3\r\n"         

但我想保留分隔符,这是一个非常长的正则表达式。 我看了一点,似乎一个不错的方法是尝试lookbehinds。但是,我不知道如何连接我的长正则表达式。例如,
MWE_2 &lt;- as.list(strsplit(MWE, "(?&lt;=[Table\\s+\\d+\\.\\s+(([A-z]|[ \t]))+\\r\\n])"))

产生错误:

invalid regular expression '(?<=[Table\s+\d+\.\s+(([A-z]|[  ]))+\r\n])', reason 'Invalid regexp'

如何以紧凑的方式做到这一点?

另外,有没有不保留第一个元素的直接方法?

【问题讨论】:

  • 你写 我可以用 : MWE_1 &lt;- … 做到这一点,但这与 MWE_2 &lt;- … 的表达方式完全相同,而且 会产生错误,所以你不能用这个表达式做任何事情,尤其是没有收到你为MWE_1显示的结果。
  • 感谢您的意见,但您尝试过吗?这实际上是我得到的(我添加了我得到的截图)。从给出的答案来看,我猜是在 R 中,后视和前瞻在其标准形式中没有被考虑在内,这就是为什么您需要指定 prel=TRUE 选项,然后使用 ?= 。我不清楚为什么它不适用于?&lt;=,但没有它我仍然可以做我想做的事。
  • 是的,我试过了。您在屏幕截图中显示的表达式(不是以(?&lt;=[ 开头)与您在问题文本中给出的表达式不同。

标签: r regex string split


【解决方案1】:

尝试前瞻并简化您正在寻找的内容:

提供了 R 特定的字符串转义。

(?=Table \\d+\\.)

确保启用perl=TRUE

https://regex101.com/r/Cpyu6k/1

【讨论】:

  • 要么我尝试 MWE_1 &lt;- as.list(strsplit(MWE, "(?=Table \d+\.)")) 并得到这个错误:Error: '\d' is an unrecognized escape in character string starting ""(?=Table \d" 要么尝试使用双 \\ 如MWE_1 &lt;- as.list(strsplit(MWE, "(?=Table \\d+\\.)"))` 并得到另一个错误@ 987654329@\d+\.)',原因'无效的正则表达式'`
  • @AnthonyMartin 抱歉,我不熟悉 R 语言。您应该始终根据您的环境规则转义字符串。根据您问题中的代码示例,(?=Table \\d+\\.) 应该可以工作。
  • @AnthonyMartin 这是 R 的在线正则表达式测试器,当根据我的最后评论转义反斜杠时,它似乎可以正常工作。 spannbaueradam.shinyapps.io/r_regex_tester
  • 不幸的是它仍然不起作用,我的问题与我在第一条评论中提到的第二个错误相同。它似乎也不适用于您提供的网站 - 或者我遗漏了一些明显的东西?
  • @AnthonyMartin 尝试根据stackoverflow.com/a/21493089/2191572启用perl=TRUE
【解决方案2】:

我不清楚为什么它不适用于?&lt;= ...

Regular Expressions as used in R 这么说(你有 重复量词 + 在模式中):

模式 (?&lt;=...)(?&lt;!...) 是后向模式 等价物:它们不允许重复量词,也不允许\C...


我仍然对这 5 个元素有疑问,而不是开始了解原因,

> MWE_2
[[1]]
[1] "4 BLABLA\r\n"
[2] " "
[3] "Table 1. Real GDP\r\n Percentage changes\r\n 2016 2017\r\nArgentina -2.5 2.7\r\nAustralia 2.6 2.5\r\n BLABLA \r\n"
[4] " "
[5] "Table 2. Nominal GDP\r\n Percentage changes\r\n 2011 2012\r\nArgentina 31.1 21.1\r\nAustralia 7.7 3.3\r\n"

但我可以在之后删除空元素……

索引 [2] 和 [4] 上没有 空元素 - 这些元素包含一个空格。这是因为strsplit(MWE, "(?= Table \\d+\\.)", perl=TRUE) 中的模式匹配长度为零的分隔符,因为它只包含一个零宽度的正向超前断言并且没有实际的分隔符项; strsplit 如果严格遵循其记录的算法,将进入无限循环

重复{
        如果字符串为空
            休息。
        如果有比赛
            将匹配左侧的字符串添加到输出。
            删除匹配项及其左侧的所有内容。
        别的
            将字符串添加到输出。
            休息。
    }
- 但在其代码中有这种特殊处理:
            /* Match was empty. */
            pt[0] = *bufp;
            pt[1] = '\0';
            bufp++;

这会导致返回 空匹配 位置的一个字符(在您的情况下为空格),并在其后继续搜索。

解决方案很简单:不要只使用零宽度断言作为模式;相反,通过将分隔空间移出断言来稍微改变它:

strsplit(MWE, " (?=Table \\d+\\.)", perl=TRUE)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 2021-09-12
    相关资源
    最近更新 更多