Excel: ostatni znak / ciąg pasuje do ciągu

187

Czy istnieje skuteczny sposób na identyfikację ostatniego dopasowania znaku / ciągu w ciągu za pomocą funkcji podstawowych? Czyli nie ostatni znak / string z łańcucha, ale pozycja ostatniego wystąpienia o charakterze / String jest w ciąg. Searchi findoba działają od lewej do prawej, więc nie mogę wymyślić, jak zastosować bez długiego algorytmu rekurencyjnego. I to rozwiązanie wydaje się przestarzała.

geotheory
źródło
3
Ponieważ chcę pozycję ostatniej instancji np. Kropki „.” w ciągu „one.two.three.four”
geotheory
6
Zabawne, jak błędne odczytanie pytania
budzi
1
Powiedziałbym, że popatrz na to z innej perspektywy, to znaczy, że inni też nie rozumieli, co masz na myśli w twoim pytaniu, i dlatego doszedłem do wniosku, że sugestia była właściwym rozwiązaniem ... Nawet twoja wybrana odpowiedź zaczęła się od „Myślę, że ja rozumiem, co masz na myśli „... Nie krytyka, ale prośba o uczynienie twoich pytań łatwiejszymi do zrozumienia, aby ludzie mogli łatwiej odpowiedzieć.
John Bustos
Powinienem był dodać przykład do pytania, ale myślę, że było wystarczająco, aby odróżnić to od zapytania dotyczącego końcowego znaku ciągu: searchi findzarówno w treści ciągu zapytania , „dopasowanie” jest terminem standardowym, plus połączony przykład.
geotheory
możliwy duplikat Jak wyodrębnić ostatni podciąg z kolumny Excel?
Jean-François Corbett,

Odpowiedzi:

1

Wraz z nowszymi wersjami programu Excel pojawiają się nowe funkcje, a tym samym nowe metody. Chociaż można go powielać w starszych wersjach (ale nie widziałem go wcześniej), gdy używa się programu Excel O365, można użyć:

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

Można to również wykorzystać do pobrania ostatniej pozycji (nakładających się) podciągów:

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

Chociaż pozwala to nam nie używać już dowolnych znaków zastępczych i pozwala na nakładanie się wzorców, „minusem” jest użycie tablicy.


Uwaga: Możesz wymusić to samo zachowanie w starszych wersjach programu Excel za pomocą jednego z nich

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

Wprowadzone przez CtrlShiftEnterlub za pomocą wstawki, INDEXaby pozbyć się niejawnego skrzyżowania:

=MATCH(2,INDEX(1/(MID(A2,ROW(A1:INDEX(A:A,LEN(A2))),1)="Y"),))
JvdV
źródło
1
Myślę, że to dziedziczy teraz kleszcza, choć pełne historyczne zaszczyty należą do długoletniego rozwiązania @ tigeravatar stackoverflow.com/a/18617720/1156245
geotheory
Uwaga: Chociaż moja sugestia wygrałaby podczas szkicowego golfa, użycie tablic nie zawsze jest zalecane, gdy jest używane w dużych ilościach. Ma jednak inne zalety, o których starałem się wyraźnie wspomnieć. To sprawia, że ​​odpowiedź @Tigeravatar jest tak samo aktualna jak wcześniej!
JvdV
345

Myślę, że rozumiem o co ci chodzi. Powiedzmy na przykład, że chcesz najbardziej w prawo \ w następującym ciągu (który jest przechowywany w komórce A1):

Dysk: \ Folder \ Podfolder \ Nazwa pliku. Tekst

Aby uzyskać pozycję ostatniego \, użyłbyś tej formuły:

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

To mówi nam, że najbardziej na prawo \ jest znak 24. Czyni to, szukając „@” i zastępując ostatnie „\” znakiem „@”. Określa ostatni za pomocą

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

W tym scenariuszu podciąg to po prostu „\”, który ma długość 1, więc możesz zrezygnować z podziału na końcu i po prostu użyć:

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

Teraz możemy go użyć, aby uzyskać ścieżkę folderu:

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

Oto ścieżka do folderu bez końcowego \

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

Aby uzyskać tylko nazwę pliku:

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

Jednak tutaj jest alternatywna wersja przenoszenia wszystkiego na prawo od ostatniej instancji określonej postaci. Korzystając z tego samego przykładu, zwróciłoby to również nazwę pliku:

=TRIM(RIGHT(SUBSTITUTE(A1,"\",REPT(" ",LEN(A1))),LEN(A1)))
tigeravatar
źródło
24
kręcenie głową; wirowanie głowy; kręcenie głową; „ok - nie chcę tego używać bez zrozumienia tego, więc… hmm, ok, hmm ... poczekaj co? whoah! naprawdę? to geniusz! Jestem pewien, że nie pomyślałbym o tym za kilka godzin jeśli nie dni lub tygodnie! ” - +1, niestety, ponieważ +5 lub +10 jest trudne do zrobienia na własną rękę --- jeśli utkniesz w objaśnieniu: (na przykładzie) SUBSTITUTEwszystkie (3) wystąpienia \bez niczego (skróć długość łańcucha o 3) -> że \(3.) jest ostatnim; zastąp to czymś wyjątkowym i FINDpozycją tej wyjątkowej postaci ... niesamowite ... dzięki!
Code Jockey
7
To jest sprytne. Musisz tylko uważać, aby komórka nie zawierała już znaku „@”, w przeciwnym razie będziesz musiał zapisać coś innego. Możesz to sprawdzić za pomocą =ISNUMBER(SEARCH("@",A1)), zgodnie z propozycją @ gwin003 .
geotheory
3
Twoja ostatnia opcja wyodrębnienia wszystkiego po prawej stronie ostatniego wystąpienia jest bardzo doceniana, ponieważ przez większość czasu szukałem „ostatniego wystąpienia ciągu x w ciągu y”, moim ostatecznym celem było doprowadzenie wszystkiego do prawo do ostatniego zdarzenia.
SSilk
1
Dlaczego 99? Czy po prostu zakładasz, że długość tych różnych łańcuchów jest mniejsza niż 99? Zobacz tę odpowiedź i tę odpowiedź, które nie zakładają takiego założenia.
Jean-François Corbett
2
Zamiast „@” użyłem CHAR (9) (znak tabulacji), ponieważ moje dane pierwotnie pochodzą z pliku rozdzielanego tabulatorami i jestem pewien, że nie będzie ich w moich danych.
Josiah Yoder
28

Co powiesz na utworzenie niestandardowej funkcji i użycie jej w formule? VBA ma wbudowaną funkcję,InStrRev , która robi dokładnie to, czego szukasz.

Umieść to w nowym module:

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

A twoja funkcja będzie wyglądać tak (zakładając, że oryginalny ciąg znajduje się w B1):

=LEFT(B1,RSearch(B1,"\"))
Keith Rust
źródło
2
To bardzo uproszczone, ale działające rozwiązanie. Jeśli możesz użyć VBA w swoim projekcie, użyj tego.
Patrick Hofman,
7

tigeravatar i Jean-François Corbett zasugerowali użycie tej formuły do ​​wygenerowania ciągu znaków po ostatnim wystąpieniu znaku „\”

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

Jeśli znakiem używanym jako separator jest spacja „”, należy zmienić formułę na:

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

Nie trzeba wspominać, że znak „{” można zastąpić dowolnym znakiem, który „normalnie” nie występuje w przetwarzanym tekście.

Eugen Sumindan
źródło
Uważam to rozwiązanie za bardziej eleganckie i zrozumiałe. Również jeśli pomnożymy LEN (A1) przez liczbę, możemy uzyskać n-ty do ostatniego wystąpienia, pod warunkiem, że oryginalny ciąg nie zawiera spacji (co miało miejsce w moim przypadku)
Zlatin Zlatev
4

Właśnie wymyśliłem to rozwiązanie, nie wymaga VBA;

Znajdź ostatnie wystąpienie „_” w moim przykładzie;

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

Wyjaśnione na lewą stronę;

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"

Mam nadzieję, że to było pomocne.

Panie Tobie
źródło
3

Możesz użyć tej funkcji, którą utworzyłem, aby znaleźć ostatnią instancję ciągu w ciągu.

Upewnij się, że przyjęta formuła programu Excel działa, ale jest zbyt trudna do odczytania i użycia. W pewnym momencie musisz podzielić się na mniejsze części, aby można było je utrzymać. Moja funkcja poniżej jest czytelna, ale to nie ma znaczenia, ponieważ wywołujesz ją w formule przy użyciu nazwanych parametrów. To sprawia, że ​​korzystanie z niego jest proste.

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

Używam tego w ten sposób:

=RIGHT(A2, LEN(A2) - FindLastCharOccurence(A2, "\"))
Michael Z.
źródło
2

Biorąc pod uwagę część komentarza dokonanego przez @SSilk, moim ostatecznym celem było doprowadzenie wszystkiego do prawej strony tego ostatniego wystąpienia. Alternatywnym podejściem z bardzo prostą formułą jest skopiowanie kolumny (powiedzmy A) ciągów znaków i skopiowanie (powiedzmy) Kolumna B) zastosuj Znajdź i zamień. Na przykład biorąc przykład:Drive:\Folder\SubFolder\Filename.ext

Znajdź co

Zwraca to, co pozostaje (tutaj Filename.ext) po ostatnim wystąpieniu dowolnej postaci (tutaj \), co i tak czasami jest celem i ułatwia znalezienie pozycji ostatniej takiej postaci za pomocą krótkiej formuły, takiej jak:

=FIND(B1,A1)-1
orzechy
źródło
1

Jestem trochę spóźniony na imprezę, ale może to może pomóc. Link w pytaniu miał podobną formułę, ale moja używa instrukcji IF (), aby pozbyć się błędów.

Jeśli nie boisz się klawiszy Ctrl + Shift + Enter, możesz całkiem dobrze poradzić sobie z formułą tablicową.

Ciąg (w komórce A1): „one.two.three.four”

Formuła:

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

Wynik: 14

Pierwszy,

ROW($1:$99)

zwraca tablicę liczb całkowitych od 1 do 99: {1,2,3,4,...,98,99} .

Kolejny,

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

zwraca tablicę ciągów o długości 1 znalezionych w ciągu docelowym, a następnie zwraca puste ciągi po osiągnięciu długości ciągu docelowego: {"o","n","e",".",..."u","r","","",""...}

Kolejny,

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

porównuje każdy element w tablicy z ciągiem „.” i zwraca indeks znaku w ciągu lub FAŁSZ:{FALSE,FALSE,FALSE,4,FALSE,FALSE,FALSE,8,FALSE,FALSE,FALSE,FALSE,FALSE,14,FALSE,FALSE.....}

Ostatni, ubiegły, zeszły,

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

zwraca maksymalną wartość tablicy: 14

Zaletą tej formuły jest to, że jest krótka, stosunkowo łatwa do zrozumienia i nie wymaga żadnych unikalnych znaków.

Wady to wymagane użycie Ctrl + Shift + Enter i ograniczenie długości łańcucha. Można to obejść za pomocą wariantu pokazanego poniżej, ale ta odmiana korzysta z funkcji OFFSET (), która jest funkcją zmienną (czytaj: wolno).

Nie jestem pewien, jaka jest szybkość tej formuły w porównaniu z innymi.

Wariacje:

=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
źródło
0

Prostym sposobem na to w VBA jest:

YourText = "c:\excel\text.txt"
xString = Mid(YourText, 2 + Len(YourText) - InStr(StrReverse(YourText), "\" ))
Landelin Delcoucq
źródło
0

Bardzo późno na imprezę, ale prostym rozwiązaniem jest użycie VBA do stworzenia niestandardowej funkcji.

Dodaj funkcję do VBA w skoroszycie, arkuszu lub module VBA

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

Następnie formuła komórkowa

=lastsegment(B1,"/")

w komórce, a ciąg do przeszukania w komórce B1 zapełni komórkę tekstem kończącym ostatnie „/” z komórki B1. Bez ograniczenia długości, bez niejasnych wzorów. Jedynym minusem jest to, że potrzebuję skoroszytu z obsługą makr.

W ten sposób można wywołać dowolną funkcję VBA użytkownika, aby zwrócić wartość do formuły komórkowej, w tym jako parametr do wbudowanej funkcji Excel.

Jeśli zamierzasz intensywnie korzystać z tej funkcji, powinieneś sprawdzić wielkość liter, gdy znak nie znajduje się w ciągu, a następnie ciąg jest pusty itp.

użytkownik8512894
źródło
0

Komórka A1 = find/the/position/of/the last slash

prosty sposób to odwrócić tekst, a następnie normalnie znaleźć pierwszy ukośnik. Teraz możesz uzyskać długość pełnego tekstu minus ten numer.

Tak jak:

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

Zwraca 21, pozycję ostatniego /

Richard
źródło
REVERSETEXTnie jest standardową formułą Excela
d219