Извлечь число фиксированной длины из ячейки Excel - PullRequest
3 голосов
/ 21 июня 2020

Несколько потоков с похожими именами для этого, но все равно не смогли решить мою проблему. Мне нужно извлечь ЧИСЛО фиксированной длины из строки Excel (в моем сценарии 8 цифр). Для этой цели была предоставлена ​​следующая формула Excel:

=MID(A1,FIND("--------",SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"0","-"),"1","-"),"2","-"),"3","-"),"4","-"),"5","-"),"6","-"),"7","-"),"8","-"),"9","-")),8)

Он выполняет свою работу, однако у меня есть две проблемы с этим:

  1. Самое главное - я ищу для соответствия точному . Хотя он извлекает первую найденную последовательность 8-di git, я действительно после только 8-di git чисел, что означает, что числа 9-di git (или более длинные) должны игнорироваться (поскольку числа 7-di git уже есть). Эта формула также извлекает первые 8 цифр из более длинного числа.

  2. Менее важно, но было бы здорово искать только числа, начинающиеся с 1. Итак, на самом деле просто пытаюсь извлечь это: 1 ??????? как числовое значение c. Таким образом, должно быть извлечено что-то вроде «a 12891212 a» или «a 12891212 a», а 12891212 0a или 23456789 не должно.

Если это возможно, я бы предпочел подход на основе формул Excel по сравнению с VBA. Любая помощь приветствуется!

Ответы [ 5 ]

5 голосов
/ 21 июня 2020

Это можно сделать с помощью формулы, но все зависит от вашей версии Excel:

enter image description here


1) Excel 2016, you could still use a formula:

Formula in B1:

=IFERROR(MID(A1,MAX((MID(A1,ROW(A$1:INDEX(A:A,LEN(A1))),1)="1")*(ISNUMBER(--MID(A1,ROW(A$1:INDEX(A:A,LEN(A1))),8)))*(NOT(ISNUMBER(--MID(A1,ROW(A$1:INDEX(A:A,LEN(A1)))+8,1))))*(NOT(ISNUMBER(--MID(A1,ROW(A$1:INDEX(A:A,LEN(A1)))-1,1))))*(ROW(A$1:INDEX(A:A,LEN(A1))))),8),"Nothing found")

Note: This is an array formula and needs to be confirmed through CtrlShiftEnter


2) Excel 2019, using CONCAT и FILTERXML:

Формула в B1:

=IFERROR(FILTERXML("<t><s>"&CONCAT(IF(ISNUMBER(--MID(A1,ROW(A$1:INDEX(A:A,LEN(A1))),1)),MID(A1,ROW(A$1:INDEX(A:A,LEN(A1))),1),"</s><s>"))&"</s></t>","//s[starts-with(., '1') and string-length(.) =8]"),"Nothing Found")

Примечание: Это формула массива, и ее необходимо подтвердить с помощью Ctrl Shift Введите

3) Excel 365, с использованием ранее упомянутых функций, но включая SEQUENCE:

Формула в B1:

=IFERROR(FILTERXML("<t><s>"&CONCAT(IF(ISNUMBER(--MID(A1,SEQUENCE(LEN(A1)),1)),MID(A1,SEQUENCE(LEN(A1)),1),"</s><s>"))&"</s></t>","//s[starts-with(., '1') and string-length(.) =8]"),"Nothing Found")

Часть формул XPATH заботится о фактическом запросе, ища строки, которые начинаются с «1» и имеют общую длину «8». Тогда это будет работать даже со строками вроде 'abc123456789abc12345678abc29876543', возвращающими '12345678'.

Если вам нравятся FILTERXML и XPATH, тогда это может показаться вам интересным.

4) VBA: если вы должны использовать VBA, я думаю, что UDF - хороший вариант. Примерно так:

Function GetStr(str As String, pat As String) As String

With CreateObject("vbscript.regexp")
    .Pattern = pat
    .Global = True
    If .Test(str) = True Then
        GetStr = .Execute(str)(0).Submatches(0)
    Else
        GetStr = "Nothing found"
    End If
End With

End Function

Вы можете вызвать это в B1 согласно =GetStr(A1,"(?:^|\D)(1\d{7})(?:\D|$)"). Это использование регулярного выражения. Если вам интересно и вы хотите узнать больше, тогда это - интересное чтение для вас.

Я специально оставил шаблон вне UDF, возможно, вы когда-нибудь захотите его изменить. Текущий шаблон можно увидеть в этой онлайн Demo , где слева направо движок будет искать:

  • (?: - 1-я группа без захвата
    • ^|\D - Либо начальная строка ancor, либо что-то другое, кроме di git.
    • ) - Закрыть 1-ю группу без захвата.
  • ( - 1-я группа захвата.
    • 1\d{7} - поиск литерала 1, за которым следуют 7 цифр.
    • ) - закрытие 1-й группы захвата.
  • (?: - 2-я группа без захвата
    • \D|$ - Любое другое значение, кроме di git или ancor в конце строки.
    • ) - Закройте 2-ю группу без захвата.

введите описание изображения здесь

1 голос
/ 22 июня 2020

Другой вариант с использованием функции CONCAT + FILTER XML

В B2 формула скопирована:

=IFERROR(FILTERXML("<a><b>"&CONCAT(INDEX(TEXT(MID(SUBSTITUTE(A2," ","A"),ROW(A$1:INDEX(A:A,LEN(A2))),1),"0;;0;""</b><b>"""),0))&"</b></a>","//b[.>9999999][.<20000000]"),"not found")

введите описание изображения здесь

1 голос
/ 21 июня 2020

Простая альтернатива VBA через Split() функцию

Обратите внимание , что функция Split() будет разделена здесь на две части только его (необязательно) последний аргумент 2; по умолчанию вы получите неограниченное количество разделенных частей .

Поскольку действительные числовые последовательности должны начинаться с "1", этот di git оказывается нашим разделителем для действия разделения.

Присоединение разделителя "1" к разделяемой строке sample позволяет ссылаться на parts(1) без ошибок, даже если разделителя ("1") вообще нет.

    parts = Split(sample & "1", "1", 2)    ' arguments: string, delimiter, {limit}
Function EightDigits(sample, Optional chk As String = "N/A!") As String
Dim parts: parts = Split(sample & "1", "1", 2)   ' limit to 2 split parts only!
If Not Right(parts(0), 1) Like "#" Then          ' other preceding digit means no first "1"
    EightDigits = chk                            ' temporary string value "N/A!"
    chk = "1" & CStr(Val(parts(1)))              ' Val() cuts following non digits
End If
If Len(chk) = 8 Then EightDigits = chk           ' return only 8-digit numbers
End Function
1 голос
/ 21 июня 2020

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

=IFERROR(LOOKUP(2,1/( MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),8)* (LEN(MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),8))=8)* (NOT(ISNUMBER(MID("a"&A2,ROW($A$1:INDEX(A:A,LEN(A2))),1)+0)))* (NOT(ISNUMBER(RIGHT(MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),9))+0)))* (MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),1)="1")),MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),8)),"")

Это длинный, поскольку он построен в основном для генерации 1 строки и 4 тестов.

MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),8) генерирует строку из 8 символов.

(LEN(MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),8))=8) проверяет наличие 8 символов

(NOT(ISNUMBER(MID("a"&A2,ROW($A$1:INDEX(A:A,LEN(A2))),1)+0))) проверяет, что предыдущий символ не является di git

(NOT(ISNUMBER(RIGHT(MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),9))+0))) проверяет, что символ рядом с проверяемой строкой не является di git

(MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),1)="1") проверяет, что первый di git равен единице.

Итак, если последние 4 тесты верны, тогда умножение дает 8 di git число, которое используется для вычисления обратного числа, которое проверяется с использованием LOOKUP, которое используется для возврата найденного результата.

Однако я не буду рекомендовать его с точки зрения обслуживания .

1 голос
/ 21 июня 2020

Вот простая функция, определяемая пользователем, которая ищет подстроки, которые являются цифрами. Он создает массив подстрок. Затем он ищет элемент этого массива, который имеет длину 8 и начальный символ 1:

Option Explicit

Public Function NineD(s As String) As String
    Dim L As Long, temp As String, wf As WorksheetFunction
    Dim i As Long, arr, a
    
    Set wf = Application.WorksheetFunction
    temp = s
    L = Len(s)
    
    For i = 1 To L
        If Mid(temp, i, 1) Like "[0-9]" Then
        Else
            temp = wf.Replace(temp, i, 1, " ")
        End If
    Next i
    
    arr = Split(wf.Trim(temp), " ")
    For Each a In arr
        If Len(a) = 8 And Left(a, 1) = "1" Then
            NineD = a
            Exit Function
        End If
    Next a
End Function

enter image description here

User Defined Functions (UDFs) are very easy to install and use:

  1. ALT-F11 brings up the VBE window
  2. ALT-I ALT-M opens a fresh module
  3. paste the stuff in and close the VBE window

If you save the workbook, the UDF will be saved with it. If you are using a version of Excel later then 2003, you must save the file as .xlsm rather than .xlsx

To remove the UDF:

  1. bring up the VBE window as above
  2. clear the code out
  3. close the VBE window

To use the UDF from Excel:

=NineD(A1)

To learn more about macros in general, see:

http://www.mvps.org/dmcritchie/excel/getstarted.htm

и

http://msdn.microsoft.com/en-us/library/ee814735 (v = office.14) .aspx

, а подробные сведения о UDF см. В:

http://www.cpearson.com/excel/WritingFunctionsInVBA.aspx

Чтобы это работало, должны быть включены макросы!

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