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-
Related
I'm trying to cut out a part of a cell value.
This is how it should look:
So far I got this:
For Each item In arr
pos = InStr(item, "No")
If pos > 0 Then
ActiveSheet.Range("B" & row).Value = item
row = row + 1
Else
ActiveSheet.Range("B" & row).Value = " N/A "
row = row + 1
End If
This returns me the rows but i still need to cut out the Values
-----Update-----
This is what i have now:
Sub cut()
Call Variables
Dim arr() As Variant
Dim element As Variant
Dim element2 As Variant
Dim rows As Integer
Dim rows2 As Integer
arr = Array("test352532_No223", _
"testfrrf43tw_No345figrie_ge", _
"test123_No32_fer", _
"test_Nhuis34", _
"teftgef_No23564.345")
With ThisWorkbook.Worksheets("Numbers").Activate
rows = 1
rows2 = 1
For Each element In arr
Range("A" & rows).Value = element
With regEx
.Pattern = "(No[1-9][\.\d]+[a-z]?)"
Set mc = regEx.Execute(element)
For Each element2 In mc
ActiveSheet.Range("B" & rows2).Value = element2
rows2 = rows2 + 1
Next element2
End With
rows = rows + 1
Next element
End With
End Sub
And this is what it results:
So the problem is, that the Value in B4 should be in B5...
Formula:
Formula in B1:
=IFERROR("No"&-LOOKUP(1,-MID("_"&SUBSTITUTE(A1,".","|"),FIND("_No","_"&A1)+3,ROW($1:$99))),"")
Notes:
Add leading _ to allow for match at start of string;
FIND() is case-sensitive;
SUBSTITUTE() out the dot to prevent longer match with FIND();
The above will not work well when 1st digit after No is a zero.
VBA:
If VBA is a must, try an UDF, for example:
Function GetNo(s As String) As String
With CreateObject("vbscript.regexp")
.Pattern = "^(?:.*?_)?(No\d+)?.*$"
GetNo = .Replace(s, "$1")
End With
End Function
On your worksheets in B1, invoke through typing =GetNo(A1).
Here I used regular expressions to 'cut' the substring you are after. See an online demo. The pattern means:
^ - Start-line anchor;
(?:.*?_)? - Optional non-capture group to match 0+ (Lazy) characters upto underscore. This would also allow No at start of string;
(No\d+)? - Optional capture group to match No (case-sensitive) followed by 1+ digits;
.* - 0+ Characters;
$ - End-line anchor.
EDIT: You can also call the function in your VBA-project:
Sub Test()
arr = Range("A1:A5").Value
For x = LBound(arr) To UBound(arr)
arr(x, 1) = GetNo(CStr(arr(x, 1)))
Next
Range("B1").Resize(UBound(arr)).Value = arr
End Sub
Please, test the next function:
Function extractNoStr(x As String) As String
Dim frst As Long, last As Long, i As Long
frst = InStr(1, x, "No", vbBinaryCompare)
For i = frst + 2 To Len(x)
If Not IsNumeric(Mid(x, i, 1)) Then last = i: Exit For
Next i
If i > Len(x) And last = 0 Then last = Len(x) + 1
extractNoStr = Mid(x, frst, last - frst)
End Function
It can be tested as:
Sub testExtractNoStr()
Dim x As String
x = "test2345_No345figrie_ge"
Debug.Print extractNoStr(x)
Debug.Print activeCell.value 'select a cell containing such a string...
End Sub
To process all range of column A:A, returning in B:B, please use the next code:
Sub extractAll()
Dim sh As Worksheet, lastR As Long, arr, arrFin, i As Long
Set sh = ActiveSheet
lastR = sh.Range("A" & sh.rows.count).End(xlUp).row
arr = sh.Range("A1:A" & lastR).Value2 'place the range in an array for faster processing
ReDim arrFin(1 To UBound(arr), 1 To 1) 'ReDim the final array to receive all occurrences
For i = 1 To UBound(arr)
arrFin(i, 1) = extractNoStr(CStr(arr(i, 1)))
Next i
'drop the processed array content, at once:
sh.Range("B1").Resize(UBound(arrFin), 1).Value2 = arrFin
End Sub
Using a Macro or Formula, is there a way to achieve the result of the following formula of Office 365?
=FILTER(B:B,A:A = "x")
What it does is get all the values from Column B if Column A on the same row has a value of x.
My PC has office 365 but the one I'm working with only has Office Pro Plus 2019. I had to use my pc when I needed the function and I'm getting tired of it, maybe it can be done on Office Pro Plus 2019 too using a formula or a macro?
Use:
=IFERROR(INDEX($B$1:$B$100,AGGREGATE(15,7,ROW($A$1:$A$100)/($A$1:$A$100="x"),ROW($ZZ1))),"")
Note the use of a set range and not full columns. That is done on purpose, This being an array formula it will do a lot of calculations each cell it is placed. Limiting the range to the data set will speed it up.
Put this in the first cell of the output and copy down till blanks are returned.
I had some spare time and I am recently interested in User defined functions so I decided to make my own version of what I imagine this would be. I'm prefacing this by saying its not good and is excessively long but it works!
Function JOINIF(ByRef IfRange As Range, ByVal Criteria As String, Optional JoinRange As Range, Optional Delimeter As String = ",") As String
'IfRange is the range that will be evaluated by the Criteria
'Criteria is a logical test that can be applied to a cell value.
'Examples of Criteria: "=Steve", ">100", "<>Toronto", "<=-1"
'JoinRange is the range of values that will be concatenated if the corresponding -
'IfRange cell meets the criteria. JoinRange can be left blank if the values to be -
'concatenated are the IfRange values.
'Delimeter is the string that will seperate the concatenated values.
'Default delimeter is a comma.
Dim IfArr() As Variant, JoinArr() As Variant, OutputArr() As String
Dim IfArrDim As Integer, JoinArrDim As Integer
Dim JCount As Long, LoopEnd(1 To 2) As Long
Dim MeetsCriteria As Boolean, Expression As String
Dim i As Long, j As Long
'PARSING THE CRITERIA
Dim Regex As Object
Set Regex = CreateObject("VBScript.RegExp")
Regex.Pattern = "[=<>]+"
'Looking for comparison operators
Dim Matches As Object
Set Matches = Regex.Execute(Criteria)
If Matches.Count = 0 Then
'If no operators found, assume default "Equal to"
If Not IsNumeric(Criteria) Then
'Add quotation marks to allow string comparisons
Criteria = "=""" & Criteria & """"
End If
Else
If Not IsNumeric(Replace(Criteria, Matches(0), "")) Then
Criteria = Matches(0) & """" & Replace(Criteria, Matches(0), "") & """"
End If
'Add quotation marks to allow string comparisons
End If
'Trim IfRange to UsedRange
Set IfRange = Intersect(IfRange, IfRange.Parent.UsedRange)
'Default option for optional JoinRange input
If JoinRange Is Nothing Then
Set JoinRange = IfRange
Else
Set JoinRange = Intersect(JoinRange, JoinRange.Parent.UsedRange)
End If
'DIMENSIONS
'Filling the arrays
If IfRange.Cells.Count > 1 Then
IfArr = IfRange.Value
IfArrDim = Dimensions(IfArr)
Else
ReDim IfArr(1 To 1)
IfArr(1) = IfRange.Value
IfArrDim = 1
End If
If JoinRange.Cells.Count > 1 Then
JoinArr = JoinRange.Value
JoinArrDim = Dimensions(JoinArr)
Else
ReDim JoinArr(1 To 1)
JoinArr(1) = JoinRange.Value
JoinArrDim = 1
End If
'Initialize the Output array to the smaller of the two input arrays.
ReDim OutputArr(IIf(IfRange.Cells.Count < JoinRange.Cells.Count, IfRange.Cells.Count - 1, JoinRange.Cells.Count - 1))
'DEFINING THE LOOP PARAMETERS
'Loop ends on the smaller of the two arrays
If UBound(IfArr) > UBound(JoinArr) Then
LoopEnd(1) = UBound(JoinArr)
Else
LoopEnd(1) = UBound(IfArr)
End If
If IfArrDim = 2 Or JoinArrDim = 2 Then
If Not (IfArrDim = 2 And JoinArrDim = 2) Then
'mismatched dimensions
LoopEnd(2) = 1
ElseIf UBound(IfArr, 2) > UBound(JoinArr, 2) Then
LoopEnd(2) = UBound(JoinArr, 2)
Else
LoopEnd(2) = UBound(IfArr, 2)
End If
End If
'START LOOP
If IfArrDim = 1 Then
For i = 1 To LoopEnd(1)
If IsNumeric(IfArr(i)) And IfArr(i) <> "" Then
Expression = IfArr(i) & Criteria
Else
'Add quotation marks to allow string comparisons
Expression = """" & IfArr(i) & """" & Criteria
End If
MeetsCriteria = Application.Evaluate(Expression)
If MeetsCriteria Then
If JoinArrDim = 1 Then
OutputArr(JCount) = CStr(JoinArr(i))
Else
OutputArr(JCount) = CStr(JoinArr(i, 1))
End If
JCount = JCount + 1
End If
Next i
Else
For i = 1 To LoopEnd(1)
For j = 1 To LoopEnd(2)
If IsNumeric(IfArr(i, j)) And IfArr(i, j) <> "" Then
Expression = IfArr(i, j) & Criteria
Else
'Add quotation marks to allow string comparisons
Expression = """" & IfArr(i, j) & """" & Criteria
End If
MeetsCriteria = Application.Evaluate(Expression)
If MeetsCriteria Then
If JoinArrDim = 1 Then
OutputArr(JCount) = CStr(JoinArr(i))
Else
OutputArr(JCount) = CStr(JoinArr(i, j))
End If
JCount = JCount + 1
End If
Next j
Next i
End If
'END LOOP
ReDim Preserve OutputArr(JCount + 1 * (JCount > 0))
JOINIF = Join(OutputArr, Delimeter)
End Function
Private Function Dimensions(var As Variant) As Long
'Credit goes to the great Chip Pearson, chip#cpearson.com, www.cpearson.com
On Error GoTo Err
Dim i As Long, tmp As Long
While True
i = i + 1
tmp = UBound(var, i)
Wend
Err:
Dimensions = i - 1
End Function
Examples of it in use:
Seperate IfRange and JoinRange
IfRange as the JoinRange
You might try the following udf (example call: FILTER2(A1:A100,B1:B100)) consisting of the following tricky steps:
a) Evaluate the general condition (=If(A1:A100="x",Row(A1:A100),"?") as tabular Excel formula and assign all valid row numbers to array x (marking the rest by "?" strings),
b) Filter out all "?" elements
c) Apply x upon the data column benefitting from the advanced restructuring features of Application.Index()
Public Function Filter2(rng1 As Range, rng2 As Variant, Optional ByVal FilterID As String = "x")
Dim a As String: a = rng1.Address(False, False, External:=True)
'a) get all valid row numbers (rng1)
Dim myformula As String: myformula = "if(" & a & "=""" & FilterID & """,row(" & a & "),""?"")"
Dim x: x = Application.Transpose(Evaluate(myformula))
'b) filter out invalid "?" elements
x = VBA.Filter(x, "?", False)
'c) apply x upon data column (rng2)
If UBound(x) > -1 Then Filter2 = Application.Index(rng2, Application.Transpose(x), 1)
End Function
Note that function calls before versions 2019/MS 365 need to be entered as array formula (Ctrl+Shift+Enter).
The function assumes one-column (range) arguments.
Edit due to comment as of 2022-06-08
The whole example is based on the actual row numbers starting in the first row (OP ranges refer to A:A,B:B. If you want to allow ranges to start at any row, you'd need to change the myFormula definition in section a) by correcting the row indices by subtracting possible offsets (row number + 1 - first row):
Dim myFormula As String
myFormula = "if(" & a & "=""" & FilterID & """,row(" & a & ")+1 -" & rng1.Row & ",""?"")"
Try this UDF for the Filter Function:
Function FILTER_HA(Where, Criteria, Optional If_Empty) As Variant
Dim Data, Result
Dim i As Long, j As Long, k As Long
'Create space for the output (same size as input cells)
With Application.Caller
i = .Rows.Count
j = .Columns.Count
End With
'Clear
ReDim Result(1 To i, 1 To j)
For i = 1 To UBound(Result)
For j = 1 To UBound(Result, 2)
Result(i, j) = ""
Next
Next
'Count the rows to show
For i = 1 To UBound(Criteria)
If Criteria(i, 1) Then j = j + 1
Next
'Empty?
If j < 1 Then
If IsMissing(If_Empty) Then
Result(1, 1) = CVErr(xlErrNull)
Else
Result(1, 1) = If_Empty
End If
GoTo ExitPoint
End If
'Get all data
Data = Where.Value
'Copy the rows to show
For i = 1 To UBound(Data)
If Criteria(i, 1) Then
k = k + 1
For j = 1 To UBound(Data, 2)
Result(k, j) = Data(i, j)
Next
End If
Next
'Return the result
ExitPoint:
FILTER_HA = Result
End Function
I want to make a function where I extract all words with length = 2 from a sentence. For example, if the sentence is "The Cat is brown", I want the result in the cell to be "is". If there are multiple words with length = 2, I want to keep these too. I have tried MID, RIGHT, LEFT, etc. These does not work as the position of the word is not always identical.
I have no clue how to do this in VBA, any suggestions are welcome :)
Thanks
I have made you a UDF which should work for what you want. You use it like so:
=ExtractWords(Cell to check, Optional number of letters)
By default it will check for 2 letter words but you can specify as well as shown above.
Here is the code. Place it into a module
Function ExtractWords(Cell As Range, Optional NumOfLetters As Integer)
Dim r As String, i As Long, CurrentString As String, FullString As String, m As String
If NumOfLetters = 0 Then NumOfLetters = 2
r = Cell.Value
For i = 1 To Len(r)
m = Mid(r, i, 1)
If Asc(UCase(m)) >= 65 And Asc(UCase(m)) <= 90 Or m = "-" Or m = "'" Then 'Accepts hyphen or single quote as part of the word
CurrentString = CurrentString & m
If i = Len(r) Then GoTo CheckLastWord
Else
CheckLastWord:
If Len(CurrentString) = NumOfLetters Then
If FullString = "" Then
FullString = CurrentString
Else
FullString = FullString & " " & CurrentString 'Change space if want another delimiter
End If
End If
CurrentString = ""
End If
Next i
If FullString = "" Then
ExtractWords = "N/A" 'If no words are found to contain the length required
Else
ExtractWords = FullString
End If
End Function
There are probably other ways to do it that may be easier or more efficient. This is just something I came up with.
Double Upper Case Occurrences
In Excel you can e.g. use it like this:
=getDUC(A1)
=getDUC(A1," ")
=getDUC(A1,",")
=getDUC(A1,"-")
The Code
Option Explicit
' In Excel:
Function getDUC( _
ByVal s As String, _
Optional ByVal Delimiter As String = ", ") _
As String
Dim arr As Variant
arr = DoubleUCaseToArray(s)
getDUC = Join(arr, Delimiter)
End Function
' In VBA:
Sub testDoubleUCaseToArray()
Dim CCodes As Variant: CCodes = Array("US,UKUs", "UkUS,UK", "kUSUKsUK")
Dim arr As Variant
Dim n As Long
For n = LBound(CCodes) To UBound(CCodes)
arr = DoubleUCaseToArray(CCodes(n))
Debug.Print Join(arr, ",")
Next n
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: From a specified string, returns all unique double upper case
' occurrences in a 1D (zero-based) array.
' Remarks: From the string 'USUk' it returns only 'US' (not `SU`).
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function DoubleUCaseToArray( _
ByVal s As String) _
As Variant
If Len(s) > 1 Then
With CreateObject("Scripting.Dictionary")
Dim cFirst As String * 1
Dim cSecond As String * 1
Dim n As Long
For n = 1 To Len(s) - 1
cFirst = Mid(s, n, 1)
If cFirst Like "[A-Z]" Then
cSecond = Mid(s, n + 1, 1)
If cSecond Like "[A-Z]" Then
.Item(cFirst & cSecond) = Empty
End If
n = n + 1
End If
Next n
If .Count > 0 Then
DoubleUCaseToArray = .Keys
End If
End With
End If
End Function
I am writing a very simple vba code that is designed to iterate through the letters/numbers in each cell in row 2 and only keep the numbers in the beginning. Each cell starts with between 4 and 7 numbers, and then will be followed by either a letter (1 or more), a . and a number, or an underscore and a letter and a number.
The issue I am having is that my code is only returning the correct values for some of the cells. Only the cells that have a . are cleaned correctly. The ones with the underscore delete everything after the _, but keep the _ itself and the cells with letters keep the letters but delete the . and anything after it.
This is my code:
Sub getIDs()
Dim counter As Integer
counter = 1
Dim rowCounter As Integer
rowCounter = 2
Dim original As String
original = ""
Dim newText As String
newText = ""
Do While Len(Cells(rowCounter, 2)) > 0
Do While counter <= Len(Cells(rowCounter, 2))
If Not IsNumeric((Mid(Cells(rowCounter, 2).Value, counter, 1))) Or Mid(Cells(rowCounter, 2).Value, counter, 1) = "_" Then
Exit Do
Else
counter = counter + 1
End If
Loop
newText = Left(Cells(rowCounter, 2), counter)
Cells(rowCounter, 2) = newText
rowCounter = rowCounter + 1
Loop
End Sub
Examples: The original cells contain these four types of info (numbers vary):
Input Desired output Actual output Actual output OK?
----------------|-----------------|--------------|-------------------------
12345_v2.jpg 12345 12345_ No, "_" should be removed
293847.psd 293847 293847 OK
82364382.1.tga 82364382 82364382 OK
172982C.5.tga 172982 172982C No, "C" should be removed
So I found two problems with your code. The first that counter, really needs to be counter-1 when you set new text since that is the position of the non-numeric or underscore character. Copying at the counter point will give you an extra character.
The second issue is that you need to reset the counter variable outside of the inner Do loop, otherwise you will start at the position of the previous last found character. Try this.
Sub getIDs()
Dim counter As Integer
counter = 1
Dim rowCounter As Integer
rowCounter = 2
Dim original As String
original = ""
Dim newText As String
newText = ""
Do While Len(Cells(rowCounter, 2)) > 0
counter = 1
Do While counter <= Len(Cells(rowCounter, 2))
If Not IsNumeric((Mid(Cells(rowCounter, 2).Value, counter, 1))) Or Mid(Cells(rowCounter, 2).Value, counter, 1) = "_" Then
Exit Do
Else
counter = counter + 1
End If
Loop
newText = Left(Cells(rowCounter, 2), counter - 1)
Cells(rowCounter, 2) = newText
rowCounter = rowCounter + 1
Loop
End Sub
This will remove dots and underscores.
I have to run; no time to implement removing letters. But this should put you on the right track. I may continue tomorrow.
Sub lkjhlkjh()
Dim s As String
Dim iUnderscore As Long
Dim iDot As Long
Dim iCut As Long
s = Sheet1.Cells(1, 1)
iUnderscore = InStr(s, "_")
iDot = InStr(s, ".")
If iUnderscore = 0 Then
If iDot = 0 Then
'Don't cut
Else
iCut = iDot
End If
Else
If iDot = 0 Then
iCut = iUnderscore
Else
If iDot > iUnderscore Then
iCut = iUnderscore
Else
iCut = iDot
End If
End If
End If
If iCut > 0 Then s = Left(s, iCut - 1)
Sheet1.Cells(1, 1) = s
End Sub
I am reading in information from a .txt file, This text file has 2 row and 6 column; each element is separated by space or tab. I have the data to read all the strings but I find difficult in putting the data to the cells. How can I find end of first Row.
Text File:
$SUBCASE 1 1
$DISP 0 509 5 1 2
Below is the complete code, I'm getting only the first character string and rest not...
Private Sub PCH_Click()
Dim arTemp() As Variant
Dim lRet As String
Dim sVal As String
Dim Row As Long
Dim Col As Long
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
'Default method Uses Open Dialog To Show the Files
lRet = Application.GetOpenFilename("PCH files (*.pch), *.*")
'Reads the file into characters
sVal = OpenTextFileToString2(lRet)
Dim tmp As Variant
tmp = SplitMultiDelims(sVal, ",;$ ", True) ' Place the 2nd argument with the list of delimiter you need to use
Row = 0
For i = LBound(tmp, 1) To UBound(tmp, 1)
Row = Row + 1
Col = 1
While Not vbNewLine = ""
ws.Cells(Row, Col) = tmp(i) 'output on the first column
MsgBox (tmp(i))
Col = Col + 1
Wend
Next i
End Sub
Function OpenTextFileToString2(ByVal strFile As String) As String
' RB Smissaert - Author
Dim hFile As Long
hFile = FreeFile
Open strFile For Input As #hFile
OpenTextFileToString2 = Input$(LOF(hFile), hFile)
Close #hFile
End Function
Function SplitMultiDelims(ByRef Text As String, ByRef DelimChars As String, _
Optional ByVal IgnoreConsecutiveDelimiters As Boolean = False, _
Optional ByVal Limit As Long = -1) As String()
Dim ElemStart As Long, N As Long, M As Long, Elements As Long
Dim lDelims As Long, lText As Long
Dim Arr() As String
lText = Len(Text)
lDelims = Len(DelimChars)
If lDelims = 0 Or lText = 0 Or Limit = 1 Then
ReDim Arr(0 To 0)
Arr(0) = Text
SplitMultiDelims = Arr
Exit Function
End If
ReDim Arr(0 To IIf(Limit = -1, lText - 1, Limit))
Elements = 0: ElemStart = 1
For N = 1 To lText
If InStr(DelimChars, Mid(Text, N, 1)) Then
Arr(Elements) = Mid(Text, ElemStart, N - ElemStart)
If IgnoreConsecutiveDelimiters Then
If Len(Arr(Elements)) > 0 Then Elements = Elements + 1
Else
Elements = Elements + 1
End If
ElemStart = N + 1
If Elements + 1 = Limit Then Exit For
End If
Next N
'Get the last token terminated by the end of the string into the array
If ElemStart <= lText Then Arr(Elements) = Mid(Text, ElemStart)
'Since the end of string counts as the terminating delimiter, if the last character
'was also a delimiter, we treat the two as consecutive, and so ignore the last elemnent
If IgnoreConsecutiveDelimiters Then If Len(Arr(Elements)) = 0 Then Elements = Elements - 1
ReDim Preserve Arr(0 To Elements) 'Chop off unused array elements
SplitMultiDelims = Arr
End Function
You can read a file row by row with following code
Sub IOTest()
Dim fnum, i As Integer, j As Integer
Dim line As String
Dim lines As Variant
Dim regEx As Object
Set regEx = CreateObject("vbscript.regexp")
With regEx
.Pattern = "\s{1}" 'only one whitespace
.Global = True 'find all occurrences
End With
fnum = FreeFile()
Open ThisWorkbook.Path & "\IO_Test.txt" For Input As #fnum
Do Until EOF(fnum) 'until End of file
i = i + 1
Input #fnum, line 'load row into line
'First replace found sole whitespaces with ","
'Then split on the ","s
lines = Split(regEx.Replace(line, ","), ",")
For j = LBound(lines) To UBound(lines)
Cells(i, j + 1) = lines(j)
Next j
Loop
Close #fnum
End Sub
I tested this with the strings
"$SUBCASE" & vbTab & "1" & vbTab & vbTab & vbTab & vbTab & "1"
"$DISP" & vbTab & "0" & vbTab & "509" & vbTab & "5" & vbTab & "1" & vbTab & "2"
And it only works if you have one whitespace(eg. space, tab,...) separating the data. If you have more than one whitespace between the data it gets trickier. But if you can provide an example on how the data is separated I can take a look at it.
I hope it helps, let me know either way ;)