Найти N-й экземпляр символа в Excel (без VBA) - PullRequest
0 голосов
/ 27 марта 2019

TL; DR сводка: я хочу формулу, которая найдет N-ное "_" (для любого N) в строке и вернет ее индекс; ИЛИ найти N-ю подстроку, разделенную "_". У меня есть VBA, чтобы сделать это, но это медленно.

Длинная версия: Я работаю с данными рекламной кампании. Мои маркетологи (к счастью) используют последовательную схему именования для своих кампаний. К сожалению, это очень долго.

Названия кампаний содержат ровно 1 часть данных, которые я не могу получить из отчетов.

Для справки названия кампаний имеют формат:

ADV_CO_BG_Product_UniqueID_XX_mm.dd.yyyy_mm.dd.yyyy_TYP_NUM

... и у меня есть столбец около 200K из них (растет на пару сотен каждую неделю).

Edit:
Важной частью является то, что в названии кампании есть несколько частей, между которыми стоит _. В этом случае мне нужна 9-я часть, но я хочу, чтобы опция была достаточно гибкой, чтобы мне не нужно было добавлять или удалять строки, чтобы изменить какую часть я нацеливаю.

Я видел в других вопросах, как использовать вложенную формулу, такую ​​как:

=MID(
  Data_OLV[@Campaign],
  FIND("_",Data_OLV[@Campaign],
    FIND("_",Data_OLV[@Campaign],
      FIND("_",Data_OLV[@Campaign],
        FIND("_",Data_OLV[@Campaign],
          FIND("_",Data_OLV[@Campaign],
            FIND("_",Data_OLV[@Campaign],
              FIND("_",Data_OLV[@Campaign],
                FIND("_",Data_OLV[@Campaign])+1)
              +1)
            +1)
          +1)
        +1)
      +1)
    +1)
  +1,
3)

... но это трудно изменить, если мне нужно что-то в другой позиции.

У меня есть UDF под названием StringSplit (см. Ниже), который обеспечивает желаемые результаты, но он очень медленный (и работает только при включении макросов, что не вся моя аудитория).

Есть ли лучший способ сделать то, что я пытаюсь сделать?

    Public Function StringSplit(input_ As String, delimiter_ As String, index_ As Integer)
        On Error GoTo err

        out = Split(input_, delimiter_, -1, vbTextCompare)
        StringSplit = out(index_ - 1)
        Exit Function
    err:
        If err.Number = 9 Then
            StringSplit = CVErr(xlErrRef)
            Exit Function
        End If
        StringSplit = err.Description
    End Function

Ответы [ 5 ]

2 голосов
/ 27 марта 2019

Я думаю, что это формула, которую вы ищете -

=MID(A2, FIND(CHAR(1), SUBSTITUTE(A2, B2, CHAR(1), C2))+1, FIND(CHAR(1), SUBSTITUTE(A2, B2, CHAR(1), C2+1)) -  FIND(CHAR(1), SUBSTITUTE(A2, B2, CHAR(1), C2))-1)

Вот как это сделать -

enter image description here

Здесь B2 - это Delimiter type, а C2 - это Nth occurrence of the Delimiter. Вы можете изменить код в соответствии с вашими потребностями. Просто измените B2 & C2.

1 голос
/ 27 марта 2019

Если, например, вы хотите найти третий экземпляр ? в ячейке A1 , попробуйте:

=FIND(CHAR(1),SUBSTITUTE(A1,"?",CHAR(1),3))

enter image description here

Примечание:

Мы предполагаем, что CHAR(1) не появляется в исходной строке.
Чтобы получить последний экземпляр, используйте:

=FIND(CHAR(1),SUBSTITUTE(A1,"?",CHAR(1),(LEN(A1)-LEN(SUBSTITUTE(A1,"?","")))))
0 голосов
/ 27 марта 2019

Один из способов найти n-й экземпляр строки с подчеркиванием, и вернуть эту подстроку , заключается в следующей формуле:

=TRIM(MID(SUBSTITUTE(A1,"_",REPT(" ",999)),MAX(1,999*(n-1)),999))

, где n - это искомый экземпляр.

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

Если вы используете версию Excel с функцией FILTERXML, вы можете использовать эту формулу:

=INDEX(FILTERXML("<t><s>" & SUBSTITUTE(A1,"_","</s><s>") & "</s></t>","//s"),n)

Не уверен, какой из них будет более эффективным (быстрее) в большой базе данных

0 голосов
/ 27 марта 2019

Как прокомментировал Egan Wolf, есть решение на http://exceljet.net/formula/find-nth-occurrence-of-character =MID([@[Campaign]],FIND(CHAR(160),SUBSTITUTE([@[Campaign]],"_",CHAR(160),9))+1,4)

Или, в более общем смысле: =MID(TextToSearch,FIND(CHAR(160),SUBSTITUTE(TextToSearch,Delimiter,CHAR(160),InstanceNumber ))+1,LengthOfDesiredSection)

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

  =MID(TextToSearch,
   FIND(CHAR(160),SUBSTITUTE(TextToSearch,Delimiter,CHAR(160),InstanceNumber))+1,
   IFERROR(
  (FIND(CHAR(160),SUBSTITUTE(TextToSearch,Delimiter,CHAR(160),InstanceNumber+1)-
   FIND(CHAR(160),SUBSTITUTE(TextToSearch,Delimiter,CHAR(160),InstanceNumber)))-1,
   LEN(TextToSearch)-
   FIND(CHAR(160),SUBSTITUTE(TextToSearch,Delimiter,CHAR(160),InstanceNumber))))

IFERROR() защищает от ситуаций, когда Delimiter появляется только InstanceNumber раз в TextToSearch.

0 голосов
/ 27 марта 2019

Вы говорите, если я прав, что данные, которые вы получаете, всегда в том формате, который вы разместили, и что вы постоянно хотите извлекать данные TYP.

Почему бы не искать TYP в строке и дополнительно искать NUM, поскольку это указывает на следующие подданные?

Тогда вы получите формулу, такую ​​как

=TRIM(MID(W20,SEARCH("TYP",W20),SEARCH("NUM",W20)-SEARCH("TYP",W20)))

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

РЕДАКТИРОВАТЬ

Так как OP упомянул строки заголовка не согласованы:

=TRIM(MID(W20,SEARCH(A1,W20),IF(A2="",LEN(W20),SEARCH(A2,W20)-SEARCH(A1,W20))))

В ячейке A1 будет строка заголовка данных, которые должны быть извлечены, в этом случае TYP

В ячейке A2 будет строка заголовка следующих субданных,Если пусто, формула возвращает все символы, найденные в первой функции SEARCH, используя ячейку A1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...