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:
Related
I'm looking for a formula that re-arranges values in excel cells.
The cells contain full names (at least one, up to 20) in the format of "last name + name(s)" but this must be convert into the following format:
1.- First letter of first name, follow by a blank space.
2.- Last name
An example can be found below.
I know I could simple use replace function, but it would be great if this might be possible to achieve via excel formulas.
Thanks in advance.
Since the strings can be so long, I would use FILTERXML and LET if you have the newest version of Excel rather than keep having to repeat things like LEFT, LEN, or FIND.
For example, if the data is always seperated by a "|" and only comes in the form "Last_Name First_Name (possible Mid_Initial)|", then you can use something like:
=LET(x, FILTERXML("<t><s>"&SUBSTITUTE(I1, "|", "</s><s>")&"</s></t>", "//s"),
y, TRIM(LEFT(RIGHT(x, LEN(x)-SEARCH(" ",x)),1)),
z, TRIM(LEFT(x, SEARCH(" ",x))),
LEFT(CONCAT(y&" "&z&", "), LEN(CONCAT(y&" "&z&", "))-2))
Try this UDF.
Option Explicit
Function ExtractName(cellRng As Range)
Dim regex As Object, mc As Object, i As Long, str As String, arr
Set regex = CreateObject("VBScript.regexp")
regex.ignorecase = False
regex.Global = True
arr = Split(cellRng.Value, "|")
str = ""
For i = LBound(arr) To UBound(arr)
regex.Pattern = "^[\w-]+\s\b."
Set mc = regex.Execute(arr(i))
str = str & Split(mc(0), " ")(1) & " " & Split(mc(0), " ")(0) & "|"
Next i
ExtractName = Left(str, Len(str) - 1)
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
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.
I want to change the following
123456789A1
to
123-456-789 A1
Background:
In Format Cells, I used this:
000-0000-00 00
And that works if everything in the cell is a number,
12345678911
will become
123-4567-89 11
But as soon there is a letter, it breaks it.
How can I change the type to ignore letters?
this is an example :
Sub test()
a = [A1]
b = Left(a, 3) & "-" & Mid(a, 4, 3) & "-" & Mid(a, 7, 3) & " " & Right(a, 2)
[A2] = b
End Sub
But want you 3 or 4 numbers in the seconde position?
if A1=123456789A1 then in A2 : 123-456-789 A1
Cell number formatting only works on numbers.
If you don't mind changing the values into text strings, you could format them in VBA using the Format function. For example:
Option Explicit
Sub FMT()
Dim R As Range, C As Range
Const sFMT As String = "###-####-## ##"
Set R = Intersect(Range("A:A"), ActiveSheet.UsedRange)
For Each C In R
C.Value = Format(C.Text, sFMT)
Next C
End Sub
You will need to change the range arguments to match what you need. And you could also use this in an event-triggered macro to do it automatically.
I'm trying to get all the content between multiple parenthesis and comma delimiting them. So for example
A1 contains
thisfile.jpg (/path/to/file.jpg), thisfile2.jpg (/path/to/file2.jpg)
and B1 should look like
/path/to/file.jpg, /path/to/file2.jpg
If it's just one entry I can get what I need with this:
MID(A1,FIND("(",A1)+1,FIND(")",A1)-FIND("(",A1)-1)
But that only returns the first one, I need to be for each parenthesis. The amount of parenthesis in each row will vary.
I am sure there are better solutions out there with formulas only. Yet, I cannot help you there. But the following UDF is surely also a feasible solution. Just copy this code into an empty module:
Option Explicit
Public Function GetPaths(strTMP As String)
Dim i As Long
Dim varArray As Variant
varArray = Split(strTMP, "(")
For i = LBound(varArray) To UBound(varArray)
If InStr(1, varArray(i), ")") > 0 Then
GetPaths = GetPaths & ", " & Mid(varArray(i), 1, InStr(1, varArray(i), ")") - 1)
End If
Next i
GetPaths = Mid(GetPaths, 3)
End Function
Afterwards, you can use this formula in column B as follows: =GetPaths(A1).