从这个被关闭的问题开始,op询问如何从字符串中提取排名,第一,中间和最后一个
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"
Run Code Online (Sandbox Code Playgroud)
我想出了这个,只有当中间名包含一个句号时才有效; 否则,排名模式会从行首开始捕获.
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"
Run Code Online (Sandbox Code Playgroud)
因此,如果中间名未给出或包含一段时间,这将起作用
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))
Run Code Online (Sandbox Code Playgroud)
所以我的问题是有没有办法从字符串的结尾优先匹配,这样这个模式匹配last,middle,first,然后把所有其他东西留给rank.
我可以这样做而不会扭转字符串或像这样的hacky?此外,也许有一个更好的模式,因为我不是很好的正则表达式.
相关 - [1] [2] - 我认为这些不会起作用,因为建议采用另一种模式而不是回答这个问题.此外,在该示例中,等级中的单词的数量是任意的,并且匹配等级的模式也适用于第一名称.
我们无法从末尾开始匹配,在我所知道的任何正则表达式系统中都没有任何修饰符。但我们可以检查一下到最后为止我们还有多少字,并克制我们的贪婪:)。下面的正则表达式正在执行此操作。
^(?<rank>(?:(?:[ \t]|^)[a-z]+)+?)(?!(?:[ \t][a-z.]+){4,}$)[ \t](?<first>[a-z]+)[ \t](?:(?<middle>[a-z.]+)[ \t])?(?<last>[a-z]+)$
Run Code Online (Sandbox Code Playgroud)
当您的排名有名字、姓氏和超过 1 个单词时,排名部分将成为名字。
为了解决这个问题,你必须定义一个排名前缀列表,这意味着肯定有另一个单词在它后面并以贪婪的方式捕获它。
例如:副,高级。