First time posting a question here. Excited to be a part of the community!
I have a sticky situation where converting data for a client has me stumped.
I need to find a way to not only split a cell by multiple Delimiters, but some data points need to be removed as well. In this situation, we're talking about a list of tenants and any additional occupants on a lease.
This is how the data was exported and in its current state
You'll see that there is at least one common delimiter I can use here. The " : " would allow me to simply split the names, but the real issue here is that the tenant names listed under the data points "son" or "daughter" need to be removed. On the other hand, the tenants listed as "resident" or "tenant" must be kept.
An example of how I'd want this to look
You'll see that the names are split and only the names listed under "tenant" or "resident" are kept and the others are dropped.
I've tried to find and replace the terms I want to keep with a simple character I can use to split, but the issue is that there isn't a consistent sequence for me to use this. I've been looking for a split VBA function that would work as well, but haven't had any luck.
Thoughts here would be welcome!
I think this function is probably an over-kill. But it does what you want.
Function SplitCellValue(ByVal CellVal As String) As String
'137
Const Qualifiers As String = "tenant,resident"
Dim Fun() As String ' function return array
Dim n As Integer ' index of Fun()
Dim Qword() As String ' split Qualifiers
Dim q As Integer ' index of Qword
Dim Sp() As String ' split array
Dim i As Integer ' index of Sp()
Dim Skip As Boolean ' True if entry doesn't qualify
Dim Append As Boolean ' True to append unqualified entry to previous
If Len(CellVal) Then ' skip blank CellVal
Qword = Split(Qualifiers, ",")
Sp = Split(Trim(CellVal), ",")
ReDim Fun(1 To UBound(Sp) + 1)
For i = 0 To UBound(Sp)
If InStr(Sp(i), ":") Then
For q = LBound(Qword) To UBound(Qword)
Skip = CBool(InStr(1, Sp(i), Qword(q), vbTextCompare))
If Skip Then Exit For
Next q
If Skip Then
n = n + 1
Fun(n) = Trim(Sp(i))
Append = True
Else
Append = False
End If
Else
If n = 0 Then
' preserve unqualified, leading entry
n = 1
Append = True
End If
If Append Then
If Len(Fun(n)) Then Fun(n) = Fun(n) & ", "
Fun(n) = Fun(n) & Trim(Sp(i))
End If
End If
Next i
End If
If i Then
ReDim Preserve Fun(1 To n)
SplitCellValue = Join(Fun, ", ")
End If
End Function
List all the qualifiers in the constant Qualifiers. Everything else will be rejected. Qualifiers only qualify an element if they appear in the same comma-separated element as a colon. (I probably might as well have combined the two but I didn't.)
You can use this function in VBA with a call like this one.
Private Sub Test_SplitCellValue()
Dim R As Integer
For R = 2 To 5
Debug.Print i, SplitCellValue(Cells(R, 1).Value)
Next R
End Sub
or as a UDF, called like, =SplitCellValue(A2). Install in a standard code module for this use.
The over-kill is in what the function can do that is probably not needed. (1) A blank cell will return a blank. (2) A non-blank cell will return its original value if no colon is found in it. (3) Anything before a first element with a colon in it will be included in the return. (4) blanks in the original are removed and replaced by blanks following commas which themselves are removed and then placed between qualifying elements. All of this takes a lot of code that may have to be revised if your data or expectations defy my anticipation.
So after some trial and error, this was much simpler than I was thinking. There were two different instances of ", " & "," (one had a space behind) being used in different manners.
I was able to find and replace for the instance of comma with a space, keeping the detail I needed intact, while delimiting the "," without a space.
Thanks!
Related
For instance, I would like these 6 numbers.
Currently when I use the sort method it puts 6.6.1.1.13 first and 6.6.1.1.2 later.
Before Sort
6.6.1.1
6.6.1.1.1
6.6.1.1.13
6.6.11.14
► 6.6.1.1.2
What I Want It To Look Like After Sort
6.6.1.1
6.6.1.1.1
► 6.6.1.1.2
6.6.1.1.13
6.6.11.14
Unfortunately the only fully general way to sort outline numbers (or more formally, "path-indexes") is with a custom comparison function. Unfortunately, the Excel sorting operations and functions do not support such a feature (not even from VBA). The Excel preferred way is with custom lists, but these are not workable for path-indexes.
This leaves two choices:
Do your sorting entirely in VBA: This works (I've done it) but is pretty involved and messy. Or,
Use a Helper Column with a VBA function: This works but is not fully general, because you have to know ahead of time what the maximum index values will be.
of these, #2 above is by far the simpler option, but it does have limitations (explained below).
Basically what we want is a VBA function that can take a string like "6.6.11.14" and make it always sortable in path index order. The problem with this string is that in text order two digit indexes like ".11" and ".14" come before ".2" rather than after it.
The obvious way to fix this is to fix this is to convert all indexes into 2-digit numbers with leading zeroes. So, 6.6.11.14 would become 06.06.11.14 and crucially 6.6.2.1 would become 06.06.02.01. Now these two path-index values will sort correctly use text sorting.
The catch, however, is that this is only true if each individual index number is never greater than two digits (99). Thus, 06.07.99 sorts correctly, but 06.07.110 does not under this scheme. This is easily fixable by simply raising it from two digits to three digits, but again, the catch is that you have to know this ahead of time.
So assuming that we do know ahead of time what the maximum size/(number of digits) will be for any single index number, we can use the following VBA function to reformat your outline numbers for a helper column:
Public Function OutlineSortingFormat(OutlineNumber As String, Digits As Integer) As String
Dim PathIndexes() As String
Dim Zeroes As String
Dim i As Integer
Zeroes = "0000000000"
PathIndexes = Split(OutlineNumber, ".")
For i = 0 To UBound(PathIndexes)
PathIndexes(i) = Right(Zeroes & PathIndexes(i), Digits)
Next i
OutlineSortingFormat = Join(PathIndexes, ".")
End Function
This just splits the outline number into individual numeric strings, prefixes the correct amount of zeroes and then concatenates them back into a sortable outline number.
You then apply this by making a helper column and then using the function like so:
=OutlineSortingFormat(M3,2)
Where M is the column that has your unformatted outline indexes and the second parameter (, 2)) indicates that your want all index numbers filled (and truncated) to 2 digits. Then instead of sorting on your original outline numbers, your sort on the "helper column" containing the reformatted values.
Manual method
Use the Text to Column function and separate out your headers using "." as a delimiter.
When you are done select all the data as follows:
Perform a sort on the selected data.
Note: My data has headers has been selected and column 6 and 7 come up a A to Z as they are currently empty and it defaults to alphabetical sort as a result. The alphabetical sort can be added by adding a dummy row of data at the start or end of your data to be sorted. This is done by either adding all 0's or a number larger than any number in your list to all columns.
After selecting ok your "Combined" data will be sorted numerically based on the outline numbers to the right.
Here is some code for multiple purposes.
The first function is a UDF which if wanted could be called from the worksheet to be used as a helper function. Therefore it's easy enough to alter the pad length if required for sorting.
The second code is a little more involved but inserts a column next to the table, adds the helper function, sorts then deletes the helper column to leave the sheet structure as before.
SortColumn should be defined as the column index where the indices are. i.e. if in the first column of the designated table then it would be set to '1'
Public Function PadIndices(Cell As Range, PadLength As Long, Optional Delimiter As String) As String
If Cell.Count > 1 Then Exit Function
If Delimiter = "" Then Delimiter = "."
Dim Arr As Variant: Arr = Split(Cell.Value, Delimiter)
Dim i As Long: For i = LBound(Arr) To UBound(Arr)
If Len(Arr(i)) < PadLength Then Arr(i) = WorksheetFunction.Rept("0", PadLength - Len(Arr(i))) & Arr(i)
Next i
PadIndices = Join(Arr, Delimiter)
End Function
Sub SortByIndices()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim Table As Range: Set Table = ws.Range("H7:I11")
Dim PadLength As Long: PadLength = 2
Dim SortColumn As Long: SortColumn = 1
Table.Columns(1).Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Dim SortRange As Range: Set SortRange = Table.Columns(1).Offset(0, -1)
SortRange.Formula2R1C1 = "=PadIndices(RC[" & SortColumn & "], " & PadLength & ")"
With ws.Sort.SortFields
.Clear
.Add2 Key:=SortRange, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
End With
With ws.Sort
.SetRange Application.Union(Table, SortRange)
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
SortRange.Delete Shift:=xlToLeft
End Sub
You could make a helper column in which you remove the points and sort that helper column.
=NUMBERVALUE(SUBSTITUTE(E4;".";))
A) User defined function without the need of a help column
In order to be able to sort outline numbers, you have to bring the individual numerical values
to a well defined uniform number format (like e.g. "00" if numbers don't exceed 99 as assumed default; note the flexible String() function in section b)).
This dynamic array approach allows argument inputs of any range definitions (plus optional digit maxima) like
=Outline(A5:A10) to sort one column (with a 2-digits default maximum) or even
=Outline(A2:E4, 3) over a multicolumn range (with an explicit 3-digits maximum)
Note: tested with the newer dynamic features of Office 2019+/MS365;
for backward compatibility you would have to change the TextJoin() function and possibly enter =Outline(...) as array formula using CSE (Ctrl+Shift+Enter).
Function Outline(rng As Range, Optional ByVal digits As Long = 2)
'Date: 2022-01-09
'Auth: https://stackoverflow.com/users/6460297/t-m
'a) create unordered 1-dim array from any contiguous range
Dim myFormula As String
myFormula = "TextJoin("","",True," & rng.Address(False, False) & ")"
Dim codes
codes = Split(rng.Parent.Evaluate(myFormula), ",")
'b) add leading zeros via number format
Dim i As Long
For i = LBound(codes) To UBound(codes)
Dim tmp: tmp = Split(codes(i), ".")
Dim ii As Long
For ii = LBound(tmp) To UBound(tmp)
tmp(ii) = Format(CInt(tmp(ii)), String(digits, "0"))
Next ii
codes(i) = Join(tmp, ".") ' join to entire string element
Debug.Print i, codes(i)
Next i
'c) sort
BubbleSort codes ' << help proc BubbleSort
'd) remove leading zeros again
For i = LBound(codes) To UBound(codes)
For ii = 1 To digits - 1 ' repeat (digits - 1) times
codes(i) = Replace(codes(i), ".0", ".")
If Left(codes(i), 1) = "0" Then codes(i) = Mid(codes(i), 2)
Next
Next
'e) return function result
Outline = Application.Transpose(codes)
End Function
Help procedure BubbleSort
Sub BubbleSort(arr)
'Date: 2022-01-09
'Auth: https://stackoverflow.com/users/6460297/t-m
Dim cnt As Long, nxt As Long, temp
For cnt = LBound(arr) To UBound(arr) - 1
For nxt = cnt + 1 To UBound(arr)
If arr(cnt) > arr(nxt) Then
temp = arr(cnt)
arr(cnt) = arr(nxt)
arr(nxt) = temp
End If
Next nxt
Next cnt
End Sub
B) Just for fun: alternative single-formula approach (with restricted number range)
Instead of extending the digit formats, I played with the idea to restrict the numeric display
by executing a temporary hexadecimal replacement.
Note that this approach based on a single-formula evaluation
allows outline sub-numbers only within a numeric range from 1 to 15 (as numbers 10 to 15 get replaced by characters A to F), but might be sufficient for low hierarchy depths! Furthermore it includes a tabular Sort() function available only in Excel version MS365!
Function Outline(rng As Range)
'Site: https://stackoverflow.com/questions/70565436/how-to-sort-outline-numbers-in-numerical-order
'Date: 2022-01-09
'Auth: https://stackoverflow.com/users/6460297/t-m
'Meth: hex replacements + sort; assuming chapters from (0)1 to 15 (10=A,11=B..15=F)
'Note: allows outline sub-numbers only up to 15! Needs Excel version MS365.
Dim pattern
pattern = String(6, "X") & "Sort(" & String(6, "X") & "$,15,""F""),14,""E""),13,""D""),12,""C""),11,""B""),10,""A"")),""A"",10),""B"",11),""C"",12),""D"",13),""E"",14),""F"",15)"
pattern = Replace(Replace(pattern, "$", rng.Address(False, False)), "X", "Substitute(")
Outline = rng.Parent.Evaluate(pattern)
End Function
As mentioned in the title, I wonder if there is any way to use built-in functions in excel to see whether a cell contains a specific number and count the total numbers in the cell. The cell can contain a list of numbers seperated by comas, for instance, "1,4,7" or ranges "10-25" or a combination of both. See the print screen.
No, there is not, but you could write a VBA function to do that, something like:
Function NumberInValues(number As String, values As String) As Boolean
Dim n As Integer
n = CInt(number)
Dim parts() As String
parts = Split(values, ",")
For i = LBound(parts) To UBound(parts)
parts(i) = Replace(parts(i), " ", "")
Next
Dim p() As String
Dim first As Integer
Dim last As Integer
Dim tmp As Integer
For i = LBound(parts) To UBound(parts)
p = Split(parts(i), "-")
' If there is only one entry, check for equality:
If UBound(p) - LBound(p) = 0 Then
If n = CInt(p(LBound(p))) Then
NumberInValues = True
Exit Function
End If
Else
' Check against the range of values: assumes the entry is first-last, does not
' check for last > first.
first = CInt(p(LBound(p)))
last = CInt(p(UBound(p)))
If n >= first And n <= last Then
NumberInValues = True
Exit Function
End If
End If
Next
NumberInValues = False
End Function
and then your cell C2 would be
=NumberInValues(B2,A2)
Calculating how many numbers there are in the ranges would be more complicated as numbers and ranges could overlap.
The key part of implementing this is to create a List or Array of individual numbers that includes all the Numbers represented in the first column.
Once that is done, it is trivial to check for an included, or do a count.
This VBA routine returns a list of the numbers
Option Explicit
Function createNumberList(s)
Dim AL As Object
Dim v, w, x, y, I As Long
Set AL = CreateObject("System.Collections.ArrayList")
v = Split(s, ",")
For Each w In v
'If you need to avoid duplicate entries in the array
'uncomment the If Not lines below and remove the terminal double-quote
If IsNumeric(w) Then
'If Not AL.contains(w) Then _"
AL.Add CLng(w)
Else
x = Split(w, "-")
For I = x(0) To x(1)
'If Not AL.contains(I) Then _"
AL.Add I
Next I
End If
Next w
createNumberList = AL.toarray
End Function
IF your numeric ranges might be overlapping, you will need to create a Unique array. You can do that by changing the AL.Add function to first check if the number is contained in the list. In the code above, you can see instructions for that modification.
You can then use this UDF in your table:
C2: =OR($B2=createNumberList($A2))
D2: =COUNT(createNumberList($A2))
Here is a possible formula solution using filterxml as suggested in the comment:
=LET(split,FILTERXML("<s><t>+"&SUBSTITUTE(A2,",","</t><t>+")&"</t></s>","//s/t"),
leftn,LEFT(split,FIND("-",split&"-")-1),
rightn,IFERROR(RIGHT(split,LEN(split)-FIND("-",split)),leftn),
SUM(rightn-leftn+1))
The columns from F onwards show the steps for the string in A2. I had to put plus signs in because Excel converted a substring like "10-15" etc. into a date as usual.
Then to find if a number (in C2 say) is present:
=LET(split,FILTERXML("<s><t>+"&SUBSTITUTE(A2,",","</t><t>+")&"</t></s>","//s/t"),
leftn,LEFT(split,FIND("-",split&"-")-1),
rightn,IFERROR(RIGHT(split,LEN(split)-FIND("-",split)),leftn),
SUM((--leftn<=C2)*(--rightn>=C2))>0)
As noted by #Ron Rosenfeld, it's possible that there may be duplication within the list: the Count formula would be susceptible to double counting in this case, but the Check (to see if a number was in the list) would give the correct result. So the assumptions are:
(1) No duplication (I think it would be fairly straightforward to check for duplication, but less easy to correct it)
(2) No range in wrong order like 15-10 (although this could easily be fixed by putting ABS around the subtraction in the first formula).
Here is a little cheeky piece of code for a VBA solution:
Function pageCount(s As String)
s = Replace(s, ",", ",A")
s = Replace(s, "-", ":A")
s = "A" & s
' s now looks like a list of ranges e.g. "1,2-3" would give "A1,A2:A3"
pageCount = Union(Range(s), Range(s)).Count
End Function
because after all the ranges in the question behave exactly like Excel ranges don't they?
and for inclusion (of a single page)
Function includes(s As String, m As String) As Boolean
Dim isect As Range
s = Replace(s, ",", ",A")
s = Replace(s, "-", ":A")
s = "A" & s
Set isect = Application.Intersect(Range(s), Range("A" & m))
includes = Not (isect Is Nothing)
End Function
For a MWE, and to replicate my problem, in a blank workbook put the text
testone|testtwo
into the first cell, A1.
Then, the VBA code shall be:
Sub test()
MsgBox "testone|testtwo"
MsgBox Cells(1, 1).Text
MsgBox Split("testone|testtwo", "|")
MsgBox Split(Cells(1, 1).Text, "|")
Msgbox Split(Cells(1, 1).Text, "|").Length
End Sub
Now, already the second one gives me an error, type mismatch.
What I need this for is that I am faced a potentially long string in which n+1 substrings, of different lengths, are separated by n occurences of the symbol |. I need to extract each substring, i.e. those n-1 within two instances of the symbol, and the two at the beginning. I believe, but am not certain, that the use of the split-function is best. In a next step, want to use the Length of the result to count the number of occurences of | (as in the last line), but that does not work either.
Store the split in an array
Dim vSplit as Variant
vSplit=Split("testone|testtwo", "|")
then to get a count of how many items:
nCount = UBound(vSplit) + 1
If you want a count of how many "|" are in the string...
nCount = UBound(vSplit)
I need to parse out a list of tracking numbers from text in excel. The position in terms of characters will not always be the same. An example:
Location ID 987
Your package is arriving 01/01/2015
Fruit Snacks 706970554628
<http://www.fedex. com/Tracking?tracknumbers=706970554628>
Olive Oil 709970554631
<http://www.fedex. com/Tracking?tracknumbers=709970554631>
Sign 706970594642
<http://www.fedex .com/Tracking?tracknumbers=706970594642>
Thank you for shopping with us!
The chunk of text is located in one cell. I would like the results to either be 3 separate columns or rows looking like this:
706970554628 , 709970554631 , 706970594642
There will not always be the same number of tracking numbers. One cell might have six while another has one.
Thank you for any help!!
I think you'll need some VBA to do this. And it's not going to be super simple stuff. #Gary'sStudent has a great example of grabbing numbers from a big string. If you need something that is more specific to your scenario you'll have to parse the string word by word and have it figure out when it encounters a tracking number in the URL.
Something like the following will do the trick:
Function getTrackingNumber(bigMessage As String, numberPosition As Integer) As String
Dim intStrPos As Integer
Dim arrTrackNumbers() As Variant
'create a variable to hold characters we'll use to identify words
Dim strWorkSeparators As String
strWordSeparators = "()=/<>?. " & vbCrLf
'iterate through each character in the big message
For intStrPos = 1 To Len(bigMessage)
'Identify distinct words
If InStr(1, strWordSeparators, Mid(bigMessage, intStrPos, 1)) > 1 Then 'we found the start of a new word
'if foundTrackNumber is true, then this must be a tracking number. Add it to the array of tracking numbers
If foundTrackNumber Then
'keep track of how many we've found
trackNumbersFound = trackNumbersFound + 1
'redim the array in which we are holding the track numbers
ReDim Preserve arrTrackNumbers(0 To trackNumbersFound - 1)
'add the track
arrTrackNumbers(trackNumbersFound - 1) = strword
End If
'Check to see if the word that we just grabbed is "tracknumber"
If strword = "tracknumbers" Then
foundTrackNumber = True
Else
foundTrackNumber = False
End If
'set this back to nothing
strword = ""
Else
strword = strword + Mid(bigMessage, intStrPos, 1)
End If
Next intStrPos
'return the requested tracking number if it exists.
If numberPosition > UBound(arrTrackNumbers) + 1 Then
getTrackingNumber = ""
Else
getTrackingNumber = arrTrackNumbers(numberPosition - 1)
End If
End Function
This is a UDF, so you can use it in your worksheet as a formula with:
=getTrackingNumber(A1, 1)
Which will return the first tracking number it encounters in cell A1. Consequently the formula
=getTrackingNumber(A1, 2)
will return the second tracking number, and so on.
This is not going to be a speedy function though since it's parsing the big string character by character and making decisions as it goes. If you can wrangle Gary's Student's answer into something workable it'll be much faster and less CPU intensive on larger data. However, if you are getting too many results and need to go at this like a surgeon, then this should get you in the ballpark.
If tracking is always a 12 digit number, then select the cell run run this short macro:
Sub parser117()
Dim s As String, ary, i As Long
With ActiveCell
ary = Split(Replace(Replace(.Text, Chr(10), " "), Chr(13), " "), " ")
i = 1
For Each a In ary
If Len(a) = 12 And IsNumeric(a) Then
.Offset(0, i).Value = a
i = i + 1
End If
Next a
End With
End Sub
I have a simple problem that I'm hoping to resolve without using VBA but if that's the only way it can be solved, so be it.
I have a file with multiple rows (all one column). Each row has data that looks something like this:
1 7.82E-13 >gi|297848936|ref|XP_00| 4-hydroxide gi|297338191|gb|23343|randomrandom
2 5.09E-09 >gi|168010496|ref|xp_00| 2-pyruvate
etc...
What I want is some way to extract the string of numbers that begin with "gi|" and end with a "|". For some rows this might mean as many as 5 gi numbers, for others it'll just be one.
What I would hope the output would look like would be something like:
297848936,297338191
168010496
etc...
Here is a very flexible VBA answer using the regex object. What the function does is extract every single sub-group match it finds (stuff inside the parenthesis), separated by whatever string you want (default is ", "). You can find info on regular expressions here: http://www.regular-expressions.info/
You would call it like this, assuming that first string is in A1:
=RegexExtract(A1,"gi[|](\d+)[|]")
Since this looks for all occurance of "gi|" followed by a series of numbers and then another "|", for the first line in your question, this would give you this result:
297848936, 297338191
Just run this down the column and you're all done!
Function RegexExtract(ByVal text As String, _
ByVal extract_what As String, _
Optional separator As String = ", ") As String
Dim allMatches As Object
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
Dim i As Long, j As Long
Dim result As String
RE.pattern = extract_what
RE.Global = True
Set allMatches = RE.Execute(text)
For i = 0 To allMatches.count - 1
For j = 0 To allMatches.Item(i).submatches.count - 1
result = result & (separator & allMatches.Item(i).submatches.Item(j))
Next
Next
If Len(result) <> 0 Then
result = Right$(result, Len(result) - Len(separator))
End If
RegexExtract = result
End Function
Here it is (assuming data is in column A)
=VALUE(LEFT(RIGHT(A1,LEN(A1) - FIND("gi|",A1) - 2),
FIND("|",RIGHT(A1,LEN(A1) - FIND("gi|",A1) - 2)) -1 ))
Not the nicest formula, but it will work to extract the number.
I just noticed since you have two values per row with output separated by commas. You will need to check if there is a second match, third match etc. to make it work for multiple numbers per cell.
In reference to your exact sample (assuming 2 values maximum per cell) the following code will work:
=IF(ISNUMBER(FIND("gi|",$A1,FIND("gi|", $A1)+1)),CONCATENATE(LEFT(RIGHT($A1,LEN($A1)
- FIND("gi|",$A1) - 2),FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2)) -1 ),
", ",LEFT(RIGHT($A1,LEN($A1) - FIND("gi|",$A1,FIND("gi|", $A1)+1)
- 2),FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1,FIND("gi|", $A1)+1) - 2))
-1 )),LEFT(RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2),
FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2)) -1 ))
How's that for ugly? A VBA solution may be better for you, but I'll leave this here for you.
To go up to 5 numbers, well, study the pattern and recurse manually in the formula. IT will get long!
I'd probably split the data first on the | delimiter using the convert text to columns wizard.
In Excel 2007 that is on the Data tab, Data Tools group and then choose Text to Columns. Specify Other: and | as the delimiter.
From the sample data you posted it looks like after you do this the numbers will all be in the same columns so you could then just delete the columns you don't want.
As the other guys presented the solution without VBA... I'll present the one that does use. Now, is your call to use it or no.
Just saw that #Issun presented the solution with regex, very nice! Either way, will present a 'modest' solution for the question, using only 'plain' VBA.
Option Explicit
Option Base 0
Sub findGi()
Dim oCell As Excel.Range
Set oCell = Sheets(1).Range("A1")
'Loops through every row until empty cell
While Not oCell.Value = ""
oCell.Offset(0, 1).Value2 = GetGi(oCell.Value)
Set oCell = oCell.Offset(1, 0)
Wend
End Sub
Private Function GetGi(ByVal sValue As String) As String
Dim sResult As String
Dim vArray As Variant
Dim vItem As Variant
Dim iCount As Integer
vArray = Split(sValue, "|")
iCount = 0
'Loops through the array...
For Each vItem In vArray
'Searches for the 'Gi' factor...
If vItem Like "*gi" And UBound(vArray) > iCount + 1 Then
'Concatenates the results...
sResult = sResult & vArray(iCount + 1) & ","
End If
iCount = iCount + 1
Next vItem
'And removes trail comma
If Len(sResult) > 0 Then
sResult = Left(sResult, Len(sResult) - 1)
End If
GetGi = sResult
End Function
open your excel in Google Sheets and use the regular expression with REGEXEXTRACT
Sample Usage
=REGEXEXTRACT("My favorite number is 241, but my friend's is 17", "\d+")
Tip: REGEXEXTRACT will return 241 in this example because it returns the first matching case.
In your case
=REGEXEXTRACT(A1,"gi[|](\d+)[|]")