Insert text after 4 decimal variable number in Excel VBA - excel

I have been working on a processing file in Excel VBA to take raw data from our very old database software and arrange the .txt output into an Excel database. The problem I am running into is that I need to add a delimiting marker after a number sequence to tell Excel to split this part of the text string into two columns. The number sequence ranges from 0.0000 to 999.9999 and I need to keep this number intact. The number is always represented with four decimal points.
Could someone please give me some direction on how to accomplish adding a character (like Æ) after a variable number sequence for all cells within a column?
Raw data:
A1: Hello World, This is a test of 22.5010 and is only a test
A2: Hello World, This is a test of 0.1250 and is only a test
A3: Hello World, This is a test of 0.0000 and is only a test
Final Result:
A1: Hello World, This is a test of 22.5010Æ and is only a test
A2: Hello World, This is a test of 0.1250Æ and is only a test
A3: Hello World, This is a test of 0.0000Æ and is only a test
Thank you in advance!

Don't forget to add the proper references to the project (in tab Tools>References):
Add "Microsoft VBScript Regular Expressions 5.5"
Now add a button onto your excel page and double click on the button to open the proper macro page. Add his code to the macro page it just opened:
Sub Button1_Clic()
'
' Button1_Clic Macro
'
'This sub will scan through the first column (A) and add Æ to the end of
'numbers with the proper format.
On Error Resume Next 'Needed incase the line doesn't have a number
Dim i As Integer
Dim NumberStr As Object
Dim RegEx As RegExp
Set RegEx = New RegExp
With RegEx
.IgnoreCase = True
.Global = False
.Pattern = "\d{1,3}\.\d{4}"
End With
For i = 1 To 500 'Change last value to the last row in the column
Set NumberStr = RegEx.Execute(Range("A" & i).Value)
Range("A" & i).Value = RegEx.Replace(Range("A" & i).Value, NumberStr(0).Value & "Æ")
Next i
End Sub
This regex "\d{1,3}\.\d{4}" reads :
- Numeric character between 1 to 3 times repeated \d{1,3}
- Dot \.
- Numeric character repeated 4 times \d{4}
More info on Regexes.

This will work even if a period occurs after the number.
This won't work if the period occurs before the number
Before:
A1: Hello World, This is a test of 0.1250 and is only a test
A2: Hello World, This is a test of 0.1250 an.d i.s on.ly a te.st
A3: Hello W.orld, This is a test of 0.1250 and is only a test
After:
A1: Hello World, This is a test of 0.1250Æ and is only a test
A2: Hello World, This is a test of 0.1250Æ an.d i.s on.ly a te.st
A3: Hello W.orldÆ, This is a test of 0.1250 and is only a test
Code:
For cell = 1 To 3 ' ENTER MAX ROW
Range("A" & cell).Value = Left(Range("A" & cell).Value, InStr(Range("A" & cell).Value, ".") + 4) & "Æ" & Right(Range("A" & cell).Value, (Len(Range("A" & cell).Value) - 4) - InStr(Range("A" & cell).Value, "."))
Next cell

Related

How to Eliminate Unwanted Text in an Excel Column with Multiple Rows

First I apologize if this question is addressed elsewhere.
Anyway I recently downloaded an excel table with people indicating their race. So if you are Asian you checked "Asian". When I downloaded the data each cell comes with information like Checked:Asian, Unchecked: White, Unchecked: Black, etc,...
See image column highlighted in yellow.
As you can imagine I want the column to only have Checked: Asian and not the other stuff I am not interested in
Question: How do I eliminate the junk?
I tried to use text to columns feature in Excel but it kept only the first column, which I do not want because some of the checked data is in the 3rd or 4th columns.
I already contacted the the app web managers and the response I got was ..sorry that is the way our software works and you will just have to clean it up
yourself Needless to say pretty #$#*&&!! up.
[Google Spreadsheet with Data: Please click the Sheet name "Race" on the Workbook2
Put this formula in a blank column and copy down:
=IFERROR(SUBSTITUTE(FILTERXML("<a><b>"&SUBSTITUTE(B2&" UNCHECKED:",":","</b><b>")&"</b></a>","//b[contains(.,'UN')=false]/following-sibling::*[1]")," UNCHECKED",""),"")
I've put together a VBA function for you that pulls out the "Checked" piece of text. It starts by seeing if the data starts with "CHECKED", in which case it gets the text up to the start of the first "UNCHECKED". If not, then it looks for " CHECKED" (with a space), and again gets the text up to the next "UNCHECKED". It then removes the "CHECKED: " text at the start of the string.
Function fExtractChecked(strData As String) As String
If Left(strData, 7) = "CHECKED" Then
strData = Left(strData, InStr(strData, "UNCHECKED") - 1)
fExtractChecked = strData
ElseIf InStr(strData, " CHECKED") > 0 Then
strData = Mid(strData, InStr(strData, " CHECKED"))
If InStr(strData, "UNCHECKED") > 0 Then
strData = Left(strData, InStr(strData, "UNCHECKED") - 1)
End If
fExtractChecked = strData
End If
If Len(fExtractChecked) > 0 Then
If InStr(fExtractChecked, ":") > 0 Then
fExtractChecked = Mid(fExtractChecked, InStr(fExtractChecked, ":") + 1)
End If
End If
fExtractChecked = Trim(fExtractChecked)
End Function
Just paste the function into a new module, and you can then use this function just like any built-in Excel function, so if your data is in cell B1, you would type this into cell C1:
=fExtractChecked(B1)
Regards,

Returning multiple values using Vlookup in excel

I have an excel sheet set up to automatically calculate meetings per day by day of the week. I would like to write a formula to return all dates I have a meeting scheduled (comma separated preferably), but I am having some difficulty. Using Vlookup, I can only get it to return the first date.
For example, here is what my data looks like:
A B C
Initial Meetings Follow-up Meetings Date
1 1 7/29/2015
0 1 7/30/2015
1 1 7/31/2015
0 0 8/1/2015
0 0 8/2/2015
I would like to write a formula to return "7/29/2015, 7/31/2015" in one cell, and "7/29/2015, 7/30/2015, 7/31/2015" in another, but I seem to be stuck.
You can't do this with vLookup.
This can be done relatively easily in a VB script, but it would affect portability as many if not most users disable macros by default and in many cases users are prevented from using Macros because their company disables them and makes it policy that users should not use them.
If you are OK with Macros, you can put the following into a new module and then use =MultiVlookup(lookup_value,table_array, col_index_num) in the same way as you'd use vlookup and it should give you a comma separated list of multiple matches:
Public Function MultiVlookup(find_value, search_range, return_row)
Dim myval ' String to represent return value (comma-separated list)
Dim comma ' Bool to represent whether we need to prefix the next result with ", "
comma = False
'Debug.Print find_value.value, return_row
For Each rw In search_range.Rows ' Iterate through each row in the range
If rw.Cells(1, 1).value = find_value Then ' If we have found the lookup value...
If comma Then ' Add a comma if it's not the first value we're adding to the list
myval = myval + ", "
Else
comma = True
End If
myval = myval + Str(rw.Cells(1, return_row).value)
End If
Next
MultiVlookup = myval
End Function
This may not be the cleanest way of doing it, and it isn't a direct copy of vlookup (for instance it does not have a fourth "range lookup" argument as vlookup does), but it works for my test:
Finally my original suggestion (in case it helps others - it's not the exact solution to the question) was:
I've not tried it myself, but this link shows what I think you might be looking for.
Great code, but don't forget to add the following is you use Option Explicit:
Dim rw As Range
WHEELS

How to concatenate a list of words into a sentence with "and" before last item in Excel?

I want to join a list of words in Excel (not in VBA... with an Excel formula in the worksheet) to the following specifications:
Formula should ignore empty cells.
Formula should concatenate the words with "and" before final item if there is more than one item in the array of cells.
Formula should add "," between items if there are more than two items.
Examples:
A1=dog
A2=cat
A3=bird
A4=fish
Result would be: dog, cat, bird, and fish
A1=dog
A2=cat
A3=(empty cell)
A4=fish
Result would be: dog, cat, and fish
A1=dog
A2=(empty cell)
A3=bird
A4=(empty cell)
Result would be: dog and bird
A1=dog
A2=(empty cell)
A3=(empty cell)
A4=(empty cell)
Result would be: dog
Pretty please? I promise I've searched and searched for the answer.
Edit: Thank you, ExcelArchitect, I got it! This was the first time I'd ever used a custom function. You use it just like any other function in the worksheet! This is so great.
Not to push my luck, but how to do I get two cells to concatenate with my result if there is only one word in the result and two other cells if there is more than one word? Example: If the function you made for me returns just "dog", I'd want it to concatenate a cell with the text (B1) "My favorite thing to wear is a " and then "dog" and then another cell (B2) that says " costume." to make the sentence "My favorite thing to wear is a dog costume." But if it returns more than one animal, it would concatenate two other cells like this: Cell C1 "My favorite things to wear are " and "dog, cat, and bird" and Cell C2 " costumes." so that it would say "My favorite things to wear are dog, cat, and bird costumes."
If you're curious, my data really has nothing to do with animals or costumes. I am writing a program that will score a psychological test and then create an interpretive report from the test scores (I'm a psychologist).
-Mary Anne
Mary Anne:
This would be a great time to use VBA! But if you don't want to, there is a way to accomplish your goal without it.
You have to account for all of the possible outcomes here. With 4 different animals that means you have 15 outcomes:
Your equation just has to take into account all 15. It is VERY long and drawn out as a result. As such, if you have more than 4 animals that you'd like to turn into phrases, you should go the VBA route.
Here is my set up:
The formula in A7 is the following:
=IF(AND(A2<>"", A3="", A4="", A5=""), A2, IF(AND(A2="", A3<>"", A4="", A5=""), A3, IF(AND(A2="", A3="", A4<>"", A5=""), A4, IF(AND(A2="", A3="", A4="", A5<>""), A5, IF(AND(A2<>"", A3<>"", A4="", A5=""), A2&" and "&A3, IF(AND(A2<>"", A3="", A4<>"", A5=""), A2&" and "&A4, IF(AND(A2<>"", A3="", A4="", A5<>""), A2&" and "&A5, IF(AND(A2="", A3<>"", A4<>"", A5=""),A3&" and "&A4, IF(AND(A2="", A3<>"", A4="", A5<>""), A3&" and "&A5, IF(AND(A2="", A3="", A4<>"", A5<>""),A4&" and "&A5, IF(AND(A2<>"", A3<>"", A4<>"", A5=""), A2&", "&A3&", and "&A4, IF(AND(A2<>"", A3<>"", A4="", A5<>""), A2&", "&A3&", and "&A5, IF(AND(A2<>"", A3="", A4<>"", A5<>""), A2&", "&A4&", and "&A5, IF(AND(A2="", A3<>"", A4<>"", A5<>""), A3&", "&A4&", and "&A5, A2&", "&A3&", "&A4&", and "&A5))))))))))))))
Here it is via Excel:
Mary Anne - I'm such a nerd that I had to do this. Here is the VBA solution, and you can have as many names as you want! Paste this code into a new module in the workbook (go to Developer -> Visual Basic, then Insert -> New Module, and paste), then you can use it in your worksheet like a regular function. Just give it the range where the names are and you should be good to go! -Matt
Function CreatePhrase(NamesRng As Range) As String
'Creates a comma-separated phrase given a list of words or names
Dim Cell As Range
Dim l As Long
Dim cp As String
'Add commas between the values in the cells
For Each Cell In NamesRng
If Not IsEmpty(Cell) And Not Cell.Value = "" And Not Cell.Value = " " Then
cp = cp & Cell.Value & ", "
End If
Next Cell
'Remove trailing comma and space
If Right(cp, 2) = ", " Then cp = Left(cp, Len(cp) - 2)
'If there is only one value (no commas) then quit here
If InStr(1, cp, ",", vbTextCompare) = 0 Then
CreatePhrase = cp
Exit Function
End If
'Add "and" to the end of the phrase
For l = 1 To Len(cp)
If Mid(cp, Len(cp) - l + 1, 1) = "," Then
cp = Left(cp, Len(cp) - l + 2) & "and" & Right(cp, l - 1)
Exit For
End If
Next l
'If there are only two words or names (only one comma) then remove the comma
If InStr(InStr(1, cp, ",", vbTextCompare) + 1, cp, ",", vbTextCompare) = 0 Then
cp = Left(cp, InStr(1, cp, ",", vbTextCompare) - 1) & Right(cp, Len(cp) - InStr(1, cp, ",", vbTextCompare))
End If
CreatePhrase = cp
End Function
Hope that helps!
Matt, via ExcelArchitect.com
VBA is simpler. A formula is quite complicated, since Excel has no native functions allowing concatenation of a range. However, given that you have written that you would have up to eight animals, it is doable with the following formula which concatenates the contents of A1:A8 according to your rules. You can change those locations in the formula in the obvious locations.
I made one change: I may be wrong, but I believe English rules indicate that the comma preceding the last and should be omitted, so I did so. It could be added in if necessary. EDIT: Further investigation reveals a difference between US and UK rules: US rules are as you requested, UK rules omit the comma before the conjunction. I will modify the formulas and UDF to comply with US conventions.
In the formulas, the modification is to place a comma immediately prior to the and. The change in the UDF is likewise minor.
The formula was constructed from the following sequences:
So putting those formulas together, so as only to refer to A1:A8, we wind up with this monster:
=SUBSTITUTE(IFERROR(SUBSTITUTE(MID(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","),2,LEN(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","))-2),",",",and ",LEN(MID(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","),2,LEN(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","))-2))-LEN(SUBSTITUTE(MID(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","),2,LEN(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","))-2),",",""))),MID(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","),2,LEN(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(CONCATENATE(",",A1,",",A2,",",A3,",",A4,",",A5,",",A6,",",A7,",",A8,","),",,",","),",,",","),",,",","))-2)),",",", ")
Here is a VBA solution which will allow for any number of items; it concatenate according to the same rules as above.
Option Explicit
Function ConcatRangeWithAnd(RG As Range, Optional Delim As String = ", ")
Dim COL As Collection
Dim C As Range
Dim S As String
Dim I As Long
Set COL = New Collection
For Each C In RG
If Len(C.Text) > 0 Then COL.Add C.Text
Next C
Select Case COL.Count
Case 0
Exit Function
Case 1
ConcatRangeWithAnd = COL(1)
Case 2
ConcatRangeWithAnd = COL(1) & " and " & COL(2)
Case Else
For I = 1 To COL.Count - 1
S = S & COL(I) & ", "
Next I
ConcatRangeWithAnd = S & "and " & COL(COL.Count)
End Select
End Function
With the new TEXTJOIN function, this can be done very easily.
Step 1: Use TEXTJOIN function with the ", " delimiter, and set the ignore_empty to TRUE. This will give you comma separated, concatenated string, ignoring the blank values.
Step 2: Count the number of not blank entries in the list using COUNTA function. And subtract 1 from it. You might want to floor the value at 1 using the MAX function at this point.
Step 3: Use the SUBSTITUTE function to replace the last instance of the comma, which was calculated in Step 2, with a " and ".
Putting it all together:
=SUBSTITUTE(TEXTJOIN(", ",TRUE,A1:A14),", "," and ",MAX(1,COUNTA(A1:A14)-1))
Plug in any Range you want instead of A1:A14 in the above formula, and you will get a comma separated concatenate with an and before the last word.
Regarding duplicates:
Firstly, I really love Matt's solution and I've added this to my collection of custom functions.
What I do miss though is the possibility to remove duplicates from the phrase without removing them from the original range.
As you can't create a virtual range (a range that you can just play with in VBA independently from your source data), the solution would probably involve converting the range to an array, running some deduplication code and then creating the phrase from that.
My solution (albeit inelegant) is just to use the UNIQUE and FILTER functions to get a deduplicated list elsewhere on the spreadsheet (can be hidden if it bothers you) and to use Matt's function on that.
=UNIQUE(FILTER(yourRange,yourRange<>""))

How to add leading zeros in Excel (timestamp with ms has no leading zeroes)

I’m still having a grave problem with some files. It’s a rather stupid problem, but I’ve been working at it for quite some time and can’t find a solution.
I need leading zeroes in the time stamps, at least on the ms level.
The timestamps that my software makes always look like this: (example)
9:55:1:19 (that is 9h, 55min, 1sec, 19 ms)
while what I need would look like
09:55:01:019
It’s no problem to make a conversion in Excel. I use
=VALUE(SUBSTITUTE(G2;":";",";3))
but I always get
09:55:01:190 (190ms!!)
Thus the milliseconds are always read like comma values, which is understandable from the software’s point of view.
I'd like a solution that either appends the correct values to the end of each row in a new column or directly changes the values in the original column (D) to the correct values. (Appending is OK because my other scripts work that way already!)
Can you help out really quickly?
https://www.dropbox.com/sh/3ch6ikddplnyjgg/vUfnVgbbzH here's an example file
With a value in A1 like:
0.413206238
the formula:
=SUBSTITUTE(TEXT(A1,"hh:mm:ss.000"),".",":")
will display:
09:55:01:019
EDIT#1:
Or if you want to convert the values in column D, in place. Select the cells and run this small macro:
Sub FFormat()
Dim r As Range, L As Long, U As Long
For Each r In Selection
ary = Split(r.Text, ":")
U = UBound(ary)
L = LBound(ary)
For i = L To U
If Len(ary(i)) = 1 Then
ary(i) = "0" & ary(i)
End If
Next i
If Len(ary(U)) = 2 Then
ary(U) = "0" & ary(U)
End If
r.Value = Join(ary, ":")
Next r
End Sub
If the original in R12 (my example) is text, you can enter this big formula: :)
=TEXT(LEFT(SUBSTITUTE(R12;":";REPT(" ";20));4);"00") & ":"&TEXT(MID(SUBSTITUTE(R12;":";REPT(" ";20));14;20);"00") & ":" & TEXT(MID(SUBSTITUTE(R12;":";REPT(" ";20));34;20);"00") & ":" & TEXT(MID(SUBSTITUTE(R12;":";REPT(" ";20));54;20);"000")
Depending on your regional settings you may need to replace field separator "; " by ","
Your data in column G has a leading space - this formula in a new column should convert to a valid time value whether you have leading spaces or not
=LEFT(TRIM(G2);FIND("^";SUBSTITUTE(TRIM(G2);":";"^";3))-1)+LOOKUP(1000;RIGHT(G2;{1;2;3})+0)/86400000
format as [h]:mm:ss.000
This will cope with single or double digit milliseconds, assumes that if there are no milliseconds you will still have third : followed by a zero. Also copes with single digit hours, minutes or seconds

String conversion with TEXT formula character limit?

I am attempting to format a single number stored as a text value.
For example, I would like to convert:
5145350002005000080
To:
5145-350002-00500-0080
The formula I am using is:
=text(A1,"0000-000000-00000-0000")
The output I am receiving is:
5145-350002-00500-0000
Why are the last 4 characters "0000" instead of "0080" as I would expect? Is there a character limit, or is my formula incorrect?
Quote from Large Number Arithmetic:
The limit in Excel is 15 significant digits in a number. Enter a 16
digit credit card number and 1234567890123456 will become
1234567890123450.
Actually, even 5145350002005001111 will result in 5145-350002-00500-0000.
Moreover, take a look at formula bar when your input cell is selected - for my Excel 2007 I see:
Hope that was helpful)
EDITED:
As a solution to solve the task - keep your numbers formatted as text and use the following formula:
=LEFT(A1,4)&"-"&MID(A1,5,6)&"-"&MID(A1,11,5)&"-"&RIGHT(A1,4)
Here is a custom function. Place it in a regular code module of the workbook and you can call it in the cell by =FormatLargeNumber("A1")
Public Function FormatLargeNumber(val As String)
'This function parses extremely large numbers per your example.
' Modify as needed.
FormatLargeNumber = Left(val, 4) & "-" _
& Mid(val, 5, 6) & "-" & _
Mid(val, 11, 5) & "-" & _
Right(val, 4)
End Function

Resources