Excel: последнее совпадение символа / строки в строке

187

Есть ли эффективный способ определить последнее совпадение символа / строки в строке, используя базовые функции? Т.е. не последний символ / строка из строки, но положение последнего вхождения символа / струны в строке. Searchи findоба работают слева направо, поэтому я не могу думать, как применить без длинного рекурсивного алгоритма. И это решение сейчас кажется устаревшим.

geotheory
источник
3
Потому что я хочу, чтобы позиция последнего экземпляра, например, периода "." в строке "one.two.three.four"
геотеория
6
Забавно, как ошибочное прочтение вопроса набирает
обороты
1
Я бы сказал, посмотрите на это с другой точки зрения, это означает, что другие люди также не поняли, что вы имели в виду в своем вопросе, и поэтому решили, что это правильное решение ... Даже выбранный вами ответ начинался с "Я думаю, что я получить то, что вы имеете в виду "... Не критика, а скорее просьба, чтобы сделать ваши вопросы более понятными, чтобы помочь людям легче ответить.
Джон Бустос
Я должен был добавить пример к вопросу, но я думаю, что этого было достаточно, чтобы отличить его от запроса о конечном символе строки: searchи для содержимогоfind строки запроса , «match» - это стандартный термин, плюс связанный пример.
13
Возможный дубликат Как извлечь последнюю подстроку из столбца Excel?
Жан-Франсуа Корбетт

Ответы:

1

С новыми версиями Excel приходят новые функции и, следовательно, новые методы. Хотя он может быть воспроизведен в более старых версиях (но я не видел его раньше), когда у вас есть Excel O365, он может использовать:

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

Это также может быть использовано для получения последней позиции (перекрывающихся) подстрок:

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

Хотя это позволяет нам больше не использовать произвольный символ замены и позволяет перекрывать шаблоны, «недостатком» является использование массива.


Примечание. Вы можете принудительно применить то же поведение в более старых версиях Excel, либо

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

Введено через CtrlShiftEnterили с помощью inline, INDEXчтобы избавиться от неявного пересечения:

=MATCH(2,INDEX(1/(MID(A2,ROW(A1:INDEX(A:A,LEN(A2))),1)="Y"),))
JvdV
источник
1
Я думаю, что это унаследовало эту галочку, хотя полные исторические награды принадлежат давнему решению @ tigeravatar stackoverflow.com/a/18617720/1156245
geotheory
Примечание: хотя мое предложение выиграет в отрывочном коде-гольфе, использование массивов не всегда рекомендуется при использовании в больших количествах. Тем не менее, у него есть и другие преимущества, о которых я пытался упомянуть. Это делает ответ @Tigeravatar таким же актуальным, как и раньше!
JvdV
345

Я думаю, я понимаю, что вы имеете в виду. Допустим, например, что вы хотите самый правый \ в следующей строке (которая хранится в ячейке A1):

Диск: \ Папка \ подпапка \ FileName.Ext

Чтобы получить позицию последнего \, вы должны использовать эту формулу:

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

Это говорит нам о том, что самый правый \ находится в 24-м символе. Он делает это путем поиска «@» и замены самого последнего «\» на «@». Он определяет последний с помощью

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

В этом сценарии подстрока просто "\", которая имеет длину 1, так что вы можете оставить разделение в конце и просто использовать:

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

Теперь мы можем использовать это, чтобы получить путь к папке:

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

Вот путь к папке без завершающего \

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

И чтобы получить только имя файла:

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

Тем не менее, здесь есть альтернативная версия получения всего справа от последнего экземпляра определенного символа. Таким образом, используя наш тот же пример, это также вернет имя файла:

=TRIM(RIGHT(SUBSTITUTE(A1,"\",REPT(" ",LEN(A1))),LEN(A1)))
tigeravatar
источник
24
голова кружится; голова кружится; голова кружится; "хорошо - не хочу использовать это, не понимая этого, так что ... э-э-э, хорошо, э-э ... подожди что? хм! правда? это гениально! я уверен, что не подумал бы об этом через несколько часов если не дни или недели! - +1, к сожалению, потому что +5 или +10 сложно сделать самостоятельно --- объяснение, если вы застряли: (на примере) SUBSTITUTEвсе (3) экземпляры \с пустыми значениями (сокращение длины строки 3) -> что \(3-е) является последним; замените это чем-то уникальным и FINDположением этого уникального персонажа ... потрясающе ... спасибо!
Код жокея
7
Это умно. Просто нужно помнить, что ячейка еще не содержит «@», в противном случае вам нужно добавить что-то другое. Вы можете проверить, используя =ISNUMBER(SEARCH("@",A1)), как предложено @ gwin003 .
геофизика
3
Ваш последний вариант для извлечения всего справа от последнего вхождения очень ценится, потому что большую часть времени я искал «последнее вхождение строки x в строке y», моей конечной целью действительно было получить все до Право этого последнего случая.
SSilk
1
Почему 99? Вы только предполагаете, что длина этих различных строк меньше 99? Смотрите этот ответ и этот ответ, который не делает такого предположения.
Жан-Франсуа Корбетт
2
Вместо «@» я использовал CHAR (9) (символ табуляции), так как мои данные изначально получены из файла с разделителями табуляции, и я гарантированно, что он не будет в моих данных.
Иосия Йодер,
28

Как насчет создания пользовательской функции и ее использования в формуле? VBA имеет встроенную функцию,InStrRev которая делает именно то, что вы ищете.

Поместите это в новый модуль:

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

И ваша функция будет выглядеть так (при условии, что исходная строка находится в B1):

=LEFT(B1,RSearch(B1,"\"))
Кит Раст
источник
2
Это очень упрощенное, но рабочее решение. Если вы можете использовать VBA в своем проекте, используйте этот.
Патрик Хофман
7

tigeravatar и Жан-Франсуа Корбетт предложили использовать эту формулу для генерации строки справа от последнего вхождения символа "\"

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

Если символ, используемый в качестве разделителя, является пробелом "", то формула должна быть изменена на:

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

Не нужно упоминать, что символ "{" можно заменить любым символом, который "нормально" не встречается в тексте для обработки.

Евгений Суминдан
источник
Я считаю это решение более элегантным и понятным. Кроме того, если вы умножаете LEN (A1) на число, вы можете получить nth до последнего вхождения, если ваша исходная строка не содержит пробелов (что было для меня)
Златин Златев
4

Просто придумали это решение, VBA не нужна;

Найдите последнее вхождение "_" в моем примере;

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

Объяснил наизнанку;

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"

Надеюсь, это было полезно.

Мистер ты
источник
3

Вы можете использовать эту функцию, которую я создал, чтобы найти последний экземпляр строки в строке.

Конечно, принятая формула Excel работает, но ее слишком сложно читать и использовать. В какой-то момент вы должны разбиться на более мелкие куски, чтобы это можно было обслуживать. Моя функция ниже читабельна, но это не имеет значения, потому что вы вызываете ее в формуле, используя именованные параметры. Это делает использование этого простым.

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

Я использую это так:

=RIGHT(A2, LEN(A2) - FindLastCharOccurence(A2, "\"))
Майкл З.
источник
2

Принимая во внимание часть комментария, сделанного @SSilk, моей конечной целью действительно было получить все правее того последнего случая , альтернативный подход с очень простой формулой - скопировать столбец (скажем A) строк и в копию (скажем, Колонка B) применить поиск и замену. Например, взять пример:Drive:\Folder\SubFolder\Filename.ext

Найти то, что

Это возвращает то, что остается (здесь Filename.ext) после последнего экземпляра любого выбранного символа (здесь \), что иногда в любом случае является целью, и облегчает поиск позиции последнего такого символа с помощью короткой формулы, такой как:

=FIND(B1,A1)-1
pnuts
источник
1

Я немного опоздал на вечеринку, но, возможно, это могло бы помочь. Ссылка в вопросе имела похожую формулу, но моя использует оператор IF (), чтобы избавиться от ошибок.

Если вы не боитесь Ctrl + Shift + Enter, вы можете справиться с формулой массива.

Строка (в ячейке A1): "one.two.three.four"

Формула:

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

Результат: 14

Первый,

ROW($1:$99)

возвращает массив целых чисел от 1 до 99: {1,2,3,4,...,98,99}.

Следующий,

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

возвращает массив строк длиной 1, найденных в целевой строке, а затем возвращает пустые строки после достижения длины целевой строки: {"o","n","e",".",..."u","r","","",""...}

Следующий,

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

сравнивает каждый элемент в массиве со строкой "." и возвращает либо индекс символа в строке, либо FALSE:{FALSE,FALSE,FALSE,4,FALSE,FALSE,FALSE,8,FALSE,FALSE,FALSE,FALSE,FALSE,14,FALSE,FALSE.....}

Последний,

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

возвращает максимальное значение массива: 14

Преимущества этой формулы в том, что она короткая, относительно простая для понимания и не требует каких-либо уникальных символов.

Недостатками являются обязательное использование Ctrl + Shift + Enter и ограничение длины строки. Это можно обойти с помощью варианта, показанного ниже, но этот вариант использует функцию OFFSET (), которая является изменчивой (читай: медленной) функцией.

Не уверен, что скорость этой формулы против других.

Варианты:

=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
источник
0

Простой способ сделать это в VBA:

YourText = "c:\excel\text.txt"
xString = Mid(YourText, 2 + Len(YourText) - InStr(StrReverse(YourText), "\" ))
Ланделин Делкук
источник
0

Очень поздно для вечеринки, но простое решение - использовать VBA для создания пользовательской функции.

Добавьте функцию в VBA в WorkBook, Worksheet или VBA Module.

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

Тогда формула клетки

=lastsegment(B1,"/")

в ячейке, и строка, которую нужно искать в ячейке B1, заполнит ячейку текстом, заканчивающимся последним знаком "/" из ячейки B1. Нет ограничений по длине, нет неясных формул. Единственным недостатком, который я могу себе представить, является необходимость создания книги с поддержкой макросов.

Любая пользовательская функция VBA может быть вызвана таким образом, чтобы вернуть значение в формулу ячейки, в том числе в качестве параметра встроенной функции Excel.

Если вы собираетесь интенсивно использовать функцию, вам нужно проверить, нет ли символа в строке, строка пуста и т. Д.

user8512894
источник
0

клетка A1 = find/the/position/of/the last slash

Простой способ сделать это - перевернуть текст, а затем найти первый слэш как обычно. Теперь вы можете получить длину полного текста минус это число.

Вот так:

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

Это возвращает 21, позиция последнего /

Ричард
источник
REVERSETEXTне стандартная формула Excel
d219