Excel UDF для захвата чисел внутри символов

У меня есть переменное текстовое поле в ячейке A1, которое содержит следующее:

Текст;#Число;#Текст;#Число

  • Этот формат может повторяться, но шаблон всегда будет Text;#Number.
  • Числа могут варьироваться от 1 до n цифр (ограничение 7)

Пример:

Исходное значение

MyName;#123;#YourName;#3456;#HisName;#78

Требуемое значение:

123, 3456, 78

Насколько я понимаю, поле слишком переменное для формул Excel.

Я попытался использовать regexp, но я новичок, когда это приходит к кодированию. если вы можете разбить код с некоторым текстом пояснения, это было бы очень признательно.

Я попробовал некоторые из приведенных ниже предложений, и они отлично работают. Еще один вопрос.

Теперь, когда я могу отделить числа от текста, есть ли способ использовать приведенный ниже код и добавить еще один слой, где мы разделим числа на x ячеек.

Например: после запуска функции, если мы получим 1234, 567 в той же ячейке, функция поместит 1234 в ячейку B2 и 567 в ячейку C2. Это будет продолжать обновлять все ячейки в одной и той же строке до тех пор, пока строка не исчерпает все числа, полученные из функции.

Спасибо


person Ray    schedule 02.05.2016    source источник
comment
Какая часть примера 2 в это разве ты не понял?   -  person    schedule 03.05.2016
comment
Разделить на #, перебрать результат, проверяя, являются ли они числами   -  person John Coleman    schedule 03.05.2016
comment
Я попробовал некоторые из приведенных ниже предложений, и они отлично работают. Еще один вопрос. Теперь, когда я могу отделить числа от текста, есть ли способ использовать приведенный ниже код и добавить еще один слой, где мы разделим числа на x ячеек. Например: после запуска функции, если мы получим 1234, 567 в той же ячейке, функция поместит 1234 в ячейку B2 и 567 в ячейку C2. Это будет продолжать обновлять все ячейки в одной и той же строке до тех пор, пока строка не исчерпает все числа, полученные из функции.   -  person Ray    schedule 03.05.2016


Ответы (4)


Это метод, предложенный Джоном Коулманом:

Public Function GetTheNumbers(st As String) As String
    ary = Split(st, ";#")
    GetTheNumbers = ""

    For Each a In ary
        If IsNumeric(a) Then
            If GetTheNumbers = "" Then
                GetTheNumbers = a
            Else
                GetTheNumbers = GetTheNumbers & ", " & a
            End If
        End If
    Next a
End Function
person Gary's Student    schedule 02.05.2016

Если шаблон фиксирован, а расположение чисел никогда не меняется, вы можете предположить, что числа будут располагаться на четных местах в строке. Это означает, что в массиве, полученном в результате разбиения на исходную строку, можно использовать нечетные индексы результирующего массива. Например, в этой строке "Text;#Number;#Text;#Number" индексы массива 1, 3 будут числами ("Text(0);#Число(1);#Text(2);#Число(3)"). Я думаю, что этот метод проще и безопаснее использовать, если шаблон действительно фиксирован, поскольку он позволяет избежать необходимости проверки типов данных.

Public Function GetNums(src As String) As String
    Dim arr
    Dim i As Integer
    Dim result As String
    arr = Split(src, ";#") ' Split the string to an array.
    result = ""
    For i = 1 To UBound(arr) Step 2 ' Loop through the array, starting with the second item, and skipping one item (using Step 2).
        result = result & arr(i) & ", "
    Next
    If Len(result) > 2 Then
        GetNums = Left(result, Len(result) - 2) ' Remove the extra ", " at the end of the the result string.
    Else
        GetNums = ""
    End If
End Function
person dePatinkin    schedule 02.05.2016

Числа могут варьироваться от 1 до n цифр (не более 7)

Ни один из других ответов, похоже, не принимает во внимание предоставленные параметры, поэтому я собрал настоящий regex решение.

Option Explicit
Option Base 0    '<~~this is the default but I've included it because it has to be 0

Function numsOnly(str As String, _
                  Optional delim As String = ", ")
    Dim n As Long, nums() As Variant
    Static rgx As Object, cmat As Object

    'with rgx as static, it only has to be created once; beneficial when filling a long column with this UDF
    If rgx Is Nothing Then
        Set rgx = CreateObject("VBScript.RegExp")
    End If
    numsOnly = vbNullString

    With rgx
        .Global = True
        .MultiLine = False
        .Pattern = "[0-9]{1,7}"
        If .Test(str) Then
            Set cmat = .Execute(str)
            'resize the nums array to accept the matches
            ReDim nums(cmat.Count - 1)
            'populate the nums array with the matches
            For n = LBound(nums) To UBound(nums)
                nums(n) = cmat.Item(n)
            Next n
            'convert the nums array to a delimited string
            numsOnly = Join(nums, delim)
        End If
    End With
End Function

numsOnly

person Community    schedule 02.05.2016
comment
[regex] на конкретные вопросы, вероятно, можно ответить здесь. - person ; 03.05.2016
comment
Спасибо за ответ. Это работает отлично. Мне нужно освежить свои навыки регулярных выражений. - person Ray; 03.05.2016

Опция регулярного выражения, использующая Replace

Sub Test()
Debug.Print StrOut("MyName;#123;#YourName;#3456;#HisName;#78")
End Sub

функция

Option Explicit
Function StrOut(strIn As String) As String
Dim objRegex As Object
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
    .Pattern = "(^|.+?)(\d{1,7})"
    .Global = True
    If .Test(strIn) Then
        StrOut = .Replace(strIn, "$2, ")
        StrOut = Left$(StrOut, Len(StrOut) - 2)
    Else
        StrOut = "Nothing"
    End If
End With
End Function
person brettdj    schedule 03.05.2016
comment
Это тоже работает. Спасибо за ответ. Не могли бы вы предоставить разбивку того, как вы смогли разделить числа, используя этот метод, если можете. - person Ray; 03.05.2016