Using a formula, not VBA, I would like to come up with a solution to split a string composed of multiple words. The formula should recognize the words where there is a capital letter and separate them. The result would be a string where the words are separated by ",".
To clarify this is an example of the string:
Nursing StudentStudentNurseNursing School
Desired Result:
Nursing Student,Student,Nurse,Nursing School
I am trying the following formula but I can only isolate the first word:
{=LEFT(Q4,SMALL(FIND(CHAR(ROW(INDIRECT("65:90"))),Q4&"ABCDEFGHIJKLMNOPQRSTUVWXYZ"),2)-1)}
Any suggestion?
To accomplish this, you will need pure VBA. Create a custom Function to get in 1 cell the string you want. Then, use Text to Columns later if you need it.
My function:
Public Function GET_STRING(ByVal ThisCell As Range) As String
Dim i As Integer
Dim MyPositions As String
Dim ArrPositions As Variant
For i = 2 To Len(ThisCell.Value) Step 1
If Mid(ThisCell.Value, i, 1) = UCase(Mid(ThisCell.Value, i, 1)) And _
Mid(ThisCell.Value, i, 1) <> " " And Left(Mid(ThisCell.Value, i - 1, 1), 1) <> " " Then MyPositions = MyPositions & i & ";"
Next i
ArrPositions = Split(Left(MyPositions, Len(MyPositions) - 1), ";")
For i = 0 To UBound(ArrPositions) Step 1
If i = 0 Then
GET_STRING = Left(ThisCell.Value, ArrPositions(i) - 1) & "," & Mid(ThisCell.Value, ArrPositions(i), ArrPositions(i + 1) - ArrPositions(i))
ElseIf i <> UBound(ArrPositions) Then
GET_STRING = GET_STRING & "," & Mid(ThisCell.Value, ArrPositions(i), ArrPositions(i + 1) - ArrPositions(i))
Else
GET_STRING = GET_STRING & "," & Mid(ThisCell.Value, ArrPositions(i), Len(ThisCell.Value) - ArrPositions(i) + 1)
End If
Next i
End Function
What I get when i use it on excel
You're pushing the envelope with this requirement. What you want to achieve requires looping over the same string repeatedly. That can only be done with recursion and Excel formulas don't do recursion.
With modern Excel 2016 you have Power Query (Get & Transform, or the add-in for Excel 2010 and 2013) and you can use that to write out the logic in M code if you don't want to use VBA. Power Query can be saved in a macro-free workbook and new data can be processed with the click of the "Refresh all" command in the ribbon.
In B2:C28 fill in these :
A ,A
B ,B
C ,C
D ,D
E ,E
F ,F
G ,G
H ,H
I ,I
J ,J
K ,K
L ,L
M ,M
N ,N
O ,O
P ,P
Q ,Q
R ,R
S ,S
T ,T
U ,U
V ,V
W ,W
X ,X
Y ,Y
Z ,Z
,
Note: B28 = , C28 =
then in A2 =SUBSTITUTE(A1,B2,C2) then drag until A28,
in A29 =RIGHT(A28,LEN(A28)-1) Done.
Hope that helps. (:
+------[edit]-----+
or in one line :
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"Z",",Z"),"Y",",Y"),"X",",X"),"W",",W"),"V",",V"),"U",",U"),"T",",T"),"S",",S"),"R",",R"),"Q",",Q"),"P",",P"),"O",",O"),"N",",N"),"M",",M"),"L",",L"),"K",",K"),"J",",J"),"I",",I"),"H",",H"),"G",",G"),"F",",F"),"E",",E"),"D",",D"),"C",",C"),"B",",B"),"A",",A")," ,"," ")
This is what I use in access VBA
Pass a string like
?GET_SPLIT_STRING("SplitAtCapitals")
and get back the following
Split At Capitals
Public Function GET_SPLIT_STRING(xStr As String) As String
Dim i As Integer, xchar As String, ychar As String
ychar = UCase(Left(xStr, 1))
For i = 2 To Len(xStr) Step 1
xchar = Mid(xStr, i, 1)
If asc(xchar) = asc(UCase(xchar)) Then
xchar = Space(1) & xchar
End If
ychar = ychar & xchar
Next
GET_SPLIT_STRING = ychar
End Function
Related
I'm trying to turn general data written as fractions like 3/4" or 13 7/32" into 3 place decimal numbers such as 0.750 or 13.219.
I have a working table replacement that handles 0 to 1" fractions. It can't handle the mixed numbers like 13 7/32". It leaves me with 13 0.219 which is why I need to replace " 0." with "." to join the 13 and 219 together with a decimal.
We do this data conversion in multiple steps and hand type because Excel tries converting some fractions like 3/4" into a date.
Original data
Resulting data
Sub FractionConvertMTO()
'this section works
For i = 6 To 70
Worksheets("BOM").Range("F6:H48").Select
Selection.Replace what:=Cells(i, 21).Value, Replacement:=Cells(i, 22).Value, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
Next
'this section doesn't work
For i = 6 To 70
Worksheets("BOM").Range("F6:H48").Select
str1 = " "
str1 = Trim(Replace(str1, " ", "+"))
Next
'this section changes the format.
For i = 66 To 130
Range("F6:H48").NumberFormat = "0.000"
Next
'this section is supposed to add an = sign in front of the cell contents but doesn't work.
Dim Cell As Range
For Each Cell In Range("F6:H48")
Cell.Value = "=" & Cell.Value
Next Cell
'this section works to highlight the first cell
Worksheets("BOM").Cells(1, 1).Select
End Sub
I dug up the following method from my library of useful functions. It converts numbers represented as a fractional string to the numeric equivalent. Simply loop through the cells needing conversion and call this method:
Public Function FractionToNumber(ByVal Value As String, Optional ByVal Digits As Long = 0) As Double
Dim P As Integer
Dim N As Double
Dim Num As Double
Dim Den As Double
Value = Trim$(Value)
P = InStr(Value, "/")
If P = 0 Then
N = Val(Value)
Else
Den = Val(Mid$(Value, P + 1))
Value = Trim$(Left$(Value, P - 1))
P = InStr(Value, " ")
If P = 0 Then
Num = Val(Value)
Else
Num = Val(Mid$(Value, P + 1))
N = Val(Left$(Value, P - 1))
End If
End If
If Den <> 0 Then N = N + Num / Den
FractionToNumber = Round(N, Digits)
End Function
You may also code something like the following:
Sub FractionConvertMTO()
Dim rng As Range
Dim Arr As Variant
Arr = Worksheets("MTO").Range("F6:H48")
For Row = 1 To UBound(Arr, 1)
For col = 1 To UBound(Arr, 2)
str1 = Arr(Row, col)
pos1 = InStr(str1, " ")
pos2 = InStr(str1, "/")
If pos2 = 0 Then
N = val(str1)
Num = 0: Den = 1
Else
If pos1 And pos1 < pos2 Then
N = val(Left$(str1, pos1 - 1))
Num = val(Mid$(str1, pos1 + 1))
Else
N = 0
Num = val(Left$(str1, pos2 - 1))
End If
Den = val(Mid$(str1, pos2 + 1))
End If
Arr(Row, col) = N + Num / Den
Next col
Next Row
Worksheets("MTO").Range("F6", "H48") = Arr
End Sub
If you dispose of the newer dynamic array features (vers. 2019+,MS365) you might write the results in one go to the entire original range (target range) as follows (overwriting the existing range; otherwise define a given offset to identify another target range: rng.Offset(,n)=..).
Tip: make a backup copy before testing (as it overwrites rng)!
Note that this example assumes the " character (asc value of 34).
A) First try via tabular VALUE() formula evaluation
Caveat: converting blanks by VALUE() would be written as #VALUE! results, which would need a further loop. To avoid this you can prefix a zero to the formulae myFormula = "=VALUE(SUBSTITUTE(" & """0""&" & rng.Address & ","""""""",""""))" so that results would be displayed as zero.
Sub ChangeToFractionValues()
'1) define original range to be replaced
Dim rng As Range
Set rng = ThisWorkbook.Worksheets("BOM").Range("F6:H48")
'2) define tabular formula
Dim myFormula As String
'myFormula = "=VALUE(SUBSTITUTE(" & rng.Address & ","""""""",""""))"
'Alternative to avoid #VALUE! displays for blanks:
myFormula = "=VALUE(SUBSTITUTE(" & """0""&" & rng.Address & ","""""""",""""))"
'Debug.Print myFormula
'3) overwrite original range (otherwise code an offset rng.Offset(,n).Value = ...
rng.Value2 = rng.Parent.Evaluate(myFormula)
End Sub
Conclusion due to comment:
Though fast, this approach has a big disadvantage: Excel interpretes date-like numbers as such, transforms them internally to dates by returning the numeric part here, so a cell input of 3/4" would return the corresponding date value of the current year for March 4th.
B) Reworked code based on direct cell evaluations in a loop //Edit
Similar to the above processing this approach is also based on evaluation, but collects all formulae as strings in a variant datafield array v, which allows to manipulate and evaluate each cell input individually:
Sub ChangeToFractionValues()
'1) define original range to be replaced
Dim rng As Range
Set rng = ThisWorkbook.Worksheets("BOM").Range("F6:H48")
'2) assign formula strings to variant 1-based 2-dim data field array
Dim v As Variant
v = rng.Formula2
'3) evaluate results in a loop
Dim i As Long, j As Long
For i = 1 To UBound(v)
For j = 1 To UBound(v, 2)
v(i, j) = Evaluate("0" & Replace(v(i, j), Chr(34), ""))
Next j
Next i
'4) overwrite original range (otherwise code an offset rng.Offset(,n).Value = ...
rng.Value = v
End Sub
str1 = trim(Replace(str1, "0.", "."))
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Lets say there is some text in a cell that reads
"this is a block of text (.7) and in this block of text (1.2) there are numbers (2.5) and these numbers need to be added together (.4)"
The answer to the sum of all these numbers would be .7+1.2+2.5+.4= 4.8
My question is, is there a way that I can have excel add all the numbers together from a block of text and just output the answer? It will always be the sum of the numbers and the numbers will always be positive. The amount of numbers will vary, it could be 2 it could be 15, could be anything.
What I have tried so far: I've tried "=sum" and highlighting the entire cell which always gives the answer "0"
Try the following User Defined Function:
Public Function Addum(rng As Range) As Double
Dim s As String, L As Long, temp As String
Dim CH As String
s = rng.Value
L = Len(s)
For i = 1 To L
CH = Mid(s, i, 1)
If CH Like "[0-9]" Or CH = "." Then
temp = temp & CH
Else
temp = temp & " "
End If
Next i
temp = Application.WorksheetFunction.Trim(temp)
arr = Split(temp, " ")
For Each a In arr
Addum = Addum + CDbl(a)
Next a
End Function
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:
The original code tries to convert a standalone period into a number. Replace the original UDF with this version:
Public Function Addum(rng As Range) As Double
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' VERSION #2
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim s As String, L As Long, temp As String
Dim CH As String
s = rng.Value
L = Len(s)
For i = 1 To L
CH = Mid(s, i, 1)
If CH Like "[0-9]" Or CH = "." Then
temp = temp & CH
Else
temp = temp & " "
End If
Next i
temp = Application.WorksheetFunction.Trim(temp)
arr = Split(temp, " ")
For Each a In arr
If IsNumeric(a) Then
Addum = Addum + CDbl(a)
End If
Next a
End Function
EDIT#2:
This version (VERSION 3) will only process numbers encapsulated in parens:
Public Function Addum(rng As Range) As Double
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' VERSION #3
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim s As String, L As Long, temp As String
Dim CH As String
s = rng.Value
L = Len(s)
For i = 1 To L
CH = Mid(s, i, 1)
If CH Like "[0-9]" Or CH = "." Or CH = "(" Or CH = ")" Then
temp = temp & CH
Else
temp = temp & " "
End If
Next i
temp = Application.WorksheetFunction.Trim(temp)
arr = Split(temp, " ")
For Each a In arr
If Left(a, 1) = "(" Then
a = Mid(a, 2, Len(a) - 2)
If IsNumeric(a) Then
Addum = Addum + CDbl(a)
End If
End If
Next a
End Function
Here is a UDF using Regular Expressions which will add only those values that are within parentheses:
Option Explicit
Function sumNumsInParenth(S As String) As Double
Dim RE As Object, MC As Object, M As Object
Dim dSum As Double
Set RE = CreateObject("vbscript.regexp")
With RE
.Global = True
.Pattern = "\((\d*(?:\.\d+)?)\)"
If .test(S) = True Then
Set MC = .Execute(S)
For Each M In MC
dSum = dSum + M.submatches(0)
Next M
End If
End With
sumNumsInParenth = dSum
End Function
Explanation of the Regex pattern
capture floating point numbers within parentheses, integer portion optional
\((\d*(?:\.\d+)?)\)
Options: Case insensitive; ^$ match at line breaks
Match the opening parenthesis character \(
Match the regex below and capture its match into backreference number 1 (\d*(?:\.\d+)?)
Match a single character that is a “digit” \d*
Between zero and unlimited times, as many times as possible, giving back as needed (greedy) *
Match the regular expression below (?:\.\d+)?
Between zero and one times, as many times as possible, giving back as needed (greedy) ?
Match the character “.” literally \.
Match a single character that is a “digit” \d+
Between one and unlimited times, as many times as possible, giving back as needed (greedy) +
Match the closing parenthesis character \)
Created with RegexBuddy
This array formula will do it:
=SUM(IF(ISNUMBER(--TRIM(MID(SUBSTITUTE(SUBSTITUTE(A1,"(",REPT(" ",99)),")",REPT(" ",99)),(ROW(1:100)-1)*99+1,99))),--TRIM(MID(SUBSTITUTE(SUBSTITUTE(A1,"(",REPT(" ",99)),")",REPT(" ",99)),(ROW(1:100)-1)*99+1,99))))
Being an array formula it must be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode.
I need help in solving the problem:
Formula in Excel cell is like this-> =20000-17000+1000 , I need to split the figures in different columns like this-> 20000 | 17000 | 1000 , no problem with removing + / -, I can live without them. Unable to find any help hence posted here.
Thanking in advance.example given
CTR+H and change sign - into whatever unique like # then replace + the same way into #.
After having 20000#17000#1000use:
Data/Text to columns/Delimited/Other and type #
You may record a macro to have it automated.
This Sub can do it:
Public Sub SplitSum(rngInput As Range, rngOutputStart As Range)
Dim varParts As Variant: varParts = Split(Replace(Replace(Mid(rngInput.Formula, 2), "-", "|"), "+", "|"), "|")
Dim c As Long: For c = LBound(varParts) To UBound(varParts)
rngOutputStart.offset(0, c - LBound(varParts)).Value = CDbl(varParts(c))
Next c
End Sub
You can use it like this:
SplitSum ActiveCell, ActiveCell.Offset(0, 1)
This function will preserve the sign before your numbers and has been written simply so as to permit you easy access for further tweaking if necessary.
Sub SumsToColumns(Rng As Range)
Dim RngVal As String
Dim Vals() As String
Dim n As Integer
RngVal = Trim(Rng.Cells(1).Formula)
If Len(RngVal) Then
RngVal = Mid(Replace(RngVal, "+ ", "+"), 2)
RngVal = Replace(RngVal, " +", " +")
RngVal = Replace(RngVal, "- ", "-")
RngVal = Replace(RngVal, "-", " -")
Do
n = Len(RngVal)
RngVal = Replace(RngVal, " ", " ")
Loop While Len(RngVal) < n
Vals = Split(RngVal)
For n = 0 To UBound(Vals)
With Rng
.Worksheet.Cells(.Row, .Column + n + 2).Value = Vals(n)
End With
Next n
End If
End Sub
You can call this function with a line like this:-
SumsToColumns(Range("G13"))
where "G13" is a range you might extract from a simple procedure that loops through all cells in a column. Please take note of the following line in the code.
.Worksheet.Cells(.Row, .Column + n + 2).Value
It specifies that the result should be written in the same worksheet as where the Range("G13") was taken from, in the same row (13 in this case) and starting 2 columns to the right, in this case "G" + 2 columns = "I". You can modify the "2" to any offset you might require. The result will be split over as many columns as there are separate numbers in G13.
I have a columns of strings as follows. How can I put the symbol '<' in between the characters ?
'ABCDE'
'BCG'
'ABCD'
The expected output should be:
A<B<C<D<E
B<C<G
A<B<C<D
=concatenate(left(A1,1),"<",mid(A1,2,1),"<",mid(A1,3,1),(if(len(A1)>3,"<"&mid(A1,4,1)&if(len(A1)>4,"<"&mid(A1,5,1),""),"")))
Will do what you want for values up to 5 letters, and as few as 3 letters. Otherwise you can change it.
Basically it adds a "<" between the first 3 letters and then checks whether the string is longer than 3 letters and if so, adds more "<" characters. If this needs to be more dynamic it's far easier in vba.
A manual, one-off, no-VBA approach would be:
use the Text to Columns tool with Fixed Width and place the markers after each character.
then use a formula like this to append values and separator
The formula could look like this if your values are in row 1
=A1&IF(LEN(B1)>0,">"&B1,"")&IF(LEN(C1)>0,">"&C1,"")&IF(LEN(D1)>0,">"&D1,"")&IF(LEN(E1)>0,">"&E1,"")
Adjust formula to suit the maximum number of characters in a cell.
Such things are not for formulas...
As you tag question as Excel-VBA too, so:
'''''''
Private Sub sb_Test_fp_AddSym()
Debug.Print fp_AddSym("abncd", "<")
End Sub
Public Function fp_AddSym(pStr$, pSym$) As String
Dim i&, j&, iLB&, iUBs&, iUBt&
Dim tSrc() As Byte, tTgt() As Byte, tSym As Byte
tSrc = pStr
tSym = Asc(pSym)
iLB = LBound(tSrc)
iUBs = UBound(tSrc)
iUBt = iUBs * 2 + 3
ReDim tTgt(iLB To iUBt)
For i = iLB To iUBs Step 2
j = i * 2
tTgt(j) = tSrc(i)
tTgt(j + 1) = tSrc(i + 1)
tTgt(j + 2) = tSym
tTgt(j + 3) = 0
Next
ReDim Preserve tTgt(iLB To (iUBt - 4))
Debug.Print tTgt
Stop
fp_AddSym = tTgt
End Function
'''
This worked for me:
Sub SymbolInsert()
Dim cl As Range, temp As String
For Each cl In Range("A1:A3") '~~~> Define your range here
For i = 1 To Len(cl)
temp = temp & Mid(cl, i, 1) & "<"
Next i
cl = IIf(VBA.Right$(temp, 1) = "<", VBA.Left$(temp, Len(temp) - 1), temp)
temp = vbNullString
Next cl
End Sub
It can probably be done with Excel formula for any length, but here is the shortest VBA solution
For Each c In Range("A:A").SpecialCells(xlCellTypeConstants)
c.Value2 = Replace( Left$( StrConv( c, vbUnicode), Len(c) * 2 - 1), vbNullChar, "<")
Next
I have some code for move text from cell to cell
Dim startIndex As Integer
Dim toIndex As Integer
Dim f As String
Dim g As String
For startIndex = 50 To 60 Step 2
toIndex = Str(startIndex + 1)
f = "F" & Str(toIndex)
g = "G" & Str(startIndex)
Range(f).Value = Range(g).Value
Range(g).Value = ""
Next startIndex
But variable f has "F 51" value instead of "F51".
How solve this problem ?
p.s. It's my first code on vba.
You should be using
CStr
not
Str
Then no workaround is needed for removing an unncessary space
ie
f = "F" & CStr(toIndex)
g = "G" & CStr(startIndex)
From Excel help for Str
When numbers are converted to strings, a leading space is always reserved for the sign of number.
You could TRIM() the toIndex or REPLACE spaces in the end result, i.e.
Replace ("alphabet", "a", "e") 'would return "elphebet"
example lifted from here: http://www.techonthenet.com/excel/formulas/replace.php
So...
f = Replace (f, " ", "")