How do you separate text in excel vba by "CamelCase" and numbers - excel

I'm trying to make a molecular composition calculator but i can seem to separate a formula by case and numbers into different cells.
Is it possible to do this in excel?
Eg:
Cl2H0 ----> Cl | 2 | H | 0

A bit crude but you could write a parsing function like this that returns an array:
Public Function parseChem(str As String) As Variant()
'should error-check first that entire string is correct
Dim retArr() As Variant
Dim i As Long, numBlocks As Long
Dim currentChar As String, currentElement As String, typeOfChar As String
Dim digitChain As Boolean
For i = 1 To Len(str)
currentChar = Mid(str, i, 1)
typeOfChar = charType(currentChar)
Select Case typeOfChar
Case Is = "upperCase"
If currentElement <> "" Then
'possibly cast numbers to longs here, and at the end...
retArr(numBlocks) = currentElement
End If
numBlocks = numBlocks + 1
ReDim Preserve retArr(1 To numBlocks)
currentElement = currentChar
digitChain = False
Case Is = "lowerCase"
currentElement = currentElement & currentChar
Case Is = "digit"
If digitChain Then
currentElement = currentElement & currentChar
Else
'new digit block
retArr(numBlocks) = currentElement
numBlocks = numBlocks + 1
ReDim Preserve retArr(1 To numBlocks)
digitChain = True
currentElement = currentChar
End If
Case Else
'do something to flag error
End Select
Next i
retArr(numBlocks) = currentElement
parseChem = retArr
End Function
Private Function charType(str As String) As String
Dim ascii As Long
ascii = Asc(str)
If ascii >= 65 And ascii <= 90 Then
charType = "upperCase"
Exit Function
Else
If ascii >= 97 And ascii <= 122 Then
charType = "lowerCase"
Exit Function
Else
If ascii >= 48 And ascii <= 57 Then
charType = "digit"
Exit Function
End If
End If
End If
End Function

OK the algorithm in the end is very simple
If at any point in the formula you have a number, then look for the next capital letter and output all characters up to that point.
If at any point in the formula you have a letter, then look for the next capital letter *or number* and output all characters up to that point.
The formula is rather long
=IF(ISNUMBER(MID($A$1,SUM(LEN($B$1:B1))+1,1)+0),
MID(MID($A$1,SUM(LEN($B$1:B1))+1,9),1,MIN(FIND( MID("ABCDEFGHIJKLMNOPQRSTUVWXYZ",ROW($1:$26),1),MID($A$1,SUM(LEN($B$1:B1))+2,9)&"ABCDEFGHIJKLMNOPQRSTUVWXYZ" ))),
MID(MID($A$1,SUM(LEN($B$1:B1))+1,9),1,MIN(FIND( MID("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",ROW($1:$36),1),MID($A$1,SUM(LEN($B$1:B1))+2,9)&"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ))))
must be entered as an array formula using CtrlShiftEnter and the 9 would need increasing ( or changing to len($a1) ) if the formula was longer than 9 characters.
Here's a shorter version that doesn't have to be entered as an array formula
=IF(ISNUMBER(MID($A1,SUMPRODUCT(LEN($B1:B1))+1,1)+0),
MID(MID($A1,SUMPRODUCT(LEN($B1:B1))+1,9),1,AGGREGATE(15,6,FIND( MID("ABCDEFGHIJKLMNOPQRSTUVWXYZ",ROW($1:$26),1),MID($A1,SUMPRODUCT(LEN($B1:B1))+2,9)&"A" ),1)),
MID(MID($A1,SUMPRODUCT(LEN($B1:B1))+1,9),1,AGGREGATE(15,6,FIND( MID("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",ROW($1:$36),1),MID($A1,SUMPRODUCT(LEN($B1:B1))+2,9)&"A"),1)))

If you are familiar with VBA then you could write a function which reads in the cell value (e.g. Cl2H0) and then a For Loop that splits the string into seperate values. You would then write these seperated values (Cl, 2, H and 0) back to indivisual columns on the excel sheet.
One way of doing this would be to use the Asc() function in a loop which will give you the Ascii number corresponding to an indivisual charachter. Ascii charachters 65 to 90 are Upper Case charachters. In your case you would want to split the string when the charachter does not fall within this range.
If you want to try this and post your example then I can give some more guidance but its hard to give more advide without first understanding if you are trying to achieve this with VBA or some other means.

Related

Remove numbers from end of string if count of numbers(characters) > 8

I need to remove numbers from end of string if count of numbers(characters) > 8
I have used the below functions , but it remove all numbers from the string.
So, How this function can be modified to add a condition if count of numbers(characters) > 8
In advance, grateful for any helpful comments and answers.
Option Explicit
Function StripNumber(stdText As String)
Dim str As String, i As Integer
stdText = Trim(stdText)
For i = 1 To Len(stdText)
If Not IsNumeric(Mid(stdText, i, 1)) Then
str = str & Mid(stdText, i, 1)
End If
Next i
StripNumber = str ' * 1
End Function
Function Remove_Number(Text As String) As String
With CreateObject("VBScript.RegExp")
.Global = True
.Pattern = "[0-9]"
Remove_Number = .Replace(Text, "")
End With
End Function
You can use
\d{8,}(?=\.\w+$)
\d{8,}(?=\.[^.]+$)
See the regex demo. If there must be at least 9 digits, replace 8 with 9.
Details:
\d{8,} - eight or more digits
(?=\.\w+$) - that are immediately followed with a . and one or more word chars and then end of string must follow
(?=\.[^.]+$) - the eight or more digits must be immediately followed with a . char and then one or more chars other than a . char till the end of string.
If you have access to the newest functions you can avoid VBA alltogether:
Formula in B2:
=LET(X,TEXTBEFORE(A2,".",-1),Y,TEXTAFTER(A2,X),Z,TEXTAFTER(CONCAT(".",IFERROR(--MID(X,SEQUENCE(LEN(X)),1),".")),".",-1),IF(LEN(Z)>8,SUBSTITUTE(A2,Z&Y,Y),A2))
Or, if there are no leading zeros in these numbers:
=LET(X,TEXTBEFORE(A2,".",-1),Y,TEXTAFTER(A2,X),Z,MAX(IFERROR(--MID(X,SEQUENCE(LEN(X)),LEN(X)),"")),IF(LEN(Z)>8,SUBSTITUTE(A2,Z&Y,Y),A2))
Or; a spilled array:
Formula in B2:
=BYROW(A2:A6,LAMBDA(a,LET(X,TEXTBEFORE(a,".",-1),Y,TEXTAFTER(a,X),Z,TEXTAFTER(CONCAT(".",IFERROR(--MID(X,SEQUENCE(LEN(X)),1),".")),".",-1),IF(LEN(Z)>8,SUBSTITUTE(a,Z&Y,Y),a))))
Or:
=BYROW(A2:A6,LAMBDA(a,LET(X,TEXTBEFORE(a,".",-1),Y,TEXTAFTER(a,X),Z,MAX(IFERROR(--MID(X,SEQUENCE(LEN(X)),LEN(X)),"")),IF(LEN(Z)>8,SUBSTITUTE(a,Z&Y,Y),a))))

How to split a number into individual digits VB using substring

I tried to put seconds in 2 text-boxes, each digit in one. Example x= 56 x1= 5 and x2= 6
' s = TimeOfDay.Second
TextBox15.Text = s.Substring(0, 1)
TextBox16.Text = s.Substring(1, 1)'
When I try this I get the following error: System.ArgumentOutOfRangeException
Any ideas on how to fix this?
ArgumentOutOfRange exceptions occurs whenever you attempt to get a character that doesn't exist at the given position. So what is happening is that there is either not a String at position 0 with a length of 1 or there is not a String at position 1 with a length of 1.
To prevent this, add a simple If/Then statement to check if the length of the original String at least equal to the position of the character. Also for what it's worth, since you only want one letter, simply get the character at the desired index of the String.
Here is a quick example:
If s.Length >= 1 Then
TextBox15.Text = s(0).ToString()
End If
If s.Length >= 2 Then
TextBox16.Text = s(1).ToString()
End If
Fiddle: Live Demo
You don't need to convert it to a string before getting the digits, just doing the maths to get them will work well enough:
Dim rightNow = DateTime.Now
TextBox15.Text = (rightNow.Second \ 10).ToString()
TextBox16.Text = (rightNow.Second Mod 10).ToString()
And another approach.
Dim c() As Char = DateTime.Now.Second.ToString("00").ToArray
TextBox1.Text = c(0)
TextBox2.Text = c(1)

VBA generate a code

there. I made this code that replaces a character for two number (e.g. 0 = 10; 1 = 11; 2 = 12; ...) and everything works fine except for the first element (the zero element). So, if I put "010a4" string on cell A1 and use my formula "=GENERATECODE(A1)", my expected return value is "1011102014" but I've got a "110111102014" string. So, only zero value occur this error and I can't figured out why. Any thoughts?
My code:
Function GENERATECODE(Code As String)
Dim A As String
Dim B As String
Dim i As Integer
Const AccChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Const RegChars = "1011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071"
For i = 1 To Len(AccChars)
A = Mid(AccChars, i, 1)
B = Mid(RegChars, 2 * i - 1, 2)
Code = Replace(Code, A, B)
Next
GENERATECODE = Code
End Function
Your problem is that your code first change each 0 to 10 then each 1 to 11. So each 0 give you 10 then 110.
If you want to keep the same kind of algorithm (which might not be a good choice), you need to change AccChars and RegChars so that a character is never replaced by a string that can give a character found later on the AccChars String. In your case just replace Const AccChars = "012 ... per Const AccChars = "102 ... and Const RegChars = "101112 ... per Const RegChars = "111012 ...
But it might be better to change your algorithm altogether. I would first suggest to not use in place editing of the string, but rather to use 2 Strings.
In addition to being incorrect, your current code is inefficient since it involves scanning over the code string multiple times instead of just once. Simply scan over the string once, gathering the substitutions into an array which is joined at the end:
Function GENERATECODE(Code As String) As String
Dim codes As Variant
Dim i As Long, n As Long
Dim c As String
n = Len(Code)
ReDim codes(1 To n)
For i = 1 To n
c = Mid(Code, i, 1)
Select Case c
Case "0" To "9":
codes(i) = "1" & c
Case "a" To "z":
codes(i) = Asc(c) - 77
Case "A" To "Z":
codes(i) = Asc(c) - 19
Case Else:
codes(i) = "??"
End Select
Next i
GENERATECODE = Join(codes, "")
End Function
Example:
?generatecode("010a4")
1011102014
The point of the two offsets is that you want "a" to map to 20 and "A" to map to 46. Note Asc("a") - 77 = 97 - 77 and Asc("A") - 19 = 65-19 = 46.

How do I perform a XOR calculation of two binary numbers in excel 2007

I wanted to perform a XOR calculation of two Binary numbers for example: on Sheet 1
Range A1 = 10101010
Range A2 = 11100010
Now I need to perform XOR of A1, A2 result in A3. I tried different formula's two perform XOR calculations like: A1^A2, (BITXOR (A1, A2)) but unfortunately it didn't worked I think because I am using excel 2007 "XOR" doesn't support.
I'm expecting a result of 1001000.
First, you should note that Excel pre-Excel2013 has no bitwise operators or functions built-in (Excel's OR() function is logical even if the operands are numeric). Excel 2013 finally adds this glaringly missing functionality.
Using VBA
The simplest way is to create a User Defined Function that does it. Formulae can work if you are prepared for either a decimal output, or helper columns, or a very repetitive Concatenate formula but VBA gets around these limitations - I recommend it if you are able to have code in the workbook.
Decimal Input, Decimal Output
The below examples just expose the built-in bitwise operators to use as functions in Excel formulae. I assume an integral type, although you could change it to accept decimals etc.
You can convert your string binary numbers (e.g. "1010") to decimals (10, for the previous example) using the BIN2DEC() function built-in to Excel, although this only handles 9 bits + sign bit, alternatively you can use an array formula to convert it for you (see my section on "Using Formulas" below).
Public Function BITWISE_OR(operand1, operand2)
BITWISE_OR = CLng(operand1) Or CLng(operand2)
End Function
Public Function BITWISE_AND(operand1, operand2)
BITWISE_AND = CLng(operand1) And CLng(operand2)
End Function
Public Function BITWISE_XOR(operand1, operand2)
BITWISE_XOR = CLng(operand1) Xor CLng(operand2)
End Function
Converting the numeric results back to binary strings is pretty annoying with formulas - if you need more than the range covered by DEC2BIN() (a paltry -512 to +511) function built in to Excel then I would suggest either using VBA (see below), or building up your binary string bit by bit using columns or rows (see my Using Formulas section below).
Binary string input, Binary string output
The below essentially iterates through a string setting each bit in turn based on the corresponding bits in the input strings. It performs the bit changes on the string in-place using Mid$ statement. Bit strings can be arbitrary length.
The below looks complicated but really it is the same basic stuff repeated 3 times for each of And, Or and XOr.
'str1, str2: the two bit strings. They can be different lengths.
'significantDigitsAreLeft: optional parameter to dictate how different length strings should be padded. Default = True.
Public Function Bitstr_AND(str1 As String, str2 As String, Optional significantDigitsAreLeft As Boolean = True)
Dim maxLen As Long, resStr As String, i As Long
If Len(str1) > Len(str2) Then maxLen = Len(str1) Else maxLen = Len(str2) 'get max length of the two strings
str1 = getPaddedString(str1, maxLen, significantDigitsAreLeft) 'pad left or right to the desired length
str2 = getPaddedString(str2, maxLen, significantDigitsAreLeft) 'pad left or right to the desired length
resStr = String$(maxLen, "0") 'prepare the result string into memory (Mid$ can operate without creating a new string, for performance)
For i = 1 To maxLen
If Mid$(str1, i, 1) = "1" And Mid$(str2, i, 1) = "1" Then
Mid$(resStr, i, 1) = "1" 'in-place overwrite of the existing "0" with "1"
End If
Next i
Bitstr_AND = resStr
End Function
'For explanatory comments, see Bitstr_AND
Public Function Bitstr_OR(str1 As String, str2 As String, Optional significantDigitsAreLeft As Boolean = True)
Dim maxLen As Long
Dim resStr As String
Dim i As Long
If Len(str1) > Len(str2) Then maxLen = Len(str1) Else maxLen = Len(str2)
str1 = getPaddedString(str1, maxLen, significantDigitsAreLeft)
str2 = getPaddedString(str2, maxLen, significantDigitsAreLeft)
resStr = String$(maxLen, "0")
For i = 1 To maxLen
If Mid$(str1, i, 1) = "1" Or Mid$(str2, i, 1) = "1" Then
Mid$(resStr, i, 1) = "1"
End If
Next i
Bitstr_OR = resStr
End Function
'For explanatory comments, see Bitstr_AND
Public Function Bitstr_XOR(str1 As String, str2 As String, Optional significantDigitsAreLeft As Boolean = True)
Dim maxLen As Long
Dim resStr As String
Dim i As Long
If Len(str1) > Len(str2) Then maxLen = Len(str1) Else maxLen = Len(str2)
str1 = getPaddedString(str1, maxLen, significantDigitsAreLeft)
str2 = getPaddedString(str2, maxLen, significantDigitsAreLeft)
resStr = String$(maxLen, "0")
For i = 1 To maxLen
If Mid$(str1, i, 1) = "1" Then
If Not Mid$(str2, i, 1) = "1" Then
Mid$(resStr, i, 1) = "1"
End If
ElseIf Mid$(str2, i, 1) = "1" Then 'Save an If check by assuming input string contains only "0" or "1"
Mid$(resStr, i, 1) = "1"
End If
Next i
Bitstr_XOR = resStr
End Function
'Helper to pad string
Private Function getPaddedString(str As String, length As Long, padLeft As Boolean) As String
If Len(str) < length Then
If padLeft Then
getPaddedString = String$(length - Len(str), "0") & str
Else
getPaddedString = str & String$(length - Len(str), "0")
End If
Else
getPaddedString = str
End If
End Function
Using Formulas
You can do an XOR operation using Text functions or Sumproduct. This may be more appropriate if you do not want to use VBA but formulas are painful to ensure they covers all situations, like negatives or different length binary strings. I refer you to the superb blog post http://www.excelhero.com/blog/2010/01/5-and-3-is-1.html for examples using Sumproduct, and http://chandoo.org/wp/2011/07/29/bitwise-operations-in-excel/ for examples using Text functions.
I cooked up my own formulae that handles certain cases and I explain them below to guide you.
Binary string Input, Decimal Output
In the below, A2 and B2 refer to the two binary numbers in up to 32-bits string form. The strings can be variable length, as the formula will pad with 0's to the necessary length. It should be obvious how to increase it to more bits. They must be entered using Ctrl+Shift+Enter.
The most significant bit is on the left. To make it least significant bit on the left, you can remove the little subtraction in the powers of 2 part, and make it pad to the right.
Bitwise And:
=SUM((((MID(REPT("0",32-LEN($A$2))&$A$2,ROW($1:$32),1)="1")+(MID(REPT("0",32-LEN($B$2))&$B$2,ROW($1:$32),1)="1"))=2)*(2^(32-ROW($1:$32))))
Bitwise Or:
=SUM((((MID(REPT("0",32-LEN($A$2))&$A$2,ROW($1:$32),1)="1")+(MID(REPT("0",32-LEN($B$2))&$B$2,ROW($1:$32),1)="1"))>0)*(2^(32-ROW($1:$32))))
Bitwise Xor:
=SUM((((MID(REPT("0",32-LEN($A$2))&$A$2,ROW($1:$32),1)="1")+(MID(REPT("0",32-LEN($B$2))&$B$2,ROW($1:$32),1)="1"))=1)*(2^(32-ROW($1:$32))))
Binary string input, Binary string Output
A single cell solution would be arduous because there is no array concatenation formula in Excel. You could do it using the CONCATENATE function glueing together each bits, with each bit being the result of an If comparing each binary string returning 1 or 0 as appropriate. As I said, though easy (just build it up like =IF(Mid(A1,1,1) = "1",...), this would be boring so I personally won't do it for you ;)
Alternatively, you could do it more simply using columns or rows to build up the string, like:
If A1 and B1 have your binary strings, then in C1 put (for AND, or for OR change the =2 at the end to >0 and for XOR change it to =1):
=IF((MID($A1,1,1)="1")+(MID($B1,1,1)="1"))=2,"1","0")
Then in D1 put:
=C1 & IF((MID($A1,COLUMN()-COLUMN($C1),1)="1")+(MID($B1,COLUMN()-COLUMN($C1),1)="1"))=2,"1","0")
Then drag this across as many columns as bits

How can you convert HEX to BIN, one character at a time in EXCEL 2010

I am trying to find a way to take a string of HEX values and convert them to BIN. I need to convert 1 HEX character at a time:
For example: HEX = 0CEC
BIN = 0000 1100 1110 1100
I need to do this in Excel. Any help would be great.
Thanks,
Larry
In a module:
Public Function HEX2BIN(strHex As String) As String
Dim c As Long, i As Long, b As String * 4, j As Long
For c = 1 To Len(strHex)
b = "0000"
j = 0
i = Val("&H" & Mid$(strHex, c, 1))
While i > 0
Mid$(b, 4 - j, 1) = i Mod 2
i = i \ 2
j = j + 1
Wend
HEX2BIN = HEX2BIN & b & " "
Next
HEX2BIN = RTrim$(HEX2BIN)
End Function
For:
=HEX2BIN("0CEC")
0000 1100 1110 1100
Yes, I had to do this recently. I'm late to the game, but other people will have to do this from time to time, so I'll leave the code where everyone can find it:
Option Explicit
Public Function HexToBinary(strHex As String, Optional PadLeftZeroes As Long = 5, Optional Prefix As String = "oX") As String
Application.Volatile False
' Convert a hexadecimal string into a binary
' As this is for Excel, the binary is returned as string: there's a risk that it will be treated as a number and reformatted
' Code by Nigel Heffernan, June 2013. Http://Excellerando.Blogspot.co.uk THIS CODE IS IN THE PUBLIC DOMAIN
' Sample Usage:
'
' =HexToBinary("8E")
' oX0010001110
'
' =HexToBinary("7")
' oX001111
'
' =HexToBinary("&HD")
' oX01101
Dim lngHex As Long
Dim lngExp As Long
Dim lngPad As Long
Dim strOut As String
Dim strRev As String
If Left(strHex, 2) = "&H" Then
lngHex = CLng(strHex)
Else
lngHex = CLng("&H" & strHex)
End If
lngExp = 1
Do Until lngExp > lngHex
' loop, bitwise comparisons with successive powers of 2
' Where bitwise comparison is true, append "1", otherwise append 0
strRev = strRev & CStr(CBool(lngHex And lngExp) * -1)
lngExp = lngExp * 2
Loop
' As we've done this in ascending powers of 2, the results are in reverse order:
If strRev = "" Then
HexToBinary = "0"
Else
HexToBinary = VBA.Strings.StrReverse(strRev)
End If
' The result is padded by leading zeroes: this is the expected formatting when displaying binary data
If PadLeftZeroes > 0 Then
lngPad = PadLeftZeroes * ((Len(HexToBinary) \ PadLeftZeroes) + 1)
HexToBinary = Right(String(lngPad, "0") & HexToBinary, lngPad)
End If
HexToBinary = Prefix & HexToBinary
End Function
You can use HEX2BIN(number, [places]).
The HEX2BIN function syntax has the following arguments:
Number Required. The hexadecimal number you want to convert. Number cannot contain more than 10 characters. The most significant bit of number is the sign bit (40th bit from the right). The remaining 9 bits are magnitude bits. Negative numbers are represented using two's-complement notation.
Places Optional. The number of characters to use. If places is omitted, HEX2BIN uses the minimum number of characters necessary. Places is useful for padding the return value with leading 0s (zeros).
I would use a simple formula as follows:
=HEX2BIN(MID(S23,1,2))&HEX2BIN(MID(S23,3,2))&HEX2BIN(MID(S23,5,2))&HEX2BIN(MID(S23,7,2)&HEX2BIN(MID(S23,9,2)&HEX2BIN(MID(S23,11,2)&HEX2BIN(MID(S23,13,2))
cell S23 = BFBEB991, Result = 10111111101111101011100110010001
This would allow it to be as long you need. Just add as many repetitions as you need incrementing the start position by 2 (eg 1, 3, 5, 7, 9, 11, 13, 15, ....). Note that the missing characters will be ignored.
For me, it gives this (sorry, in VBA, but has the advantage of not asking you the length of your string to convert). Be careful, I put a comment in the lower part for which you can add a space between each section of 4 bits. Some don't want the space and some will need it:
Length = Len(string_to_analyse)
For i = 1 To Length
Value_test_hexa = Left(Right(string_to_analyse, Length - (i - 1)), 1)
'get the asci value of each hexa character (actually can work as a decimal to binary as well)
Value_test = Asc(Value_test_hexa)
If Value_test > 47 And Value_test < 58 Then
Value_test = Value_test - 48
End If
' Convert A to F letters to numbers from 10 to 15
If Value_test > 64 And Value_test < 71 Then
Value_test = Value_test - 55
End If
'identify the values of the 4 bits for each character (need to round down)
a = WorksheetFunction.RoundDown(Value_test / 8, 0)
b = WorksheetFunction.RoundDown((Value_test - a * 8) / 4, 0)
c = WorksheetFunction.RoundDown((Value_test - a * 8 - b * 4) / 2, 0)
d = (Value_test - a * 8 - b * 4 - c * 2)
Value_converted = Value_converted & a & b & c & d ' can eventually add & " " in order to put a space every 4 bits
Next i
Tested OK so you can go with it.
Just leaving this here for anyone who needs it.
Instead of manually converting from hex to binary, I used Excel's built-in HEX2BIN function.
Function hexToBin(hexStr As String) As String
Dim i As Integer, b As String, binStr As String
For i = 1 To Len(hexStr)
b = Application.hex2bin(Mid(hexStr, i, 1), 4)
binStr = binStr & b
Next i
hexToBin = binStr
End Function

Resources