Comece a correspondência do final de uma string

9

De esta questão que foi encerrada, o op perguntou como extrair rank, first, middle e last das strings

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"

Eu inventei isso, que só funciona se o nome do meio incluir um período; caso contrário, o padrão para classificação captura o máximo possível desde o início da linha.

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"

Então, isso funcionaria se o nome do meio não fosse fornecido ou incluísse um período

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))

Então, minha pergunta é se há uma maneira de priorizar a correspondência do fim da string , de modo que esse padrão corresponda ao último, ao meio e depois a todo o restante para classificação.

Posso fazer isso sem reverter a string ou algo hacky assim? Além disso, talvez haja um padrão melhor, já que não sou muito bom com o regex.

Relacionados - [1] [2] - Eu não acho que isso funcionará já que outro padrão foi sugerido em vez de responder à pergunta. Além disso, neste exemplo, o número de palavras na classificação é arbitrário e o padrão que corresponde à classificação também funcionaria para o primeiro nome.

    
por rawr 13.11.2016 в 16:30
fonte

2 respostas

2

Não podemos começar a correspondência do final, não há nenhum modificador para isso em nenhum sistema regex que eu conheça. Mas podemos verificar quantas palavras temos até o final e restringir nossa ganância :). O regex abaixo está fazendo isso.

Esse fará o que você quiser:

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

Visualização ao vivo em regex101.com

Hátambémumaexceção:

quandovocêtiverPrimeira,Últimaemaisdeumapalavraparaaclassificação,apartedaclassificaçãosetornaráumNome.

Para resolver isso, você tem que definir uma lista de prefixos de rank, o que significa que há outra palavra que definitivamente vai atrás dela e capturá-la de maneira gananciosa.

Por exemplo: Deputado, Alto.

    
por NikitOn 25.12.2016 / 13:11
fonte
0

Meu R está enferrujado, mas colocar um ? depois de um quantificador torna-o não-ganancioso em vez de ganancioso em todos os mecanismos de regex que eu conheço. Então, para responder sua pergunta principal:

  

Existe uma maneira de priorizar a correspondência a partir do final da string, de modo que esse padrão corresponda ao último, ao meio, ao primeiro e, em seguida, deixe todo o restante para a classificação?

Você deve ser capaz de fazer isso, tornando a seção de correspondência de classificação do padrão não-gananciosa adicionando um ? após o + .

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

Padrão completo:

pat <- '(?i)(?<rank>[a-z ]+?)\s(?<first>[a-z]+)\s(?:(?<middle>[a-z.]+)\s)?(?<last>[a-z]+)'
    
por Nathan Loyer 07.12.2016 / 17:29
fonte