I've been looking for a while for a code that would give me the digits between without using regex (I want my macro to be used by anyone especially non-computer friendly people). This is a small part of a code creating series for a chart dynamically creating the chart etc.
Here is the type of data I am dealing with "C23H120N5O4Cl" so I'd like to save in a variable 23 then in another one 120 the rest should not matter (it could be nothing).
My digits will likely be between single characters (C,H,or else) but I need the numbers after C and H. So at the moment here is my code :
RangeOccupied = Range("C2").End(xlDown).row
For i = 1 To RangeOccupied
If i <> RangeOccupied Then
'Look for digits after C
pos = InStr(1, Cells(i + 1, 2), "C") + 1
pos1 = InStr(pos, Cells(i + 1, 2), "H")
NumC = Mid(Cells(i + 1, 2), pos, pos1 - pos)
'Look for digits after H
pos = InStr(1, Cells(i + 1, 2), "H") + 1
pos1 = InStr(pos, Cells(i + 1, 2), "O")
NumH = Mid(Cells(i + 1, 2), pos, pos1 - pos)
End If
Next
Ideally I'd like the pos1 numbers not to be dependent on a specific character but any character. i.e having pos1=InStr(pos,Cells(i+1,2),"ANY NON-NUMBER CHARACTER").
I do not know if it is possible without using regex.
This function will return an array of the digit strings in a text string
Option Explicit
Function myDigits(str As String) As String()
Dim col As Collection
Dim I As Long, S() As String
I = 0
Set col = New Collection
Do Until I > Len(str)
I = I + 1
If IsNumeric(Mid(str, I, 1)) Then
col.Add Val(Mid(str, I, Len(str)))
I = I + 1
Do Until Not IsNumeric(Mid(str, I, 1))
I = I + 1
Loop
End If
Loop
ReDim S(0 To col.Count - 1)
For I = 1 To col.Count
S(I - 1) = col(I)
Next I
myDigits = S
End Function
Okay, I'm absolutely certain there is a more efficient way of doing this. But I think the following example makes it fairly clear on one way to separate your values.
Option Explicit
Sub test()
Dim testValues() As String
Dim val1 As Long
Dim val2 As Long
testValues = Split("C23H120N5O4Cl,C23O120N5H4Cl,C4H120", ",")
Dim testValue As Variant
For Each testValue In testValues
ExtractValues testValue, val1, val2
Debug.Print "For " & testValue & ": " & val1 & " and " & val2
Next testValue
End Sub
Public Sub ExtractValues(ByVal inString As String, _
ByRef output1 As Long, _
ByRef output2 As Long)
Dim outString1 As String
Dim outString2 As String
Dim stage As String
stage = "Begin"
Dim thisCharacter As String
Dim i As Long
For i = 1 To Len(inString)
thisCharacter = Mid$(inString, i, 1)
Select Case stage
Case "Begin"
If thisCharacter = "C" Then stage = "First Value"
Case "First Value"
If (Asc(thisCharacter) >= Asc("0")) And _
(Asc(thisCharacter) <= Asc("9")) Then
outString1 = outString1 & thisCharacter
Else
'--- if we get here, we're done with this value
output1 = CLng(outString1)
'--- verify the next character is the "H"
If thisCharacter = "H" Then
stage = "Second Value"
Else
stage = "Next Value"
End If
End If
Case "Next Value"
If thisCharacter = "H" Then stage = "Second Value"
Case "Second Value"
If (Asc(thisCharacter) >= Asc("0")) And _
(Asc(thisCharacter) <= Asc("9")) Then
outString2 = outString2 & thisCharacter
Else
'--- if we get here, we're done with this value
output2 = CLng(outString2)
stage = "Finished"
Exit For
End If
End Select
Next i
If Not (stage = "Finished") Then
output2 = CLng(outString2)
End If
End Sub
Here's another method that's more generic and efficient than my first solution. This approach uses a function to extract the number following a given substring -- in this case it's a single letter "C" or "H". The function accounts for the value being at the end of the input value as well.
Option Explicit
Sub test()
Dim testValues() As String
Dim val1 As Long
Dim val2 As Long
testValues = Split("C23H120N5O4Cl,C23O120N5H4Cl,C4H120", ",")
Dim testValue As Variant
For Each testValue In testValues
val1 = NumberAfter(testValue, "C")
val2 = NumberAfter(testValue, "H")
Debug.Print "For " & testValue & ": " & val1 & " and " & val2
Next testValue
End Sub
Private Function NumberAfter(ByVal inString As String, _
ByVal precedingString As String) As Long
Dim outString As String
Dim thisToken As String
Dim foundThisToken As Boolean
foundThisToken = False
Dim i As Long
For i = 1 To Len(inString)
thisToken = Mid$(inString, i, 1)
If thisToken = precedingString Then
foundThisToken = True
ElseIf foundThisToken Then
If thisToken Like "[0-9]" Then
outString = outString & thisToken
Else
Exit For
End If
End If
Next i
NumberAfter = CLng(outString)
End Function
I found this solution from here Extract numbers from chemical formula
Public Function ElementCount(str As String, element As String) As Long
Dim i As Integer
Dim s As String
For i = 1 To 3
s = Mid(str, InStr(str, element) + 1, i)
On Error Resume Next
ElementCount = CLng(s)
On Error GoTo 0
Next i
End Function
Which works but if simple molecules like CH4 are put in it does not work since no number are shown... but I (we) can probably work that out.
Thanks again for all the solutions !
EDIT:
Here is the function I use that I think takes all possible scenarios into account ! Thanks again for your help !
Public Function ElementCount(str As String, element As String) As Long
Dim k As Integer
Dim s As String
For k = 1 To Len(str)
s = Mid(str, InStr(str, element) + 1, k)
On Error Resume Next
ElementCount = CLng(s)
On Error GoTo 0
If InStr(str, element) > 0 And ElementCount = 0 Then
ElementCount = 1
End If
Next k
End Function
EDIT
Changed the function to use and return dictionaries having keys of "C" and "H" paired with their numbers. Included a screenshot below.
Made sure it handles for tricky situations where multiple letters are packed ontop of each other:
Code:
Sub mainLoop()
Dim numbers As Scripting.Dictionary: Set numbers2 = New Scripting.Dictionary
For i = 1 To 5
Set numbers = returnDict(Cells(i, 1).Value)
printout numbers, i
Next
End Sub
Function returnDict(cellValue As String) As Scripting.Dictionary
Dim i As Integer: i = 1
Dim holder As String: holder = ""
Dim letter As String
Set returnStuff = New Scripting.Dictionary
While i < Len(cellValue)
If Mid(cellValue, i, 1) = "C" Or Mid(cellValue, i, 1) = "H" Then
i = i + 1
If IsNumeric(Mid(cellValue, i, 1)) Then
letter = (Mid(cellValue, i - 1, 1))
Do While IsNumeric(Mid(cellValue, i, 1))
holder = holder & Mid(cellValue, i, 1)
i = i + 1
If i > Len(cellValue) Then Exit Do
Loop
returnStuff.Add letter, holder
holder = ""
ElseIf Mid(cellValue, i, 1) <> LCase(Mid(cellValue, i, 1)) Then
returnStuff.Add Mid(cellValue, i - 1, 1), "1"
End If
Else
i = i + 1
End If
Wend
End Function
And heres a quick little function used to print out the contents of the dictionary
Sub printout(dict As Scripting.Dictionary, row As Integer)
Dim i As Integer: i = 2
For Each Key In dict.Keys
Cells(row, i).Value = Key & ": " & dict.Item(Key)
i = i + 1
Next
End Sub
My 2c:
Sub tester()
Dim r, arr, v
arr = Array("C", "Z", "Na", "N", "O", "Cl", "Br", "F")
For Each v In arr
Debug.Print v, ParseCount("C15H12Na2N5O4ClBr", v)
Next v
End Sub
Function ParseCount(f, s)
Const ALL_SYMBOLS As String = "Ac,Al,Am,Sb,Ar,As,At,Ba,Bk,Be,Bi,Bh,Br,Cd,Ca,Cf,Ce,Cs,Cl," & _
"Cr,Co,Cn,Cu,Cm,Ds,Db,Dy,Es,Er,Eu,Fm,Fl,Fr,Gd,Ga,Ge,Au,Hf,Hs,He,Ho,In,Ir,Fe,Kr,La,Lr," & _
"Pb,Li,Lv,Lu,Mg,Mn,Mt,Md,Hg,Mo,Mc,Nd,Ne,Np,Ni,Nh,Nb,No,Og,Os,Pd,Pt,Pu,Po,Pr,Pm,Pa,Ra," & _
"Rn,Re,Rh,Rg,Rb,Ru,Rf,Sm,Sc,Sg,Se,Si,Ag,Na,Sr,Ta,Tc,Te,Ts,Tb,Tl,Th,Tm,Sn,Ti,Xe,Yb,Zn," & _
"Zr,B,C,F,H,I,N,O,P,K,S,W,U,V,Y"
Dim atoms, rv, pos, i As Long
atoms = Split(ALL_SYMBOLS, ",")
rv = 0 'default return value
If IsError(Application.Match(s, atoms, 0)) Then
rv = -1 'not valid atomic symbol
Else
i = 1
pos = InStr(i, f, s, vbBinaryCompare)
If pos > 0 Then
If Len(s) = 2 Then
'should be a true match...
rv = ExtractNumber(f, pos + 2)
ElseIf Len(s) = 1 Then
'check for false positives eg "N" matches on "Na"
Do While pos > 0 And Mid(f, pos + 1, 1) Like "[a-z]"
i = pos + 1
pos = InStr(i, f, s, vbBinaryCompare)
Loop
If pos > 0 Then rv = ExtractNumber(f, pos + 1)
Else
'exotic chemistry...
End If
End If
End If
ParseCount = rv
End Function
'extract consecutive numeric digits from f starting at pos
' *returns 1 if no number present*
Function ExtractNumber(f, pos)
Dim rv, s, i As Long
Do While (pos + i) <= Len(f)
If Not Mid(f, pos + i, 1) Like "#" Then Exit Do
i = i + 1
Loop
ExtractNumber = IIf(i = 0, 1, Mid(f, pos, i))
End Function
Related
I have an array of numbers, once i "use" a number I want to remove using a specific index I have stored for that value.
I know there is no direct method but is there a way I work around this?
Example:
ShiftArray(1,25,12)
Pos = 1
Shiftarray(pos).delete
The array then should be = ShiftArray(1,12)
(I know such a method does not exist, just for clarity of intention's sake)
I tried the following but it gave me an error:
ShiftHeadsArray(pos - 1) = " "
StringUse = Application.WorksheetFunction.Trim(Join(ShiftHeadsArray, " "))
ShiftHeadsArray = Split(StringUse, " ")
Where pos is the position of the number I want to remove within the array.
Try this code
Sub Test()
Dim arr
arr = Array(1, 25, 12)
DeleteItem arr, 1
Debug.Print Join(arr, ", ")
End Sub
Sub DeleteItem(ByRef arr, v)
Dim a(), i As Long, n As Long, x As Long, y As Long
x = LBound(arr): y = UBound(arr)
ReDim a(x To y)
For i = x To y
If i <> v Then a(i - n) = arr(i) Else n = n + 1
Next i
If (y - n) >= x Then ReDim Preserve a(x To y - n)
arr = a
End Sub
Having a array-only based solution isn't so trivial, if you're interested in catching possible errors.
Remark: Instead of just returning an empty array or the input array like in this example, you should raise an error if the input isn't proper. But this depends on how you like the function to behave.
Public Sub Test()
'Some common tests:
Debug.Assert Join(RemoveItemByIndex(Array(), 1), "-") = vbNullString
Debug.Assert Join(RemoveItemByIndex(Array(1), 0), "-") = vbNullString
Debug.Assert Join(RemoveItemByIndex(Array(1), 1), "-") = vbNullString
Debug.Assert Join(RemoveItemByIndex(Array(1, 25, 12), 1), "-") = "1-12"
Debug.Assert Join(RemoveItemByIndex(Array(1, 25, 12), 10), "-") = "1-25-12"
Debug.Assert Join(RemoveItemByIndex(Array(1, 25, 12), -1), "-") = "1-25-12"
Debug.Assert Join(RemoveItemByIndex("foo", -1), "-") = vbNullString
'Your working sample:
Dim originalArray() As Variant
originalArray = Array(1, 25, 12)
Dim item As Variant
For Each item In RemoveItemByIndex(originalArray, 1)
Debug.Print item
Next item
End Sub
Public Function RemoveItemByIndex(ByVal arrayToWorkOn As Variant, ByVal indexToRemove As Long) As Variant()
RemoveItemByIndex = Array()
If Not IsArray(arrayToWorkOn) Then Exit Function
If Not IsArrayInitialized(arrayToWorkOn) Then Exit Function
If UBound(arrayToWorkOn) - LBound(arrayToWorkOn) = 0 Then Exit Function
RemoveItemByIndex = arrayToWorkOn
If indexToRemove < LBound(arrayToWorkOn) _
Or indexToRemove > UBound(arrayToWorkOn) Then Exit Function
ReDim resultingArray(UBound(arrayToWorkOn) - 1) As Variant
Dim index As Long
Dim resultingIndex As Long
For index = LBound(arrayToWorkOn) To UBound(arrayToWorkOn): Do
If index = indexToRemove Then Exit Do
resultingArray(resultingIndex) = arrayToWorkOn(index)
resultingIndex = resultingIndex + 1
Loop While False: Next index
RemoveItemByIndex = resultingArray
End Function
Public Function IsArrayInitialized(ByVal arrayToWorkOn As Variant) As Boolean
On Error Resume Next
IsArrayInitialized = IsArray(arrayToWorkOn) And _
Not IsError(LBound(arrayToWorkOn, 1)) And _
LBound(arrayToWorkOn, 1) <= UBound(arrayToWorkOn, 1)
End Function
Regarding the : Do and Loop While False:: This is a neat trick to simulate a 'continue'.
See here for more information: VBA - how to conditionally skip a for loop iteration
Remove Array Item by Index
Option Explicit
Sub TESTremoveArrayItemByIndex()
Dim Addresses As Variant: Addresses = Array("A1", "A2", "A3")
Dim Values As Variant: Values = Array(1, 25, 10)
Dim mIndex As Variant
mIndex = Application.Match(Application.Max(Values), Values, 0)
Dim dAddress As String: dAddress = Application.Index(Addresses, mIndex)
' If you are sure that 'Addresses' is zero-based, instead of the previous
' line you can do:
'Dim cAddress As String: cAddress = Addresses(Index - 1)
removeArrayItemByIndex Addresses, mIndex
Debug.Print "Addresses(After): " & Join(Addresses, ",")
removeArrayItemByIndex Values, mIndex
Debug.Print "Values(After): " & Join(Values, ",")
End Sub
Sub TESTremoveArrayItemByIndexDebugPrint()
Dim Addresses As Variant: Addresses = Array("A1", "A2", "A3")
Debug.Print "Addresses(Before): " & Join(Addresses, ",")
Dim Values As Variant: Values = Array(1, 25, 10)
Debug.Print "Values(Before): " & Join(Values, ",")
Dim mIndex As Variant
mIndex = Application.Match(Application.Max(Values), Values, 0)
Debug.Print "Maximum Index: " & mIndex
Dim dAddress As String: dAddress = Application.Index(Addresses, mIndex)
' If you are sure that 'Addresses' is zero-based, instead of the previous
' line you can do:
'Dim cAddress As String: cAddress = Addresses(Index - 1)
Debug.Print "Delete Address: " & dAddress
removeArrayItemByIndex Addresses, mIndex
Debug.Print "Addresses(After): " & Join(Addresses, ",")
removeArrayItemByIndex Values, mIndex
Debug.Print "Values(After): " & Join(Values, ",")
End Sub
Sub removeArrayItemByIndex( _
ByRef arr As Variant, _
ByVal Index As Long)
Dim n As Long
For n = Index + LBound(arr) - 1 To UBound(arr) - 1
arr(n) = arr(n + 1)
Next n
ReDim Preserve arr(LBound(arr) To n - 1)
End Sub
A separate program that I cannot change adds to a spreadsheet and sometimes it duplicates something.
For example:in cell 5, 3
ABC, vbd, S19M-0027757-27760, S19M-0027757-27760(1)
or it could be
ABC, vbd S19M-0027757-27760, S19M-0027757-27760(1)
What I need to do is replace both of them with S19M-0027757-27760(1) so the out come would be:
ABC, vbd, S19M-0027757-27760(1)
So far I have:
For i = 5 To lRow
inputArray = Split(Cells(i, 3).Value, " ")
For j = 0 To (UBound(inputArray) - LBound(inputArray) - 1)
Dim firstString As String
Dim secondString As String
firstString = inputArray(j)
secondString = inputArray(j + 1)
Next
Next
I am thinking the next step would be to compare letter by letter? But what about the comma and (1)?
Try this. Possibly not enough examples to be sure it will work in all cases, but a short test worked.
Sub x()
Dim i As Long, inputArray, j As Long, outputArray(), k As Long
For i = 1 To 3
inputArray = Split(Cells(i, 3).Value, ", ")
For j = LBound(inputArray) To UBound(inputArray)
k = k + 1
ReDim Preserve outputArray(1 To k)
If j = UBound(inputArray) - 1 Then
If inputArray(j + 1) Like inputArray(j) & "(*)" Then
outputArray(k) = inputArray(j + 1)
Exit For
Else
outputArray(k) = inputArray(j)
End If
Else
outputArray(k) = inputArray(j)
End If
Next j
Cells(i, 4).Value = Join(outputArray, ", ")
Erase outputArray: k = 0
Next i
End Sub
Some other way, possible through RegEx:
Sub Test()
Dim RegEx As Object: Set RegEx = CreateObject("VBScript.RegExp")
RegEx.Global = True
RegEx.Pattern = "([A-Z0-9-]{18})(?=.+\1)"
Dim lr As Long, x As Long
With Sheet1
lr = .Cells(.Rows.Count, 3).End(xlUp).Row
For x = 5 To lr
.Cells(x, 3).Value = Replace(Replace(RegEx.Replace(.Cells(x, 3).Value, ""), ", ,", ", "), " ,", ", ")
Next x
End With
End Sub
I agree with #SJR, some more examples would be great to know if the RegEx.Pattern would hold TRUE. I now went with the assumptions of 18-char patterns. It would hold for the current sample data:
Before:
After:
I have the following Excel sheet which has random number combinations build using numbers from 2 to 50 in set of 3, 2 and 1 in Column A.
I am trying to build whole possible combinations between Column A elements such that the obtained combination doesn't have any repeating numbers in them and contains all the number from 2 to 50.
My current code starts from A2 and builds only a single combination set. It doesn't evaluate other possible combinations with starting element as in A2, it then goes to A3 and then builds only one combination set using A3. This step continues for A4,A5...
This is my current code.
Private Sub RP()
Dim lRowCount As Long
Dim temp As String, s As String
Dim arrLength As Long
Dim hasElement As Boolean
Dim plans() As String, currentPlan() As String
Dim locationCount As Long
Dim currentRoutes As String
Dim line As Long
Worksheets("Sheet1").Activate
Application.ActiveSheet.UsedRange
lRowCount = ActiveSheet.UsedRange.Rows.Count
locationCount = -1
line = 2
Debug.Print ("*********")
For K = 2 To lRowCount - 1
currentRoutes = ""
For i = K To lRowCount
s = ActiveSheet.Cells(i, 1)
Do
temp = s
s = Replace(s, " ", "")
Loop Until temp = s
currentPlan = Split(Trim(s), ",")
arrLength = UBound(currentPlan) - LBound(currentPlan) + 1
hasElement = False
If Len(Join(plans)) > 0 Then
For j = 0 To arrLength - 1
pos = Application.Match(currentPlan(j), plans, False)
If Not IsError(pos) Then
hasElement = True
Exit For
End If
Next j
End If
If Not hasElement Then
currentRoutes = currentRoutes & (Join(currentPlan, ",")) & " "
If Len(Join(plans)) > 0 Then
plans = Split(Join(plans, ",") & "," & Join(currentPlan, ","), ",")
Else
plans = currentPlan
End If
End If
Next i
If locationCount < 0 Then
locationCount = UBound(plans) - LBound(plans) + 1
End If
If (UBound(plans) - LBound(plans) + 1) < locationCount Then
Debug.Print ("Invalid selection")
Else
Debug.Print (Trim(currentRoutes))
Worksheets("Sheet1").Cells(line, 11) = currentRoutes
line = line + 1
End If
Erase plans
Debug.Print ("*********")
Next K
End Sub
I am looking for a formula to list occurrences of values only if they are greater than 2 times; and the result would be shown as in the image.
For example, if a value repeats 2 times, it's shown by "2", and 3 times by "3". so if there are two numbers repeating in the range, then it would be shown by "32" as in the image below. (There is no need for a comma between the numbers). Thanks.
Here is a simple UDF:
Function mycount(rng As Range) As String
Dim str As String
Dim rngcnt As Range
For Each rngcnt In rng
If InStr("," & str & ",", "," & rngcnt.Value & ",") = 0 Then
If Application.WorksheetFunction.CountIf(rng, rngcnt) > 1 Then
mycount = mycount & Application.WorksheetFunction.CountIf(rng, rngcnt)
str = str & "," & rngcnt
End If
End If
Next rngcnt
End Function
So your call on the sheet would be:
=mycount(A2:H2)
Then copy down.
The way I got it is defining a VBA function.This function uses a dictionary, so it is necessary to add th reference to 'Microsoft Scripting Runtime' (look here). Also, I have used a function to sort the characters in string from here
Function Repetitions(rng As Range)
Dim dict As New Scripting.Dictionary
Dim res() As Integer
For aux = 1 To rng.Count
Dim numero As Integer
numero = rng.Cells(1, aux).Value
If Not dict.Exists(numero) Then
dict.Add numero, 1
Else
dict(numero) = dict(numero) + 1
End If
Next aux
Dim result As String
result = ""
For aux = 0 To UBound(dict.Items)
If dict.Items(aux) > 1 Then result = result & dict.Items(aux)
Next aux
While Len(result)
iTemp = 1
Temp = Left(result, 1)
For I = 2 To Len(result)
If StrComp(Mid(result, I, 1), Temp, vbTextCompare) = 0 Then
If StrComp(Mid(result, I, 1), Temp, vbBinaryCompare) = 1 Then
Temp = Mid(result, I, 1)
iTemp = I
End If
End If
If StrComp(Mid(result, I, 1), Temp, vbTextCompare) = 1 Then
Temp = Mid(result, I, 1)
iTemp = I
End If
Next I
Repetitions = Repetitions & Temp
result = Left(result, iTemp - 1) & _
Mid(result, iTemp + 1)
Wend
End Function
After all, you will be able to use the function as formula in Excel, calling it as following for example:
=Repetitions(A2:F2)
I am facing problem when receiving a long message as below
40=1.22.50=0.002.60=35.
The system use the dot as separator while there is also decimal values for numeric value.
The desired output is
40=1.22
50=0.002
60=35
I am now using manual way to format the message. Hope to have a better way to overcome this.
Assuming you have one dot "." as the decimal position, and another "." that separates each element in the array. You can use the code below to read all values of the Long string into an array (Nums is the name of the array).
Option Explicit
Sub Seperate_DecimNumbers()
Dim Nums As Variant
Dim FullStr As String
Dim DotPosition As Integer
Dim i As Integer
' init array size to a large size , will redim it at the end to number of elements found
ReDim Nums(1 To 100)
FullStr = "40=1.22.50=0.002.60=35."
i = 1 ' init array elements counter
Do Until Len(FullStr) = 0
' call FindN function , searching for the 2nd "."
DotPosition = FindN(FullStr, ".", 2)
' unable to find 2 "." in the string >> last element in the array
If DotPosition = 0 Then
Nums(i) = FullStr
Exit Do
Else ' was able to find 2 "." in the string
Nums(i) = Left(FullStr, DotPosition - 1)
End If
i = i + 1
FullStr = Right(FullStr, Len(FullStr) - DotPosition)
Loop
' redim array back to maximum of numbers found in String
ReDim Preserve Nums(1 To i)
' place output start location from Range A2 and below (till number of elements in the array)
Range("A1").Offset(1, 0).Resize(UBound(Nums), 1).Value = Application.Transpose(Nums)
End Sub
Function FindN(sInputString As String, sFindWhat As String, N As Integer) As Integer
' this function find the Nth position of a certain character in a string
Dim J As Integer
Application.Volatile
FindN = 0
For J = 1 To N
FindN = InStr(FindN + 1, sInputString, sFindWhat)
If FindN = 0 Then ' unable to find the 2nd "." >> last appearance
Exit For
End If
Next
End Function
See result below:
Here's my take on the answer, which splits things on the = rather than the .. Doing it this way allows for input such as 40=1.22.50=0.002.60=35.70=120. (i.e. the part to the right of an = does not have to contain a ., it could be an integer.)
Sub SplitDotEqual()
Dim s As String
Dim a() As String
Dim i As Integer
Dim d As Integer
'Read from A1
s = Range("A1").Value
'Split on the "="
a = Split(s & ".", "=") ' include an extra "." to ensure that
' the final field is ended
For i = 0 To UBound(a) - 1
'Put the "=" back
a(i) = a(i) & "="
'Find the last "." before the next "="
d = InStrRev(a(i + 1), ".")
'Append everything prior to the "."
a(i) = a(i) & Left(a(i + 1), d - 1)
'Write to A2:Ax
Cells(i + 2, 1).Value = a(i)
'Strip off everything prior to the ".",
'leaving just the stuff prior to the "="
a(i + 1) = Mid(a(i + 1), d + 1)
Next
End Sub
Let's assume that every other dot is a separator. This code changes the odd-numbered dots into pipes and then parses on the pipes:
Sub parser()
Dim FlipFlop As Boolean, dot As String, pipe As String
Dim s As String, L As Long, i As Long, CH As String
dot = "."
pipe = "|"
s = Range("A1").Value
L = Len(s)
FlipFlop = True
For i = 1 To L
CH = Mid(s, i, 1)
If CH = dot Then
If FlipFlop Then
Else
Mid(s, i, 1) = pipe
End If
FlipFlop = Not FlipFlop
End If
Next i
msg = s & vbCrLf
ary = Split(s, pipe)
For Each a In ary
msg = msg & vbCrLf & a
Next a
MsgBox msg
End Sub
got more closer message and the code partially works.
8=TEST.1.2.9=248.35=D.49=MMUIJ.56=FGTUH.34=32998.50=MMTHUJ.57=AY/ABCDE.52=20161216-07:58:07.11=00708991.1=A-12345-