Excel: dernière correspondance caractère / chaîne dans une chaîne

187

Existe-t-il un moyen efficace d'identifier la dernière correspondance de caractère / chaîne dans une chaîne à l'aide des fonctions de base? Ce n'est pas le dernier caractère / chaîne de la chaîne, mais la position de la dernière occurrence d'un caractère / chaîne dans une chaîne. Searchet les finddeux fonctionnent de gauche à droite, donc je ne peux pas penser comment appliquer sans un long algorithme récursif. Et cette solution semble désormais obsolète.

géothéorie
la source
3
Parce que je veux la position de la dernière instance de la période par exemple "." dans la chaîne "one.two.three.four"
geotheory
6
Amusant comment une lecture erronée de la question suscite des votes
Geotheory
1
Je dirais de regarder les choses de l'autre point de vue, cela signifie que d'autres personnes n'ont pas non plus compris ce que vous vouliez dire dans votre question et ont donc pensé que la suggestion était la bonne solution ... Même votre réponse sélectionnée commençait par "Je pense que je Comprenez ce que vous voulez dire "... Pas une critique, mais plutôt une demande visant à rendre vos questions plus faciles à comprendre pour aider les gens à y répondre plus facilement.
John Bustos
J'aurais dû ajouter l'exemple à la question, mais je pense qu'il y en avait assez pour distinguer cela d'une requête sur le caractère final d'une chaîne: searchet findle contenu de la chaîne de requête , `` match '' est un terme standard, plus l'exemple lié.
geotheory
duplication possible de Comment extraire la dernière sous-chaîne d'une colonne Excel?
Jean-François Corbett

Réponses:

1

Avec les nouvelles versions d'Excel viennent de nouvelles fonctions et donc de nouvelles méthodes. Bien qu'il soit réplicable dans les anciennes versions (mais je ne l'ai pas vu auparavant), quand on a Excel O365, on peut utiliser:

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

Cela peut également être utilisé pour récupérer la dernière position des sous-chaînes (qui se chevauchent):

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

Bien que cela nous permette à la fois de ne plus utiliser de caractère de remplacement arbitraire et de permettre des motifs qui se chevauchent, le «inconvénient» est l'utilisation d'un tableau.


Remarque: vous pouvez forcer le même comportement dans les anciennes versions d'Excel via

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

Saisie via CtrlShiftEnterou en utilisant une ligne INDEXpour se débarrasser de l'intersection implicite:

=MATCH(2,INDEX(1/(MID(A2,ROW(A1:INDEX(A:A,LEN(A2))),1)="Y"),))
JvdV
la source
1
Je pense que cela hérite de la tique maintenant, bien que tous les honneurs historiques appartiennent à la solution de longue date de @ tigeravatar stackoverflow.com/a/18617720/1156245
geotheory
Remarque: alors que ma suggestion gagnerait au code-golf sommaire, l'utilisation de tableaux n'est pas toujours recommandée lorsqu'elle est utilisée en grande quantité. Cela a cependant d'autres avantages que j'ai essayé de mentionner explicitement. Cela rend la réponse de @Tigeravatar tout aussi pertinente qu'avant!
JvdV
345

Je pense que je comprends ce que tu veux dire. Supposons par exemple que vous vouliez le \ le plus à droite dans la chaîne suivante (qui est stockée dans la cellule A1):

Lecteur: \ Folder \ SubFolder \ Filename.ext

Pour obtenir la position du dernier \, vous utiliseriez cette formule:

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

Cela nous indique que \ est le plus à droite au caractère 24. Pour ce faire, il recherche "@" et remplace le tout dernier "\" par un "@". Il détermine le dernier en utilisant

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

Dans ce scénario, la sous-chaîne est simplement "\" qui a une longueur de 1, vous pouvez donc laisser la division à la fin et utiliser simplement:

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

Nous pouvons maintenant l'utiliser pour obtenir le chemin du dossier:

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

Voici le chemin du dossier sans le \

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

Et pour obtenir uniquement le nom du fichier:

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

Cependant, voici une version alternative de tout ce qui est à droite de la dernière instance d'un personnage spécifique. Donc, en utilisant notre même exemple, cela renverrait également le nom du fichier:

=TRIM(RIGHT(SUBSTITUTE(A1,"\",REPT(" ",LEN(A1))),LEN(A1)))
tigreavatar
la source
24
tête qui tourne; tête qui tourne; tête qui tourne; "ok - je ne veux pas utiliser ça sans le comprendre, alors ... euh huh, ok, euh hein ... attends quoi? whoah! vraiment? c'est du génie! Je suis convaincu que je n'y aurais pas pensé dans plusieurs heures sinon des jours ou des semaines! " - +1, malheureusement, parce que +5 ou +10 est difficile à faire par moi-même --- if-you're-stuck-explication: (en utilisant l'exemple) SUBSTITUTEtoutes les (3) instances de \avec rien (raccourcir la longueur de la chaîne par 3) -> que \(le 3ème) est le dernier; remplacez cela par quelque chose d'unique et FINDla position de ce personnage unique ... génial ... merci!
Code Jockey
7
C'est intelligent. Il suffit de prendre garde que la cellule ne contient pas déjà '@', sinon vous devrez sous-traiter avec autre chose. Vous pouvez vérifier en utilisant =ISNUMBER(SEARCH("@",A1)), comme proposé par @ gwin003 .
geotheory
3
Votre dernière option pour extraire tout ce qui se trouve à droite de la dernière occurrence est très appréciée car la plupart du temps, j'ai recherché la "dernière occurrence de la chaîne x dans la chaîne y", mon objectif final a vraiment été de tout ramener au droit de cette dernière occurrence.
SSilk
1
Pourquoi 99? Supposez-vous simplement que la longueur de ces différentes chaînes est inférieure à 99? Voir cette réponse et cette réponse qui ne font pas une telle hypothèse.
Jean-François Corbett
2
Au lieu de "@", j'ai utilisé CHAR (9) (le caractère de tabulation), car mes données proviennent à l'origine d'un fichier délimité par des tabulations, et je suis assuré que ce ne sera pas dans mes données.
Josiah Yoder
28

Que diriez-vous de créer une fonction personnalisée et de l'utiliser dans votre formule? VBA a une fonction intégrée,InStrRev , qui fait exactement ce que vous recherchez.

Mettez ceci dans un nouveau module:

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

Et votre fonction ressemblera à ceci (en supposant que la chaîne d'origine est en B1):

=LEFT(B1,RSearch(B1,"\"))
Keith Rust
la source
2
C'est une solution très simpliste mais fonctionnelle. Si vous pouvez utiliser du VBA dans votre projet, utilisez celui-ci.
Patrick Hofman
7

tigeravatar et Jean-François Corbett ont suggéré d'utiliser cette formule pour générer la chaîne à droite de la dernière occurrence du caractère "\"

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

Si le caractère utilisé comme séparateur est un espace, "", alors la formule doit être remplacée par:

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

Inutile de le mentionner, le caractère "{" peut être remplacé par n'importe quel caractère qui n'apparaîtrait pas "normalement" dans le texte à traiter.

Eugen Sumindan
la source
Je trouve cette solution bien plus élégante et compréhensible. De plus, si vous multipliez LEN (A1) par un nombre, vous pouvez obtenir la nième à la dernière occurrence, à condition que votre chaîne d'origine ne contienne pas d'espaces (ce qui était le cas pour moi)
Zlatin Zlatev
4

Je viens de proposer cette solution, aucun VBA n'est nécessaire;

Trouvez la dernière occurrence de "_" dans mon exemple;

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

Expliqué à l'envers;

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"

J'espère que cela a été utile.

Monsieur toi
la source
3

Vous pouvez utiliser cette fonction que j'ai créée pour trouver la dernière instance d'une chaîne dans une chaîne.

Bien sûr, la formule Excel acceptée fonctionne, mais elle est beaucoup trop difficile à lire et à utiliser. À un moment donné, vous devez vous séparer en petits morceaux pour qu'il soit maintenable. Ma fonction ci-dessous est lisible, mais ce n'est pas pertinent car vous l'appelez dans une formule en utilisant des paramètres nommés. Cela rend son utilisation simple.

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

Je l'utilise comme ça:

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

Considérant une partie d'un commentaire fait par @SSilk, mon objectif final a vraiment été de tout mettre à droite de cette dernière occurrence, une approche alternative avec une formule très simple consiste à copier une colonne (disons A) de chaînes et sur la copie (disons ColonneB) applique Rechercher et remplacer. Par exemple en prenant l'exemple:Drive:\Folder\SubFolder\Filename.ext

Trouver quoi

Cela renvoie ce qui reste (ici Filename.ext) après la dernière instance du caractère choisi (ici \), ce qui est parfois l'objectif de toute façon et facilite la recherche de la position du dernier caractère de ce type avec une formule courte telle que:

=FIND(B1,A1)-1
pnuts
la source
1

Je suis un peu en retard à la fête, mais peut-être que cela pourrait aider. Le lien dans la question avait une formule similaire, mais la mienne utilise l'instruction IF () pour se débarrasser des erreurs.

Si vous n'avez pas peur de Ctrl + Maj + Entrée, vous pouvez très bien faire avec une formule matricielle.

Chaîne (dans la cellule A1): "one.two.three.four"

Formule:

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

Résultat: 14

Première,

ROW($1:$99)

renvoie un tableau d'entiers de 1 à 99: {1,2,3,4,...,98,99} .

Prochain,

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

renvoie un tableau de chaînes de 1 longueur trouvées dans la chaîne cible, puis renvoie des chaînes vides une fois que la longueur de la chaîne cible est atteinte: {"o","n","e",".",..."u","r","","",""...}

Prochain,

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

compare chaque élément du tableau à la chaîne "." et renvoie soit l'index du caractère dans la chaîne, soit FALSE:{FALSE,FALSE,FALSE,4,FALSE,FALSE,FALSE,8,FALSE,FALSE,FALSE,FALSE,FALSE,14,FALSE,FALSE.....}

Dernier,

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

renvoie la valeur maximale du tableau: 14

Les avantages de cette formule sont qu'elle est courte, relativement facile à comprendre et ne nécessite aucun caractère unique.

Les inconvénients sont l'utilisation requise de Ctrl + Maj + Entrée et la limitation de la longueur de la chaîne. Cela peut être contourné avec une variation illustrée ci-dessous, mais cette variation utilise la fonction OFFSET () qui est une fonction volatile (lecture: lente).

Je ne sais pas quelle est la vitesse de cette formule par rapport aux autres.

Variations:

=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
la source
0

Un moyen simple de le faire dans VBA est:

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

Très tard à la fête, mais une solution simple consiste à utiliser VBA pour créer une fonction personnalisée.

Ajouter la fonction à VBA dans le classeur, la feuille de calcul ou un module VBA

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

Puis la formule cellulaire

=lastsegment(B1,"/")

dans une cellule et la chaîne à rechercher dans la cellule B1 remplira la cellule avec le texte à la fin du dernier "/" de la cellule B1. Aucune limite de longueur, aucune formule obscure. Le seul inconvénient que je peux penser est la nécessité d'un classeur prenant en charge les macros.

Toute fonction VBA utilisateur peut être appelée de cette manière pour renvoyer une valeur à une formule de cellule, y compris en tant que paramètre d'une fonction Excel intégrée.

Si vous comptez utiliser la fonction de manière intensive, vous voudrez vérifier le cas où le caractère n'est pas dans la chaîne, alors la chaîne est vide, etc.

user8512894
la source
0

Cellule A1 = find/the/position/of/the last slash

un moyen simple de le faire est d'inverser le texte, puis de trouver la première barre oblique normalement. Vous pouvez maintenant obtenir la longueur du texte intégral moins ce nombre.

Ainsi:

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

Cela renvoie 21, la position du dernier /

Richard
la source
REVERSETEXTn'est pas une formule Excel standard
d219