【问题标题】:Start matching from the end of a string从字符串的末尾开始匹配
【发布时间】:2016-11-13 15:30:05
【问题描述】:

从关闭的this question,操作员询问如何从字符串中提取排名、第一、中间和最后

x <- c("Marshall Robert Forsyth", "Deputy Sheriff John A. Gooch",
       "Constable Darius Quimby", "High Sheriff John Caldwell Cook")

#                                  rank             first    middle      last     
# Marshall Robert Forsyth          "Marshall"       "Robert" ""          "Forsyth"
# Deputy Sheriff John A. Gooch     "Deputy Sheriff" "John"   "A."        "Gooch"  
# Constable Darius Quimby          "Constable"      "Darius" ""          "Quimby" 
# High Sheriff John Caldwell. Cook "High Sheriff"   "John"   "Caldwell"  "Cook"

我想出了这个只有在中间名包含句点的情况下才有效;否则,排名模式会从行首尽可能多地捕获。

pat <- '(?i)(?<rank>[a-z ]+)\\s(?<first>[a-z]+)\\s(?:(?<middle>[a-z.]+)\\s)?(?<last>[a-z]+)'

f <- function(x, pattern) {
  m <- gregexpr(pattern, x, perl = TRUE)[[1]]
  s <- attr(m, "capture.start")
  l <- attr(m, "capture.length")
  n <- attr(m, "capture.names")
  setNames(mapply('substr', x, s, s + l - 1L), n)
}

do.call('rbind', Map(f, x, pat))

#                                 rank                first      middle last     
# Marshall Robert Forsyth         "Marshall"          "Robert"   ""     "Forsyth"
# Deputy Sheriff John A. Gooch    "Deputy Sheriff"    "John"     "A."   "Gooch"  
# Constable Darius Quimby         "Constable"         "Darius"   ""     "Quimby" 
# High Sheriff John Caldwell Cook "High Sheriff John" "Caldwell" ""     "Cook"

因此,如果中间名没有给出或包含句点,这将起作用

x <- c("Marshall Robert Forsyth", "Deputy Sheriff John A. Gooch",
       "Constable Darius Quimby", "High Sheriff John Caldwell. Cook")
do.call('rbind', Map(f, x, pat))

所以我的问题是,有没有一种方法可以优先匹配字符串的 结尾,这样该模式会匹配最后、中间、第一,然后将其他所有内容留给排名。

我可以在不反转字符串或类似的东西的情况下做到这一点吗?另外,也许有更好的模式,因为我不擅长正则表达式。


相关 - [1] [2] - 我认为这些不会起作用,因为提出了另一种模式而不是回答问题。此外,在此示例中,排名中的单词数量是任意的,匹配排名的模式也适用于名字。

【问题讨论】:

  • this demo 是预期的结果吗? (perl=TRUE)
  • 好吧,我认为这仍然不适用于像Deputy Sheriff John Gooch 这样的 str ,如果有 4 个单词,如何区分。
  • 如果你需要这个,你需要一个标题列表
  • @bobblebubble 是的,这似乎可行,我从未使用过?|,所以您仍然需要定义可能的替代方案(例如,其他示例,这里只有两个)?并且没有全局标志从头开始并反向运行?在 r pat &lt;- '(?|(?&lt;rank&gt;\\w+) (?&lt;first&gt;\\w+)(?&lt;middle&gt;) (?&lt;last&gt;\\w+)$|(?&lt;rank&gt;[\\w ]+) (?&lt;first&gt;\\w+) (?&lt;middle&gt;[\\w.]+) (?&lt;last&gt;\\w+))'; do.call('rbind', Map(f, x, pat))
  • @rawr 这是一个branch reset,用替代品维护组索引。

标签: r regex


【解决方案1】:

我们不能从最后开始匹配,在我知道的任何正则表达式系统中都没有任何修饰符。但是我们可以检查直到最后我们有多少单词,并抑制我们的贪婪:)。下面的正则表达式正在这样做。

这个会做你想做的:

^(?<rank>(?:(?:[ \t]|^)[a-z]+)+?)(?!(?:[ \t][a-z.]+){4,}$)[ \t](?<first>[a-z]+)[ \t](?:(?<middle>[a-z.]+)[ \t])?(?<last>[a-z]+)$

Live preview in regex101.com

还有一个例外:

当您的排名有 First、Last 和超过 1 个单词时,排名部分将成为 First name。

要解决这个问题,您必须定义一个排名前缀列表,这意味着肯定有另一个词紧随其后并以贪婪的方式捕获它。

例如:副,高级。

【讨论】:

  • 还有一个想法:在任何语言中还有一个反向字符串函数,你可以将它与正则表达式结合并从“从头到尾”开始匹配,然后将你的匹配反向得到正常的单词。跨度>
【解决方案2】:

我的 R 生锈了,但是在我知道的所有正则表达式引擎中,在量词之后放置一个 ? 使它成为非贪婪而不是贪婪。所以回答你的主要问题:

有没有办法从字符串的末尾开始优先匹配,以便该模式匹配最后、中间、第一,然后将其他所有内容留给排名?

您应该能够通过在+ 之后添加? 使模式的排名匹配部分成为非贪婪模式来做到这一点。

(?<rank>[a-z ]+?)

完整模式:

pat <- '(?i)(?<rank>[a-z ]+?)\\s(?<first>[a-z]+)\\s(?:(?<middle>[a-z.]+)\\s)?(?<last>[a-z]+)'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-06
    • 1970-01-01
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多