Using Excel 2007 and inexperienced with VBA.
I am trying to create a text generator where, given a particular type of entry, it returns a string of text AND a number of corresponding cells.
I have a lot of data to combine and somewhat complex text statements. The data I have here is sample data. The final file will combine multiple text strings ("one" and "two", etc) with multiple cells that need to be referenced based on the specific data input there (some instances require 8 different cells).
I was able to figure out how to do Select Case where it can look up the type of entry I need, and it returns a specific text string. Great! I also know I can combine things like "One" & "Two". But how do I combine the corresponding text for the line?
Where if the entry was "ID" I could return something that looked like "One 1" but combines "One " & K2 as the .Value to return?
Image shows the sample data
Image shows data for Columns I, J, and K.
Column I stores the entry type, J is where the data is returned, and K is the column with data to be referenced. Again, what's here is the simplified reference data.
I know this line is wrong. But I'm not sure what to put in place for K2 so it will correctly reference the cell, and then loop correctly for 300 times.
Case Is = "ID": .Value = "One" & (K2)
Am I close to something workable? What would you suggest? Is Select Case the wrong way to handle this problem?
I've tried a number of options, but I am inexperienced with VBA. I think whatever I implemented to fix the issue was likely done incorrectly.
Full code of what I have shown below.
Private Sub CommandButton1_Click()
Dim logtype As Range
For Each logtype In Range("I2:I302")
With logtype.Offset(0, 1)
Select Case logtype.Value
Case Is = "ID": .Value = "One" & K2
Case Is = "Phase": .Value = "Two"
Case Is = "Install New": .Value = "Three"
Case Is = "Install OH": .Value = "Four"
Case Is = "Install AR": .Value = "Five"
Case Is = "Insp": .Value = "Six"
Case Is = "LUI": .Value = "Seven"
Case Is = "": .Value = ""
Case Else: .Value = "Not Recognized"
End Select
End With
Next logtype
End Sub
EDIT:
What I put in a comment below, just formatted more clearly.
I want to create a macro that spits out the correct language of an entry based on the kind of work completed in a work order.
For example, ID or Install New and then return the correct language and reference data for the entry:
I2: ID
K2: Number (I'd type in the actual No.)
Returns:
"Complied with ID No. [K2]. No defects noted."
I4: Install New
L4: Actual part number
M4: etc...
N4: ...
O4: ...
Returns:
"Removed P/N [L4], S/N [M4]. Installed P/N [N4], S/N [O4]. Ops checked good."
Does that make sense? Thanks!
EDIT 2:
Hey everyone, I've tried tracking down alternative methods of solving this problem but I still haven't produced anything better than what I have here.
Any thoughts or help would be greatly appreciated. Thank you!
For each cell in Range("I2:I302")
cell.offset(0,1).value=cell.offset(0,1).text & cell.offset(0,2).text
next
Please take a look at the attached image. I have a long list of items and I've created a common keywords to search in that list. I'm using this formula:
=INDEX(A:A,MATCH((("*"&B2&"*")&("*"&C2&"*")&("*"&D2&"*")&("*"&E2&"*")&("*"&F2&"*")),A:A,0))
The problem that the search is going through the same sequence that I entered.
It gives error if the sequence of the words in the cell is different than the sequence in my formula which make sense.
Is there a way I can search for 3 or more words that are existing in any cell in any sequence?
I am open to using VBA if necessary.
My search results:
Here is the user defined function:
Public Function indexMX(rng As Range, pat1 As Range, pat2 As Range, pat3 As Range, pat4 As Range, pat5 As Range) As Variant
Dim r As Range, rngx As Range, s(1 To 5) As String, Kount As Long, j As Long
s(1) = pat1.Value
s(2) = pat2.Value
s(3) = pat3.Value
s(4) = pat4.Value
s(5) = pat5.Value
Set rngx = Intersect(rng, rng.Parent.UsedRange)
For Each r In rngx
v = r.Value
Kount = 0
For j = 1 To 5
If InStr(1, v, s(j)) > 0 Or s(j) = "" Then Kount = Kount + 1
Next j
If Kount = 5 Then
indexMX = v
Exit Function
End If
Next r
indexMX = "no luck"
End Function
Here is an example of its usage:
As you see, we give the UDF() the address of the column and the addresses of the five keywords and the UDF() finds the first item containing all five words.
If a keyword is blank, it is not used. (so if you want to search for only two keywords, leave the other three blank). If no matches are found the phrase no luck is returned.
User Defined Functions (UDFs) are very easy to install and use:
ALT-F11 brings up the VBE window
ALT-I
ALT-M opens a fresh module
paste the stuff in and close the VBE window
If you save the workbook, the UDF will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the UDF:
bring up the VBE window as above
clear the code out
close the VBE window
To use the UDF from Excel:
=myfunction(A1)
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
and for specifics on UDFs, see:
http://www.cpearson.com/excel/WritingFunctionsInVBA.aspx
Macros must be enabled for this to work!
EDIT#1:
to remove case sensitivity, replace:
If InStr(1, v, s(j)) > 0 Or s(j) = "" Then Kount = Kount + 1
with:
If InStr(1, LCase(v), LCase(s(j))) > 0 Or s(j) = "" Then Kount = Kount + 1
Yes, it is possible for a single cell to return three matching words from a different cell. The answer in this example uses a formula to return 6 matches. VBA and special array functions are not used.
This is the formula:
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUMPRODUCT((IFERROR(SEARCH(FIRST,TARGET),0)>0)*100000+(IFERROR(SEARCH(SECOND,TARGET),0)>0)*20000+(IFERROR(SEARCH(THIRD,TARGET),0)>0)*3000+(IFERROR(SEARCH(FOURTH,TARGET),0)>0)*400+(IFERROR(SEARCH(FIFTH,TARGET),0)>0)*50+(IFERROR(SEARCH(SIXTH,TARGET),0)>0)*6),"1",FIRST&DELIM),"2",SECOND&DELIM),"3",THIRD&DELIM),"4",FOURTH&DELIM),"5",FIFTH&DELIM),"6",SIXTH&DELIM),"0","")
Did you notice the named ranges? FIRST, SECOND, THIRD, etc are individual cells and each one holds a word. We are trying to find those words inside TARGET. If we find the words, then we will write them in this cell holding this formula and each word will be separated by DELIM
The ranges are optional. In the picture below, you'll see cell A2 contains the word "named". This is the first of the six words we're tying to find and it can be expressed as FIRST = "A2" = "named" Inside the formula you'll see that FIRST appears twice. You could replace it with "named" and the cell A2 would become blank but the functionality of the formula would not change.
Even TARGET is optional. It could be written as E1 or typed out word for word.
I don't know why anyone would do that... but it is possible.
DELIM is at cell B2, it is a double space
Now to explain how it works
SEARCH(search for what?, search where?) This is responsible for determining if a match exists or not. If you understand what the named ranges then you've already figured out the syntax is. The location of first letter that of match in TARGET is returned. In this formula it is always 1 If it is not found then the number is 0
IFERROR(value,value) tries to perform the operation. If successful then the result is displayed. If there's an error the second result is displayed. Every IFERROR in this formula is practically the same: IFERROR(SEARCH(FIRST,TARGET),0) It searches inside TARGET trying to find the FIRST word. Result if found is 1 and if not found is 0
It gets a little more complicated from here so lets recap. We're calling SEARCH 6 times. Once for each word we want to find and we're always looking in TARGET. Result will be a 1 if match is found or a 0 if not. Ironically, us humans can put it together and see the match but the formula can't determine which words have been matched without more information
SUMPRODUCT takes the sum (addition) of the product (multiplication) of two or more arrays.
multiply two arrays to get the product
a, b, c * e, f, g = ae, bf, cg
takethe sum of the product to get the SUMPRODUCT
ae + bf + cg`
This is easiest when thought of a price and quantity. If one array is the price of a group of items and the other is quantity of the same group of items, then multiplying the two arrays will create a new array where each element is the cost to buy all items of that type in the group the total, and adding all those numbers give you the total cost you'd pay for all of the items
Here we multiply two arrays:
Qty Price
12.0 0.3
70.0 0.1
20.0 0.4
Multiply them to get the product:
Qty Price Total
12.0 0.3 3.8
70.0 0.1 7.0
20.0 0.4 8.0
Take the sum of the product:
Qty Price Total
12.0 0.3 3.8
70.0 0.1 7.0
20.0 0.4 8.0
18.8 SUMPRODUCT
Lets look at part of the formula:
SUMPRODUCT((IFERROR(SEARCH(FIRST,TARGET),0)>0)*100000+IFERROR(SEARCH(SECOND,TARGET),0)>0)*20000+...
It is easy to see this segment is looking for two words. We know SUMPRODUCT want's to multiply and add arrays. If you're thinking (IFERROR(SEARCH(FIRST,TARGET),0)>0) is an array, you'd be right! It's not an array in the technical sense of the word, but it does evaluate into a single value which can thought of as a 1x1 array, or, a cell. The sharp eyed and quick witted, may have noticed there is something on this array we have mentioned. It's the inequality at the end! Many of you know that you can take numerical values and turn them into boolean by testing them with an inequality. So lets evaluate.... SEARCH for FIRST inside TARGET = 1 because FIRST = "named" which is inside TARGET waaaaaaay in the back and because it wasn't an error we get to keep the 1. Next we do the inequality 1 > 0 = TRUE One is greater than zero and evaluates to TRUE
This is what we have right now
SUMPRODUCT((TRUE*100000+IFERROR(SEARCH(SECOND,TARGET),0)>0)*20000+....
Can you identify the arrays now? We know TRUE is an array, a 1x1. You know the IFERROR bit all the way to the inequality is also an array. Lets evaluate that IFERROR .... Mathematically we should still be working from left to right but trust me, we're ok if we let it slide this once.
IFERROR(SEARCH(SECOND,TARGET),0)>0) SECOND = "array" = 1 = TRUE
Did you follow my short hand? It's ok if you didn't just back up and practice on FIRST until you understand.
Plugging in the value gives us something like this
SUMPRODUCT(TRUE*100000+TRUE*20000+...
SUMPRODUCT is the SUM(addition) of the PRODUCT(multiplication)
So we're adding the stuff we multiply
SUMPRODUCT = (TRUE * 100000) + (TRUE * 20000)
Remember how easy it was to go from 1 > 0 to TRUE. We're "getting all up into that boolean TRUE that" equals 1 Here's a fun fact, -1 is also equal to TRUE. If you've ever seen a formula with a double negative in it like this STUFF(--(MORESTUFF( that's just some Excel wizard person making sure they get a +1 instead of a -1 ... ok, so lets get back on track and evalute
SUMPRODCUT = 1 * 100000 + 1 * 20000+....
SUMPRODCUT = 100000 + 20000+....
SUMPRODCUT = 120000+.....
I know you've been asking about those numbers. One hundred thousand? What's one hundred thousand for? I've been purposefully ignoring until it became convenient to talk about it. And now it's convenient. Go look at the whoooole formula and you'll find a pattern. Those numbers are in a decreasing sequence. Anyone who's ever done bitwise logic can see where this is going.I'm running short on time so I'll cut to the chase. Assume a hypothetical situation where every word was matched. You'd end up with
SUMPRODUCT = 100000 + 20000 + 3000 + 400 + 50 + 6
SUMPRODCUT = 123456
123456 are you pulling my leg? No, I am not. We're almost done so if you're still with me then you're gonna drive it home.
We have a large group of SUBSTITUTE teachers at the front of the line and we gotta get rid of them.
We also have this to contend with :"1",FIRST&DELIM),"2",SECOND&DELIM),"3",THIRD&DELIM),"4",FOURTH&DELIM),"5",FIFTH&DELIM),"6",SIXTH&DELIM),"0","")
Thankfully for us, they are part of the same problem. We worked our way from the middle out.
SUBSTITUTE(SUBSTITUTE(text, old text, new text)
SUBSTITUTE(SUBSTITUTE("123456","1", FIRST & DELIM),"2",SECOND & DELIM)....
Remember at top DELIM was pointing to a cell holding a double space. Each DELIM can be replaced with " " or any other delimiter you want.
SUBSTITUTE(SUBSTITUTE("123456","1", "named" & " "),"2",SECOND & DELIM)...
SUBSTITUTE("named 23456","2",SECOND & DELIM)...
SUBSTITUTE("named 23456","2","array"& " ")...
("named array 3456")... and so on.
Any questions?
Ok, class is dismissed!
I wish to compare two cells in excel which contain similar text but one containing different delimiters in it. I want to ignore the delimiters while comparing the strings.
Eg.
John Doe: Mary Ann. Are Married/
John Doe Mary Ann Are Married
I am totally unaware of macros. Any leads are appreciated!
If you have Office 365 Excel then we can use this array formula:
=TEXTJOIN("",TRUE,IF(((CODE(UPPER(MID(A1,ROW(INDIRECT("1:" & LEN(A1))),1)))>=65)*(CODE(UPPER(MID(A1,ROW(INDIRECT("1:" & LEN(A1))),1)))<=90))+(CODE(UPPER(MID(A1,ROW(INDIRECT("1:" & LEN(A1))),1)))=32),MID(A1,ROW(INDIRECT("1:" & LEN(A1))),1),""))=TEXTJOIN("",TRUE,IF(((CODE(UPPER(MID(A2,ROW(INDIRECT("1:" & LEN(A2))),1)))>=65)*(CODE(UPPER(MID(A2,ROW(INDIRECT("1:" & LEN(A2))),1)))<=90))+(CODE(UPPER(MID(A2,ROW(INDIRECT("1:" & LEN(A2))),1)))=32),MID(A2,ROW(INDIRECT("1:" & LEN(A2))),1),""))
Being an array formula it must be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode. If done correctly then Excel will put {} around the formula.
You can try this:
Function CompareByLetter(t1 As String, t2 As String) As Boolean
CompareByLetter = CleanString(t1) = CleanString(t2)
End Function
Function CleanString(t As String) As String
Dim t1, x, c
For x = 1 To Len(t)
c = Asc(UCase(Mid(t, x, 1)))
If (c >= 65 And c <= 90) Or c = 32 Then t1 = t1 & Mid(t, x, 1)
Next x
CleanString = t1
End Function
Then you can use it as a formula:
=CompareByLetter(A1,A2)
This macro just compares strings by only keeping letters and spaces.
You can also use =CleanString(A1) to remove all other characters from your strings.
To use this in your project, open excel and press ALT+F11
Right click off to the left side and select Insert -> Module
Paste the code into the module window on the right (see attached).
Image mirror since Stackoverflow image hosting seems down
After that, you should be able to use the functions as you would a formula.
Just enter =CompareByLetter(A1,A2) in a cell.
I have two columns with codes relating to various products. It is a 3-part code delimitized with a '-'. The length of each of the 3 parts are not constant and are alphanumeric.
The need is that I have to categorize them according to 4 criterias:
Compare each of the codes in B against A and vice-versa, and categorize them all as below and in the image:
1. Exactly Matched codes
2. Prefix or Suffix Changes codes
3. Totally New codes
However there seems to be a complication. The codes in two columns are not necessarily sorted and there can be a match anywhere in the other column, Is there a way to look up for the text and then do the compare function. I know this opens up a lot of complications -- my thought is to look up the value, and then pass the parameters to get the category.. Thanks again!!! – user1087661 1 hour ago
Kindly help me achieve this. Is there any formula to check through an array and Find functions? many thanks for the support.
you can use split function and select case to deal with your problem. i assume you know how to use a UDF.
Function CompareCode(Text1, Text2, Optional Delim = "-")
Dim T1, T2, CC
T1 = Split(Text1, Delim)
T2 = Split(Text2, Delim)
CC = (T1(0) <> T2(0)) * 100 + (T1(1) <> T2(1)) * 10 + (T1(2) <> T2(2)) * 1
CC = Format(-CC, "000")
Select Case CC
Case "000": CompareCode = "Same code"
Case "100": CompareCode = "Prefix changed"
Case "010": CompareCode = "Base changed"
Case "110": CompareCode = "Prefix and base changed"
Case "001": CompareCode = "Suffix changed"
Case "101": CompareCode = "Prefix and suffix changed"
Case "011": CompareCode = "Base and suffix changed"
Case "111": CompareCode = "Totally new code"
Case Else:
End Select
End Function
This is merely a partial answer:
For the first part, the exactely matching codes, you can use a simple lookup formula such as SUMIFS() where you are matching the items in Column B to the whole set in Column A.
For the other two requirements, if I wanted to do this by formula, then I would use the LEN(), LEFT() and RIGHT() formulas to extract the prefix, base, and sufix into separate columns. Do this for both Group A and B.
Finding your matching groups should become fairly straight forward from that point on.
Does anybody know if it is possible to show numbers in MS Excel with SI-prefixes?
I'd like to have
... 1 n, 1 µ, 1 m, 1, 1 k, 1M, 1 G, ...
instead of scientific format
... 1E-09, 1E-06, 1E-03, 1, 1E+03, 1E+06. 1E+09, ...
Perhaps adding an unit like V (volts), F (farad) etc.
I would be perfect, if the cell would still contain the number and not a string, so it can easily be changed to another format (back to scientific or whatever)
You can do something like this, which I got from Millions & Thousands Custom Number Formatting :
[>=1000000] #,##0.0,," MΩ";[<1000000] #,##0.0," kΩ";General
400 renders as 0.4 kΩ (probably not what you want)
4000 renders as 4.0 kΩ
40e3 renders as 40.0 kΩ
40e6 renders as 40.0 MΩ
but you can probably add more clauses to cover other ranges. Nevermind, you can't.
You can also use LOG and CHOOSE to keep it in a single formula and reasonably compact.
=ROUND(
E10 / (1000 ^ INT(LOG(ABS(E10),1000)) )
,0
) & CHOOSE(
INT(LOG(ABS(E10),1000)) + 6
,"f","p","n","µ","m","","k","M","G","T","P"
)
In this formula:
E10 (referred to 3 times) is the cell containing the raw value.
ROUND formats number for display, here rounding to no decimals (0).
INT(LOG(ABS(E10),1000)) is the prefix index -5 through +5.
CHOOSE is the prefix to use (needs positive index, hence + 6).
No solution will work better than scientific notation.
If you use custom number formats, then you would have to enter them manually (or with VBA) such that they will mask the actual content of the cell.
For instance, if you want to display the following format pairs:
1 n 1E-09
1 µ 1E-06
1 m 1E-03
1 1
1 k 1E+03
1 M 1E+06
1 G 1E+09
If you have 0.001, you would have to set the format as "1 m" -- this will mask the number, so if you have 0.002 you would have to set it as "2 m" -- if you changed it to 0.004 it would still display 2 m as a result. This obviously isn't ideal.
You could set it up as a two-column sheet, where you have the values in the left, and use a formula to display with units on the right, but then you end up not being able to do math with the formatted values.
So basically, the answer is "no", it isn't possible.
You could theoretically write a VBA script that will automatically change the visible contents according to the cell contents whenever a number is changed, but the script would be bulky and would cause serious trouble to whoever you sent to if they had macros off. It would also require all sorts of corner cases depending on if you wanted numbers formatted 'normally' in certain cells. So while it may be theoretically possible, it is practically impossible
It is possible, though bulky using a conversion table and the match and index functions.
From a conversion table like this (2 columns):
1.E+15 P
1.E+12 T
1.E+09 G
1.E+06 M
1.E+03 k
1.E+00
1.E-03 m
1.E-06 µ
1.E-09 n
1.E-12 p
1.E-15 f
You could then perform the following translation
3.68437E+11 --> 368.44 G
If you have the conversion table in columns A and B
and the unformatted number in cell G1
H1
=G1/INDEX(A:A,MATCH(G1,$A:$A,-1)+1)
I1
=INDEX($B:$B,MATCH(G1,$A:$A,-1)+1)
Then the proper numerals will display in column H with the suffix/prefix in column I.
It is still ponderous, and should only be used for final output since calculations from the modified numbers will have to include a reverse translation.
There's no way I know of to do this as a number format (where you can then use the formatted number as you would any other numeric value for subsequent calculation), but for simply presenting the number using SI prefixes, here's the formula I use. It takes the formula in the specified cell (usually next to it, in this case E28), scales the number, rounds to the specified number of significant figures (in this case 3), appends the appropriate SI prefix, and then appends the specified unit (in this case 'F' for Farads). The advantage here is that the formula is self-contained and doesn't require any external reference tables. This formula works for femto (10^-15) through Tera (10^12), but can easily be expanded for additional prefixes
=CONCAT(
ROUND(
IF(E28>1E12, E28/1E12,
IF(E28>1E9, E28/1E9,
IF(E28>1E6, E28/1E6,
IF(E28>1E3, E28/1E3,
IF(E28>1, E28,
IF(E28>1E-3, E28*1E3,
IF(E28>1E-6, E28*1E6,
IF(E28>1E-9, E28*1E9,
IF(E28>1E-12, E28*1E12,
E28*1E15
) ) ) ) ) ) ) ) ),
3 +N("This is the number of significant digits to round to")
-(1+INT(LOG10(ABS(
IF(E28>1E12, E28/1E12,
IF(E28>1E9, E28/1E9,
IF(E28>1E6, E28/1E6,
IF(E28>1E3, E28/1E3,
IF(E28>1, E28,
IF(E28>1E-3, E28*1E3,
IF(E28>1E-6, E28*1E6,
IF(E28>1E-9, E28*1E9,
IF(E28>1E-12, E28*1E12,
E28*1E15
) ) ) ) ) ) ) ) ) ))))
),
IF(E28>1E12, "T",
IF(E28>1E9, "G",
IF(E28>1E6, "M",
IF(E28>1E3, "k",
IF(E28>1, "",
IF(E28>1E-3, "m",
IF(E28>1E-6, "µ",
IF(E28>1E-9, "n",
IF(E28>1E-12, "p",
"f"
) ) ) ) ) ) ) ) ),
"F" +N("This is the unit symbol that will be appended to the end")
)
If you want to round to a fixed number of decimal figures as opposed to significant figures, the formula is a little simpler:
=CONCAT(
ROUND(
IF(E28>1E12, E28/1E12,
IF(E28>1E9, E28/1E9,
IF(E28>1E6, E28/1E6,
IF(E28>1E3, E28/1E3,
IF(E28>1, E28,
IF(E28>1E-3, E28*1E3,
IF(E28>1E-6, E28*1E6,
IF(E28>1E-9, E28*1E9,
IF(E28>1E-12, E28*1E12,
E28*1E15
) ) ) ) ) ) ) ) ),
3 +N("This is the number of decimal digits to round to")
),
IF(E28>1E12, "T",
IF(E28>1E9, "G",
IF(E28>1E6, "M",
IF(E28>1E3, "k",
IF(E28>1, "",
IF(E28>1E-3, "m",
IF(E28>1E-6, "µ",
IF(E28>1E-9, "n",
IF(E28>1E-12, "p",
"f"
) ) ) ) ) ) ) ) ),
"F" +N("This is the unit symbol that will be appended to the end")
)
Note that I've written all of the scaling constants in exponential notation, Excel will change these to plain numbers when you enter the formula. By using a relative cell reference, it's pretty easy to copy and paste the formula around where you need it.
The formula could be condensed into a single block of IF/CONCAT/ROUND statements, but arranging it as I've done here separates out the rounding constant into a single point in the formula, making it easier to change.
Just select the cell or range of cells you want to contain the given symbol. Right click on the cell and select FORMAT CELLS. Select the NUMBER format on the left, enter decimal places, etc on the right. Now go all the way down the list of your format options on the left and select CUSTOM. (IMPORTANT: Do NOT select ANY custom format options on the right.) Left click in the box just below TYPE: and above the list of custom format options. (This box displays your current selected format. {0.00 if you selected the default number format} You want to keep this formatting AND add additional formatting.) Click to the right of 0.00 and type the following: " μ" Click OKAY and you may enter your data as normal. Formatting cells has no impact on the values you enter. You can perform all functions as normal. I am attaching a pic where I used the same instructions to apply litters and the greek MU notation to values and performed some basic calculations without impeding Excel's ability to function.Special Notation in Excel
This is a limited answer for Google Sheets, using actual number formats instead of expressions that output text.
Spinning off from endolith's answer, I settled on this:
[>=1E6] #,##0.0,,"M";[>1E3] #,##0.0,"K";0.#####################
It works on numbers from 1 to <1E16, though can't be expanded to units above M. Doesn't work for negative numbers or fractional numbers. It is limited by the number of conditional sections Google Sheets is able to parse.
Docs: https://developers.google.com/sheets/api/guides/formats#number_format_patterns
' Hans Wolfgang Schulze 20190921, cause I always need this and need to write it again cause I forgot where I saved it.
' Paste this into Excel's Macro Editor (F11) and use from any cell.
' Copyleft 2019. Please include original author's name in all derivative works.
'
' Note that the conversions in this code is assuming normal Base 10, and not Binary 1024. Lots of code has to change.
' Currently recognizes numbers like "-123123.123G" or "123E15" with or without actual units.
' Special case of Excel's "-" nothing equals 0.
' Assumes, if exists, that the rightmost character is the SI exponent designation - See expS below.
' Usage: =DSci("45e9k") gives "4.5E12" as an answer.
Const expS = "-qryzafpnum KMGTPEZYRQ" ' https://en.wikipedia.org/wiki/Metric_prefix
Function DSci(inputS As String) As Double
Dim which As Integer
which = InStr(expS, Right(inputS, 1))
whichUnitary = InStr(expS, " ") ' offset into expS for " " unity value
If which = 0 Then
which = InStr("----F-Nµ- k-gt-e", Right(inputS, 1)) ' try alt case and form that aren't obscure ie k=K or m!=M
End If
If which > 0 Then ' has a terminating exponential character. 1 is not found.
If which = 1 Then ' "-"
DSci = 0 ' excel nothing value (0)
Else ' convert only the left side of input
DSci = CDbl(Left(inputS, Len(inputS) - 1)) * 10# ^ ((which - whichUnitary) * 3#) ' fix for Binary K's
End If
Else
DSci = CDbl(inputS) ' convert whole string instead ' special case devide by 1.024 for each 1000 for Binary K's
End If
End Function
' Formats to SI convention 10 ^ (-30 ... +30) and recent suggested expansions
' Usage =Sci(5.531e9, "B") gives string of "5.531GB"
' Significant digits are suggested as 4, can be any positive number.
Function Sci(value As Double, optionalUnit As String, Optional significant As Integer = 4) As String
Dim mant As Double, exp As Double, rank As Integer
rankUnitary = InStr(expS, " ") ' offset into expS for " " unity value
If value = 0 Then exp = 0 Else exp = Log(value) / Log(10#) ' nDigits
mant = value / (10# ^ exp) '
While mant >= 999.9999999999 ' don't want 2000K, rather 2M. Change to 1023.9999999999# for Binary K's
exp = exp + 3#
mant = mant / 1000# ' change to 1024# for binary K's etc.
Wend
rank = Int((exp + 0.0000000000001) / 3#) ' should be >1E-300 or so? Why not? 3 != 3#? More changes for Binary K's ?
mant = mant * 10# ^ (-rank * 3# + exp) ' adjust mantussa after de-ranking. Change?? for Binary K's
If Abs(rank) >= rankUnitary Then ' outside of +/- yY bounds
expChar = "?" ' what do you call it then? Not defined.
Else
expChar = Mid(expS, rank + rankUnitary, 1) ' add SI
End If
Sci = Left(mant, Abs(significant)) ' don't allow negative numbers, pretend they are positive lengths
If Right(Sci, 1) = "." Then Sci = Left(Sci, Len(Sci) - 1) ' lop off right DP
Sci = Sci & " " & expChar & optionalUnit
End Function