Concatenate If Not Null List With Commas - excel

In Excel, I need to Concatenate every other cell into one "master" cell. I have used this formula to conquer before =SUBSTITUTE(TRIM(G2 & " " & BC2 & " " & BE2 & " " & BG2), " ", ", ") but this alters the data when the data I am concatenate has a comma in it.
The range of cells that I need to concatenate is every other cell ranging from G2 all the way to BG2. What would be the best course of action to make this happen handling concatenation that involves comma lists?
EDIT
By what I mean with alters data is that this
S223 - Pills, S2323 - Patterns - Backstock, 1/Var
becomes this with the formula above
S223, -, Pills,, S2323, -, Patterns, -, Backstock,, 1/Var

Use the UDF on: VLOOKUP with multiple criteria returning values in one cell
The formula:
=TEXTJOIN(", ",TRUE,IF(MOD(COLUMN(G2:BG2),2)=1,G2:BG2,""))
Being an array formula it would need to be confirmed with Ctrl-Shift-Enter.

The following UDF from answers.microsoft.com should be what you're after
Function TEXTJOIN(delimiter As String, ignore_empty As String, ParamArray textn() As Variant) As String
Dim i As Long
For i = LBound(textn) To UBound(textn) - 1
If Len(textn(i)) = 0 Then
If Not ignore_empty = True Then
TEXTJOIN = TEXTJOIN & textn(i) & delimiter
End If
Else
TEXTJOIN = TEXTJOIN & textn(i) & delimiter
End If
Next
TEXTJOIN = TEXTJOIN & textn(UBound(textn))
End Function

Quite some while ago, i found this code online as i needed it for a personal project of mine. What this does is it takes a string and replace every "unallowed" value by a specified character. In your case I would imagine you allowing every character except "," and replace it by "" or " ". This way, A, -, B, -, C, would become A - B - C
Function cleanString(text As String) As String
Dim output As String
Dim c
For i = 1 To Len(text)
c = Mid(text, i, 1)
If (c >= "a" And c <= "z") Or (c >= "0" And c <= "9") Or (c >= "A" And c <= "Z" Or c = " " Or c = "-" Or c = "é" Or c = "É" Or c = "_") Then ' <=list of allowed values in a string
output = output & c
Else
output = output & " " '<= what unallowed values gets replaced by
End If
Next
cleanString = output
End Function
Hope this can help, I considered VBA as you added the tag in your question.

Related

How to format strings with numbers and special characters in Excel or Access using VBA?

I have a mathematical problem: these five strings are IDs for the same object. Due to these differences, objects appear multiple times in my Access table/query. Although there are a lot of these mutations, but I take this as an example.
76 K 6-18
76 K 6-18(2)
0076 K 0006/ 2018
0076 K 0006/2018
76 K 6/18
How would the VBA-code have to look like to recognize that these numbers stand for the same thing , so a general formatting with "RegEx()" or "format()" or "replace()"...but they must not only refer to this example but to the kind.
The common factor of these and all other mutations is always the following:
1) includes "-", no zeros left of "-", just 18 an not 2018 (year) at the end.
2) is like the first but with (2) (which can be dropped).
3) includes "/", zeros left of "/", and 2018 as year at the end.
4) is like third, but without space after "/".
5) is like the first one, but with a "/" instead of "-".
Character is always one single "K"! I suppose the best way would be to convert all 5 strings to 76 K 6 18 or in ohter cases for example to 1 K 21 20 or 123 K 117 20 . Is this possible with one elegant code or formula? Thanks
Here is a fun alternative using a rather complex but intuitive regular expression:
^0*(\d+) (K) 0*(\d+)[-\/] ?\d{0,2}(\d\d)(?:\(\d+\))?$
See an online demo
^ - Start line anchor.
0* - 0+ zeros to catch any possible leading zeros.
(\d+) - A 1st capture group of 1+ digits ranging 0-9.
- A space character.
(K) - 2nd Capture group capturing the literal "K".
- A space character.
(\d+) - A 3rd capture group of 1+ digits ranging 0-9.
[-\/] - Character class of either a hyphen or forward slash.
? - An optional space character.
\d{0,2} - 0-2 digits ranging from 0-9.
(\d\d) - A 4th capture group holding exactly two digits.
(?:\(\d+\))? - An optional non-capture group holding 1+ digits inside literal paranthesis.
$ - End line anchor.
Now just replace the whole string by the 4 capture groups with spaces in between.
Let's test this in VBA:
'A code-block to call the function.
Sub Test()
Dim arr As Variant: arr = Array("76 K 6-18", "76 K 6-18(2)", "0076 K 0006/ 2018", "0076 K 0006/2018", "76 K 6/18")
For x = LBound(arr) To UBound(arr)
Debug.Print Transform(CStr(arr(x)))
Next
End Sub
'The function that transform the input.
Function Transform(StrIn As String) As String
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "^0*(\d+) (K) 0*(\d+)[-\/] ?\d{0,2}(\d\d)(?:\(\d+\))?$"
Transform = .Replace(StrIn, "$1 $2 $3 $4")
End With
End Function
All the elements from the initial array will Debug.Print "76 K 6 18".
Hope it helps, happy coding!
EDIT: If your goal is just to check if your string compiles against the pattern, the pattern itself can be shortened a little and you can return a boolean instead:
'A code-block to call the function.
Sub Test()
Dim arr As Variant: arr = Array("76 K 6-18", "76 K 6-18(2)", "0076 K 0006/ 2018", "0076 K 0006/2018", "76 K 6/18")
For x = LBound(arr) To UBound(arr)
Debug.Print Transform(CStr(arr(x)))
Next
End Sub
'The function that checks the input.
Function Transform(StrIn As String) As Boolean
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "^0*\d+ K 0*\d+[-\/] ?\d{2,4}(?:\(\d+\))?$"
Transform = .Test(StrIn)
End With
End Function
As #Vincent has suggested, look at using a custom function to convert all of the different data to be consistent. Based on what you have described, the following seems to work:
Function fConvertFormula(strData As String) As String
On Error GoTo E_Handle
Dim astrData() As String
strData = Replace(strData, "/", " ")
strData = Replace(strData, "-", " ")
strData = Replace(strData, " ", " ")
astrData = Split(strData, " ")
If UBound(astrData) = 3 Then
astrData(0) = CLng(astrData(0))
astrData(2) = CLng(astrData(2))
If InStr(astrData(3), "(") > 0 Then
astrData(3) = Left(astrData(3), InStr(astrData(3), "(") - 1)
End If
If Len(astrData(3)) = 4 Then
astrData(3) = Right(astrData(3), 2)
End If
fConvertFormula = Join(astrData, " ")
End If
fExit:
On Error Resume Next
Exit Function
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "fConvertFormula", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume fExit
End Function
It starts by replacing "field" delimiters with spaces, and then does a replace of double spaces. It then removes any leading zeroes from the first and third elements, if there is a bracket in the last element then delete that part, and finally converts to a 2 digit value before joining it all back up.
You may have other cases that you need to deal with, so I would suggest creating a query with the original data and the data converted by this function, and seeing what it throws out.
This function unifies the given string by the rules you defined in your question:
Public Function UnifyValue(ByVal inputValue As String) As String
'// Remove all from "(" on.
inputValue = Split(inputValue, "(")(0)
'// Replace / by blank
inputValue = Replace(inputValue, "/", " ")
'// Replace - by blank
inputValue = Replace(inputValue, "-", " ")
'// Replace double blanks by one blank
inputValue = Replace(inputValue, " ", " ")
'// Split by blank
Dim splittedInputValue() As String
splittedInputValue = Split(inputValue, " ")
'// Create the resulting string
UnifyValue = CLng(splittedInputValue(0)) & _
" " & splittedInputValue(1) & _
" " & CLng(splittedInputValue(2)) & _
" " & Right(CLng(splittedInputValue(3)), 2)
End Function
It always returns 76 K 6 18 regarding to your sample values.

Index / Aggregate formula with Search

I have a sample data (1,2,3,4) on A2:D2 columns and on F1, I have (1,3), and on G1 (2,3,4).
I was suggested to use this formula
=INDEX($A2:$D2,AGGREGATE(15,6,ROW($A2:$D2)/ISNUMBER(SEARCH(TEXT($A2:$D2,"000,"),F$1&",")),1))
on F2, and G2 which is supposed to give the matching values on F2 and G2 respectively. Since both values (1,3) match, the result should be (1,3) on F2, and (2,3,4) on G2.
So basically this formula is supposed to work like index/match formula but instead of single values, it works on comma separated 2 or 3 values.
When I try to use the formula I keep getting #NUM! error. Can I get a little help to make this formula work, please?
Thanks.
Note: I am open to alternative solutions, but if it requires VBA, it has to be with a user defined formula. Without UDF, it is not useful for me.
A UDF should look like this
Option Explicit
Function MultFind(r As Range, s As String) As String
Dim c As Range
Dim result As String
For Each c In r
If InStr("," & s & ",", "," & c & ",") <> 0 Then result = result & c & ","
Next c
If Len(result) > 0 Then result = Left(result, Len(result) - 1)
MultFind = result
End Function
Called as
=MultFind($A2:$D2,F1)
Edit
Here it is with optional parameter for delimiter:
Option Explicit
Function MultFind(r As Range, s As String, Optional delimiter As String = ",") As String
Dim c As Range
Dim result As String
' Check each cell in range against search string
For Each c In r
If InStr(delimiter & s & delimiter, delimiter & c & delimiter) <> 0 Then result = result & c & delimiter
Next c
' Delimiter may be more than one character
If Len(result) > 0 Then result = Left(result, Len(result) - Len(delimiter))
MultFind = result
End Function

Adding conditional zeroes to a ssn style number in Excel

Trying to add conditional zeroes to a ssn style number in Excel.
1234-1234-12 -> 12340-1234-12
12345-123-12 -> 12345-1230-12
12345-1234-1 -> 12345-1234-10
12345-1234-12 -> do nothing
You will need to parse each part and then make sure it is the desired number of numbers and concatenate it back together:
=LEFT(LEFT(A1,FIND("-",A1)-1)&"00000",5)&"-" & LEFT(MID(A1,FIND("-",A1)+1,FIND("-",A1,FIND("-",A1)+1)-FIND("-",A1)-1)&"0000",4)&"-"&LEFT(MID(A1,FIND("-",A1,FIND("-",A1)+1)+1,LEN(A1))&"00",2)
If you want a VBA answer to complement #scottcraner's excellent answer:
Function ExpandSSN(s As String) As String
Dim A As Variant
Dim part As String
A = Split(s, "-")
part = Trim(A(0))
A(0) = part & String(5 - Len(part), "0")
part = Trim(A(1))
A(1) = part & String(4 - Len(part), "0")
part = Trim(A(2))
A(2) = part & String(2 - Len(part), "0")
ExpandSSN = Join(A, "-")
End Function
Put the above code in a standard code module. Then enter the formula e.g. =ExpandSSN(A1) in B1 and drag down:

string text with blank cells

I am trying to string together text from cells across by row when some of the cells are blank. I also want to have commas separating the text from each cell but cannot figure out how to only have commas put in when there is data in a cell.
I have tried using variations of concatenate and stringing the text using A1&B1&C1 but nothing is returning the data in the format I want.
Is there a combination of nested formulas I can use that will return the data in the format I want?
Here's a VBA solution I had before the newer versions:
Public Function JOINCELLS(ByVal ref As Range) As String
Dim c As Range
For Each c In ref
If Len(c) > 0 Then
JOINCELLS = JOINCELLS & c & ", "
End If
Next
JOINCELLS = Left(JOINCELLS, Len(JOINCELLS) - 2)
End Function
Then, it's just =JOINCELLS(A1:D1).
The formula below could do the trick. Concatenate the val The trim would remove spaces from the ends, and the substitute would swap the space for the comma(space).
=SUBSTITUTE(TRIM(A1 & " " & B1 & " " & C1 & " " & D1), " ", ", ")
Edit from the comments below - you could update the spaces between the quotes to be any character that does not appear in your cells. You would just have to the substitute formula to match. If you don't use the | character for example:
=SUBSTITUTE(TRIM(A1 & "|" & B1 & "|" & C1 & "|" & D1), "|", ", ")

Extract two substrings from a set of three separated by ampersands

I am trying to extract numbers from a text.
If I have an entry like 12&6&2014, how can I extract the 12 (the number that is before the first &) and 2014 (the number that occurs after the second &)?
To get first number:
=LEFT(A1, FIND("&", A1)-1)
To get last number after the second &:
=RIGHT(A1, 4)
Otherwise, if that's not always a year:
=MID(A1, FIND(CHAR(1), SUBSTITUTE(A1, "&", CHAR(1), 2))+1, LEN(A1))
you can loop through each character int he string and check to see if it is numeric
Sub getNumberValues()
Dim s As String
Dim c As New Collection
Dim sNewString As String
s = "12&6&2014"
For v = 1 To Len(s)
If IsNumeric(Mid(s, v, 1)) Then
sNewString = sNewString & Mid(s, v, 1)
Else
c.Add sNewString
sNewString = ""
End If
Next v
'add the last entry
c.Add sNewString
sNewString = ""
For Each x In c
sNewString = sNewString & x & Chr(13)
Next
MsgBox sNewString
End Sub
If what I understand is correct which is that the characters that separate vary as well as how many digits are used you might look into something like this:
Function CleanUp(Txt)
For x = 1 To 255
Select Case x
Case 45, 47, 65 To 90, 95, 97 To 122
Txt = WorksheetFunction.Substitute(Txt, Chr(x), "") <- "" can be replaced
End Select with "&" to do a
Next x MID() using & as
the delimiter
CleanUp = Txt
End Function
If you can use VBA, this will replace your characters with a blank, but you could put in your own character and then use your formulas to separate from a specific delimiter.
The original code can be found here:
http://www.mrexcel.com/forum/excel-questions/380531-extract-only-numbers.html
Simplest might be Text to Columns with & as the delimiter, then delete the middle column. This overwrites the original data, so a copy might be appropriate.
Another simple way would be to create two copies, and for one Find what: &* and Replace with: nothing, for the other Find what: *& and Replace with: nothing.
An alternative formula solution might be:
=DAY(SUBSTITUTE($A1,"&","/"))
and
=YEAR(SUBSTITUTE($A1,"&","/"))

Resources