【问题标题】:Regex - remove sentences starting with certain words only if it is the last sentence正则表达式 - 仅当它是最后一个句子时才删除以某些单词开头的句子
【发布时间】:2021-12-13 19:38:12
【问题描述】:

根据标题,我正在尝试清理大量短文本,以删除以某些单词开头的句子——但前提是它是 >1 的 last 句子该文本。

假设我想删掉以“Jack is ...”开头的最后一句话
下面是一个不同情况的例子:

test_strings <- c("Jack is the tallest person.", 
                  "and Jack is the one who said, let there be fries.", 
                  "There are mirrors. And Jack is there to be suave.", 
                  "There are dogs. And jack is there to pat them. Very cool.", 
                  "Jack is your lumberjack. Jack, is super awesome.",
                  "Whereas Jack is, for the whole summer, sound asleep. Zzzz", 
                  "'Jack is so cool!' Jack is cool. Jack is also cold."
                  )

这是我目前拥有的正则表达式:"(?![A-Z'].+[\\.|'] )[Jj]ack,? is.+\\.$"

map_chr(test_strings, ~str_replace(.x, "(?![A-Z'].+[\\.|'] )[Jj]ack,? is.+\\.$", "[TRIM]"))

产生这些结果:

[1] "[TRIM]"                                                   
[2] "and [TRIM]"                                               
[3] "There are mirrors. And [TRIM]"                            
[4] "There are dogs. And [TRIM]"                               
[5] "Jack is your lumberjack. [TRIM]"                          
[6] "Whereas Jack is, for the whole summer, sound asleep. Zzzz"
[7] "'Jack is so cool!' Jack is cool. [TRIM]"  


## Basically my current regex is still too greedy. 
## No trimming should happen for the first 4 examples. 
## 5 - 7th examples are correct. 

## Explanations:
# (1) Wrong. Only one sentence; do not trim, but current regex trims it. 
# (2) Wrong. It is a sentence but does not start with 'Jack is'.
# (3) Wrong. Same situation as (2) -- the sentence starts with 'And' instead of 'Jack is'
# (4) Wrong. Same as (2) (3), but this time test with lowercase `jack`
# (5) Correct. Trim the second sentence as it is the last. Optional ',' removal is tested here.
# (6) Correct.
# (7) Correct. Sometimes texts do not begin with alphabets. 

感谢您的帮助!

【问题讨论】:

    标签: r regex stringr


    【解决方案1】:
    gsub("^(.*\\.)\\s*Jack,? is[^.]*\\.?$", "\\1 [TRIM]", test_strings, ignore.case = TRUE)
    # [1] "Jack is the tallest person."                              
    # [2] "and Jack is the one who said, let there be fries."        
    # [3] "There are mirrors. And Jack is there to be suave."        
    # [4] "There are dogs. And jack is there to pat them. Very cool."
    # [5] "Jack is your lumberjack. [TRIM]"                          
    # [6] "Whereas Jack is, for the whole summer, sound asleep. Zzzz"
    # [7] "'Jack is so cool!' Jack is cool. [TRIM]"                  
    

    分解:

    • ^(.*\\.)\\s*:因为我们需要在修剪之前至少有一个句子,所以我们需要找到前面的点\\.;
    • Jack,? is 来自您的正则表达式
    • [^.]*\\.?$:零个或多个“不是.-dots”,后跟.-dot 和字符串结尾;如果您想在最后一个句点之后允许空格,那么您可以将其更改为 [^.]*\\.?\\s*$,在您的示例中似乎没有必要

    【讨论】:

    • 谢谢,完美!只有两个问题:\\1 做什么,如何反转这个正则表达式以与 str_extract 一起使用来提取修剪后的句子?
    • \\1 是对模式中第一个 (...) 块的反向引用。请参阅stackoverflow.com/a/22944075/3358272 以获得良好的正则表达式(重新)更新。如果你的意思是提取Jack is ...这句话,那么str_extract(test_strings, "(?&lt;=[.])\\s*Jack,? is [^.]*\\.?$");如果您的意思是除此之外的提取,那么 str_replace 适合您,它在功能上等同于 gsub(尽管使用 this 测试,5x slower)。
    【解决方案2】:

    您可以匹配一个点(或使用字符类 [.!?] 匹配更多字符,然后匹配包含 Jack 并以点结尾的最后一个句子(或再次匹配更多字符的字符类):

    \.\K\h*[Jj]ack,? is[^.\n]*\.$
    

    模式匹配:

    • \.\K 匹配 . 并忘记到目前为止匹配的内容
    • \h*[Jj]ack,? is 匹配可选的水平空白字符,然后是 Jack 或 jack,以及可选的逗号和 is
    • [^.\n]*\. 可以选择匹配除 . 或换行符以外的任何字符
    • $字符串结束

    Regex demo | R demo

    示例代码:

    test_strings <- c("Jack is the tallest person.", 
                      "and Jack is the one who said, let there be fries.", 
                      "There are mirrors. And Jack is there to be suave.", 
                      "There are dogs. And jack is there to pat them. Very cool.", 
                      "Jack is your lumberjack. Jack, is super awesome.",
                      "Whereas Jack is, for the whole summer, sound asleep. Zzzz", 
                      "'Jack is so cool!' Jack is cool. Jack is also cold."
                      )
    
    sub("\\.\\K\\h*[Jj]ack,? is[^.\\n]*\\.$", " [TRIM]", test_strings, perl=TRUE)
    

    输出

    [1] "Jack is the tallest person."                              
    [2] "and Jack is the one who said, let there be fries."        
    [3] "There are mirrors. And Jack is there to be suave."        
    [4] "There are dogs. And jack is there to pat them. Very cool."
    [5] "Jack is your lumberjack. [TRIM]"                          
    [6] "Whereas Jack is, for the whole summer, sound asleep. Zzzz"
    [7] "'Jack is so cool!' Jack is cool. [TRIM]"
    

    【讨论】:

    • 副手,您知道使用.\K 与(?&lt;=.) 的后视功能是否存在差异?
    • @r2evans 最终他们会得到相同的结果,见regex101.com/r/W4mS5i/1 和regex101.com/r/4hGn7m/1 但不同的是,当使用lookbehind 时,lookbehind 在每一步都会触发,直到它断言一个 .向左。
    • 我已经验证它产生了相同的结果,现在看到它(至少在 R 中使用replicate(1000,test_strings))几乎是运行时间的 1/3。非常有趣,我不知道。谢谢!
    猜你喜欢
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    相关资源
    最近更新 更多