Excel: último caractere / sequência de caracteres em uma sequência

187

Existe uma maneira eficiente de identificar a última correspondência de caracteres / string em uma string usando as funções base? Ou seja, não o último caractere / sequência da sequência, mas a posição da última ocorrência de um caractere / sequência em uma sequência. Searche findambos funcionam da esquerda para a direita, então não consigo pensar em como aplicar sem um algoritmo recursivo longo. E essa solução agora parece obsoleta.

geotoria
fonte
3
Porque eu quero a posição da última instância do, por exemplo, período "." na cadeia "one.two.three.four"
geotheory 4/13
6
Divertia como uma leitura errada da questão acumula up-votos
geotheory
1
Eu diria que olhe da outra perspectiva, significa que outras pessoas também não entenderam o que você quis dizer na sua pergunta e, portanto, acharam a sugestão a solução correta ... Até a sua resposta selecionada começou com "Eu acho que eu entenda o que você quer dizer "... Não é uma crítica, mas uma solicitação para tentar tornar suas perguntas mais fáceis de entender para ajudar as pessoas a responderem mais facilmente.
John Bustos
Eu deveria ter adicionado o exemplo à pergunta, mas acho que houve o suficiente para diferenciá-lo de uma consulta sobre o caractere final de uma string: searche no conteúdo dafind string de consulta , 'match' é um termo padrão, mais o exemplo vinculado.
Geotheory # 4/13
possível duplicata de Como extrair a última substring de uma coluna do Excel?
Jean-François Corbett

Respostas:

1

Com as versões mais recentes do Excel, surgem novas funções e, portanto, novos métodos. Embora seja replicável em versões mais antigas (ainda não a vi antes), quando se tem o Excel O365, pode-se usar:

=MATCH(2,1/(MID(A1,SEQUENCE(LEN(A1)),1)="Y"))

Isso também pode ser usado para recuperar a última posição de substrings (sobrepostos):

=MATCH(2,1/(MID(A1,SEQUENCE(LEN(A1)),2)="YY"))

| Value  | Pattern | Formula                                        | Position |
|--------|---------|------------------------------------------------|----------|
| XYYZ   | Y       | =MATCH(2,1/(MID(A2,SEQUENCE(LEN(A2)),1)="Y"))  | 3        |
| XYYYZ  | YY      | =MATCH(2,1/(MID(A3,SEQUENCE(LEN(A3)),2)="YY")) | 3        |
| XYYYYZ | YY      | =MATCH(2,1/(MID(A4,SEQUENCE(LEN(A4)),2)="YY")) | 4        |

Embora isso nos permita não usar mais um caractere de substituição arbitrário e permita padrões sobrepostos, a "desvantagem" é o uso de uma matriz.


Nota: Você pode forçar o mesmo comportamento nas versões mais antigas do Excel, usando

=MATCH(2,1/(MID(A2,ROW(A1:INDEX(A:A,LEN(A2))),1)="Y"))

Introduzido CtrlShiftEnterou usando um inline INDEXpara se livrar da interseção implícita:

=MATCH(2,INDEX(1/(MID(A2,ROW(A1:INDEX(A:A,LEN(A2))),1)="Y"),))
JvdV
fonte
1
Eu acho que isso agora está herdado, embora as honras históricas completas pertençam à solução de longa data da @ tigeravatar stackoverflow.com/a/18617720/1156245
geotheory
Nota: Embora minha sugestão ganhasse em códigos de golfe incompletos, o uso de matrizes nem sempre é recomendado quando usado em grandes quantidades. No entanto, possui outros benefícios que tentei mencionar explicitamente. Isso torna a resposta do @Tigeravatar tão relevante quanto antes!
JvdV 18/06
345

Eu acho que entendi o que você quer dizer. Digamos, por exemplo, que você queira o \ mais à direita na seguinte sequência (que é armazenada na célula A1):

Unidade: \ Folder \ SubFolder \ Filename.ext

Para obter a posição do último \, você usaria esta fórmula:

=FIND("@",SUBSTITUTE(A1,"\","@",(LEN(A1)-LEN(SUBSTITUTE(A1,"\","")))/LEN("\")))

Isso nos diz que o \ mais à direita está no caractere 24. Ele faz isso procurando "@" e substituindo o último "\" por um "@". Determina o último usando

(len(string)-len(substitute(string, substring, "")))\len(substring)

Nesse cenário, a substring é simplesmente "\", com um comprimento de 1, para que você possa deixar a divisão no final e apenas usar:

=FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\",""))))

Agora podemos usar isso para obter o caminho da pasta:

=LEFT(A1,FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\","")))))

Aqui está o caminho da pasta sem o final \

=LEFT(A1,FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\",""))))-1)

E para obter apenas o nome do arquivo:

=MID(A1,FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\",""))))+1,LEN(A1))

No entanto, aqui está uma versão alternativa de colocar tudo à direita da última instância de um caractere específico. Portanto, usando o mesmo exemplo, isso também retornaria o nome do arquivo:

=TRIM(RIGHT(SUBSTITUTE(A1,"\",REPT(" ",LEN(A1))),LEN(A1)))
tigeravatar
fonte
24
cabeça girando; cabeça girando; cabeça girando; "ok - não quero usar isso sem entender, então ... uh huh, ok, uh huh ... espera o quê? whoah! sério? isso é genial! Eu me sinto confiante de que não pensaria nisso em várias horas se não dias ou semanas! " - +1, infelizmente, porque +5 ou +10 é difícil de fazer por conta própria --- explicação do problema: (usando o exemplo) SUBSTITUTEtodas (3) instâncias \sem nada (encurte o comprimento da string por 3) -> que \(o terceiro) é o último; substitua isso por algo único e FINDa posição desse personagem único ... incrível ... obrigado!
Code Jockey
7
É esperto. Só é preciso ter cuidado com o fato de que a célula ainda não contém '@', caso contrário, você precisará colocar outra coisa. Você pode verificar usando =ISNUMBER(SEARCH("@",A1)), conforme proposto por @ gwin003 .
Geotheory
3
Sua última opção para extrair tudo à direita da última ocorrência é muito apreciada, porque na maioria das vezes eu procurava a "última ocorrência da cadeia x na cadeia y", meu objetivo final era realmente obter tudo para o direito dessa última ocorrência.
23414 SSilk
1
Por que 99? Você está apenas assumindo que o comprimento dessas várias seqüências é menor que 99? Veja esta resposta e esta resposta que não fazem tal suposição.
Jean-François Corbett
2
Em vez de "@", usei CHAR (9) (o caractere de tabulação), pois meus dados originalmente são provenientes de arquivos delimitados por tabulações e garantimos que não estarão nos meus dados.
precisa
28

Que tal criar uma função personalizada e usá-la em sua fórmula? O VBA possui uma função interna InStrRev, que faz exatamente o que você está procurando.

Coloque isso em um novo módulo:

Function RSearch(str As String, find As String)
    RSearch = InStrRev(str, find)
End Function

E sua função terá esta aparência (assumindo que a string original esteja em B1):

=LEFT(B1,RSearch(B1,"\"))
Keith Rust
fonte
2
Esta é uma solução muito simplista, mas funcional. Se você pode usar algum VBA em seu projeto, use este.
Patrick Hofman
7

tigeravatar e Jean-François Corbett sugeriram usar essa fórmula para gerar a string à direita da última ocorrência do caractere "\"

=TRIM(RIGHT(SUBSTITUTE(A1,"\",REPT(" ",LEN(A1))),LEN(A1)))

Se o caractere usado como separador for espaço "", a fórmula deverá ser alterada para:

=SUBSTITUTE(RIGHT(SUBSTITUTE(A1," ",REPT("{",LEN(A1))),LEN(A1)),"{","")

Não é necessário mencionar, o caractere "{" pode ser substituído por qualquer caractere que não "normalmente" ocorreria no texto a ser processado.

Eugen Sumindan
fonte
Acho essa solução muito mais elegante e compreensível. Além disso, se você multiplicar LEN (A1) por um número, poderá obter a nésima a última ocorrência, desde que a string original não contenha espaços (o que era o meu caso)
Zlatin Zlatev
4

Acabei de criar esta solução, sem necessidade de VBA;

Encontre a última ocorrência de "_" no meu exemplo;

=IFERROR(FIND(CHAR(1);SUBSTITUTE(A1;"_";CHAR(1);LEN(A1)-LEN(SUBSTITUTE(A1;"_";"")));0)

Explicado de dentro para fora;

SUBSTITUTE(A1;"_";"") => replace "_" by spaces
LEN( *above* ) => count the chars
LEN(A1)- *above*  => indicates amount of chars replaced (= occurrences of "_")
SUBSTITUTE(A1;"_";CHAR(1); *above* ) => replace the Nth occurence of "_" by CHAR(1) (Nth = amount of chars replaced = the last one)
FIND(CHAR(1); *above* ) => Find the CHAR(1), being the last (replaced) occurance of "_" in our case
IFERROR( *above* ;"0") => in case no chars were found, return "0"

Espero que isso tenha sido útil.

Sr. Thee
fonte
3

Você poderia usar esta função que eu criei para encontrar a última instância de uma string dentro de uma string.

Certifique-se de que a fórmula aceita do Excel funcione, mas é muito difícil de ler e usar. Em algum momento, você precisa dividir-se em pedaços menores para que seja sustentável. Minha função abaixo é legível, mas isso é irrelevante porque você a chama em uma fórmula usando parâmetros nomeados. Isso simplifica o uso.

Public Function FindLastCharOccurence(fromText As String, searchChar As String) As Integer
Dim lastOccur As Integer
lastOccur = -1
Dim i As Integer
i = 0
For i = Len(fromText) To 1 Step -1
    If Mid(fromText, i, 1) = searchChar Then
        lastOccur = i
        Exit For
    End If
Next i

FindLastCharOccurence = lastOccur
End Function

Eu uso assim:

=RIGHT(A2, LEN(A2) - FindLastCharOccurence(A2, "\"))
Michael Z.
fonte
2

Considerando parte de um comentário feito por @SSilk, meu objetivo final foi realmente obter tudo à direita dessa última ocorrência. Uma abordagem alternativa com uma fórmula muito simples é copiar uma coluna (digamos A) de strings e a cópia (digamos) Coluna B) aplique Localizar e Substituir. Por exemplo, tomando o exemplo:Drive:\Folder\SubFolder\Filename.ext

Encontre o que

Isso retorna o que resta (aqui Filename.ext) após a última instância de qualquer caractere escolhido (aqui \), que às vezes é o objetivo de qualquer maneira e facilita encontrar a posição do último caractere com uma fórmula curta, como:

=FIND(B1,A1)-1
nozes
fonte
1

Estou um pouco atrasado para a festa, mas talvez isso possa ajudar. O link na pergunta tinha uma fórmula semelhante, mas o meu usa a instrução IF () para se livrar dos erros.

Se você não tem medo de Ctrl + Shift + Enter, pode se sair muito bem com uma fórmula de matriz.

String (na célula A1): "one.two.three.four"

Fórmula:

{=MAX(IF(MID(A1,ROW($1:$99),1)=".",ROW($1:$99)))}  use Ctrl+Shift+Enter

Resultado: 14

Primeiro,

ROW($1:$99)

retorna uma matriz de números inteiros de 1 a 99: {1,2,3,4,...,98,99} .

Próximo,

MID(A1,ROW($1:$99),1)

retorna uma matriz de cadeias de comprimento 1 encontrada na cadeia de destino e retorna cadeias em branco depois que o comprimento da cadeia de destino é atingido: {"o","n","e",".",..."u","r","","",""...}

Próximo,

IF(MID(I16,ROW($1:$99),1)=".",ROW($1:$99))

compara cada item na matriz com a sequência "." e retorna o índice do caractere na string ou FALSE:{FALSE,FALSE,FALSE,4,FALSE,FALSE,FALSE,8,FALSE,FALSE,FALSE,FALSE,FALSE,14,FALSE,FALSE.....}

Último,

=MAX(IF(MID(I16,ROW($1:$99),1)=".",ROW($1:$99)))

retorna o valor máximo da matriz: 14

As vantagens dessa fórmula são curtas, relativamente fáceis de entender e não requerem caracteres únicos.

As desvantagens são o uso obrigatório de Ctrl + Shift + Enter e a limitação no comprimento da string. Isso pode ser contornado com uma variação mostrada abaixo, mas essa variação usa a função OFFSET (), que é uma função volátil (leia-se: lenta).

Não tenho certeza de qual é a velocidade dessa fórmula em relação a outras.

Variações:

=MAX((MID(A1,ROW(OFFSET($A$1,,,LEN(A1))),1)=".")*ROW(OFFSET($A$1,,,LEN(A1)))) works the same way, but you don't have to worry about the length of the string

=SMALL(IF(MID(A1,ROW($1:$99),1)=".",ROW($1:$99)),2) determines the 2nd occurrence of the match

=LARGE(IF(MID(A1,ROW($1:$99),1)=".",ROW($1:$99)),2) determines the 2nd-to-last occurrence of the match

=MAX(IF(MID(I16,ROW($1:$99),2)=".t",ROW($1:$99))) matches a 2-character string **Make sure you change the last argument of the MID() function to the number of characters in the string you wish to match!
Stadem
fonte
1

Nas versões mais recentes do Excel (2013 e posteriores), o preenchimento com flash pode ser uma solução simples e rápida, consulte: Usando o Flash Fill in Excel .

RS Finanças
fonte
0

Uma maneira simples de fazer isso no VBA é:

YourText = "c:\excel\text.txt"
xString = Mid(YourText, 2 + Len(YourText) - InStr(StrReverse(YourText), "\" ))
Landelin Delcoucq
fonte
0

Muito tarde para a festa, mas Uma solução simples está usando o VBA para criar uma função personalizada.

Adicione a função ao VBA na pasta de trabalho, planilha ou módulo VBA

Function LastSegment(S, C)
    LastSegment = Right(S, Len(S) - InStrRev(S, C))
End Function

Então a fórmula da célula

=lastsegment(B1,"/")

em uma célula e a sequência a ser pesquisada na célula B1 preencherá a célula com o texto após o último "/" da célula B1. Sem limite de comprimento, sem fórmulas obscuras. A única desvantagem que posso pensar é a necessidade de uma pasta de trabalho habilitada para macro.

Qualquer função VBA do usuário pode ser chamada dessa maneira para retornar um valor a uma fórmula de célula, inclusive como parâmetro para uma função interna do Excel.

Se você for usar muito a função, verifique se o caractere não está na string, então a string está em branco etc.

user8512894
fonte
0

Célula A1 = find/the/position/of/the last slash

Uma maneira simples de fazer isso é inverter o texto e, em seguida, encontrar a primeira barra normalmente. Agora você pode obter o comprimento do texto completo menos esse número.

Igual a:

=LEN(A1)-FIND("/",REVERSETEXT(A1),1)+1

Isso retorna 21, a posição do último /

Richard
fonte
REVERSETEXTnão é uma fórmula padrão do Excel
d219 19/06