Splitting text to columns in Excel - excel

I have a column in Excel that consists of data in the following format: "NAME OF BAND Album Title". I'd like to split this cell into two--one for the all-caps band name and another for Album Title. Below are a few examples from the data:
Column A
ABSORBED Demo '98
ABSTRACT CELL THEORY Act
ABSTRACT SATAN Elite 7512
ABSTRACT SATAN Aryan Blitzkrieg Union
ABSTRACT SATAN Satanic Blood Circle
ABSTRACT SHADOWS Symphony of Hakel
Splitting by space doesn't work since bands have varying numbers of words in their name. Any help would be appreciated.

Here is a formula solution. No VBA required.
Assuming your list starts in cell A1, enter the following formula in cell B1:
=LEFT(A1,MATCH(,--(CODE(MID(A1,ROW(OFFSET($A$1,,,LEN(A1))),1))<96),)-3)
This is an array formula and must be confirmed with Ctrl+Shift+Enter.
And then in cell C1, enter this:
=MID(A1,MATCH(,--(CODE(MID(A1,ROW(OFFSET($A$1,,,LEN(A1))),1))<96),)-1,99)
This is an array formula and must be confirmed with Ctrl+Shift+Enter.
Now select the range B1:C1 and copy downward as far as needed.
.
Here is how they work. We'll discuss the first formula.
The MID function splits the value of cell A1 into individual characters. The CODE function returns the ASCII code number for each char. We test each code number to see if it is less than 96, which is "a" the first lower case char.
This gives us an array of Boolean values (TRUE or FALSE), one Booelan value for each char in cell A1.
We convert the Booleans to ONES and ZEROES by the double unary (--).
We search the array for the location of the first ZERO by using the MATCH function.
The end of the contiguous upper case letters is three char locations prior to the location returned by MATCH.
That's it.
What makes all of that possible is the array at the heart of the formula produced by the ROW/OFFSET combination. In conjunction with the LEN function, this combo produces a vector array that looks something like {1;2;3;4;5;6;7;8;9;10;11}. That array's last and largest number is equal to the length of the value in cell A1.
.
UPDATE
Here is a sample workbook showing these formulas work on the question's example data: http://www.excelhero.com/samples/torentino_excelhero.xlsx

Something like this might split off the band names from the albums.
Sub splt()
Dim rw As Long, p As Long, r As Long, sp As Long, v As Long
Dim bnd As String, ttl As String, tmp As Variant
With Worksheets("Sheet1")
For rw = 2 To .Cells(Rows.Count, 1).End(xlUp).Row
p = 1
bnd = vbNullString
ttl = Trim(.Cells(rw, 1).Value2) & Chr(32)
tmp = Split(ttl)
For v = LBound(tmp) To UBound(tmp)
If UCase(tmp(v)) = tmp(v) Then
bnd = Join(Array(bnd, tmp(v)), Chr(32))
Else
Exit For
End If
Next v
.Cells(rw, 2) = bnd
.Cells(rw, 3) = Trim(Right(ttl, Len(ttl) - Len(bnd)))
Next rw
End With
End Sub

Related

Locate the last used cell in a block of cells

I need a formula to locate the last used cell in a block. By last used cell I mean:
Locate the last column (right-most) containing non-null data
Locate the lowest cell in that column that contains non-null data
Return the address of that cell
For example, in the block B2:I16:
The function should return: I15 rather than D16. I already have a VBA UDF that I am trying to replace:
Public Function FindLast(r As Range) As String
Dim nLastRow As Long, nLastColumn As Long
Dim nFirstRow As Long, nFirstColumn As Long
Dim i As Long, j As Long
nLastRow = r.Rows.Count + r.Row - 1
nLastColumn = r.Columns.Count + r.Column - 1
nFirstRow = r.Row
nFirstColumn = r.Column
For i = nLastColumn To nFirstColumn Step -1
For j = nLastRow To nFirstRow Step -1
If Len(r(j, i)) > 0 Then
FindLast = r(j, i).Address(0, 0)
Exit Function
End If
Next j
Next i
End Function
As the worksheet must work in a macro-free environment.
This {array formula} works:
=ADDRESS(MAX(ROW(L1:P5)*(LEN(L1:P5)>0)*(COLUMN(L1:P5)=
MAX(COLUMN(L1:P5)*(LEN(L1:P5)>0)))),
MAX(COLUMN(L1:P5)*(LEN(L1:P5)>0)), 4)
Press Ctrl + Shift + Enter
Obviously the second term catches the correct column (which is the easy part). The first term includes the second term in it, in order to search that column for the last populated row.
In the figure below it was applied on the range L1:P5 and yielded the correct result O4.
The only shortcoming I found so far is that it will error out if the range contains error cells, but from reading the OP's UDF it doesn't seem to be an issue. If it does, some additional IFERROR will solve it:
=ADDRESS(MAX(ROW(L1:P5)*IFERROR(LEN(L1:P5)>0, 0)*(COLUMN(L1:P5)=
MAX(COLUMN(L1:P5)*IFERROR(LEN(L1:P5)>0,0)))),
MAX(COLUMN(L1:P5)*IFERROR(LEN(L1:P5)>0, 0)), 4)
Press Ctrl + Shift + Enter
EDIT: Added parameter 4 to the ADDRESS function to remove the $ from the result. The results in my tests match the OP's UDF after I modified it replacing r(j, i) with r.Parent.Cells(j, i).
Here is a non CSE version:
=ADDRESS(AGGREGATE(14,6,(ROW(INDEX(L1:P5,0,AGGREGATE(14,6,COLUMN(L1:P5)/(L1:P5<>""),1)-MIN(COLUMN(L1:P5))+1)))/(INDEX(L1:P5,0,AGGREGATE(14,6,COLUMN(L1:P5)/(L1:P5<>""),1)-MIN(COLUMN(L1:P5))+1)<>""),1),AGGREGATE(14,6,COLUMN(L1:P5)/(L1:P5<>""),1))
My first approach was similar to #ScottCraner's.
=ADDRESS(MOD(AGGREGATE(14,6,(ROW(L1:P5)+COLUMN(L1:P5)*10^7)*(L1:P5<>""),1),10^7),AGGREGATE(14,6,COLUMN(L1:P5)*(L1:P5<>""),1),4)
Here the first AGGREGATE is used to calculate maximum of:
COL_NUM*10^7+ROW_NUM
for nonempty cells (multiplication by 10^7 ensures column precedence). So this function technically returns both coordinates (e.g. for P4 it is 160000004 - 16th column and 4th row). MOD extracts row number.
But if one AGGREGATE can return both coordinates (as one number), the next step was to try find a formula to return the address using AGGREGATE only once. This is the best I could come up with:
=BASE(AGGREGATE(14,6,(DECIMAL(ROW(L1:P5),36)+36^6*(DECIMAL(ADDRESS(1,COLUMN(L1:P5),4),36)-1)*(L1:P5<>"")),1),36)
This formula:
decodes column letters from Base36 (shifted 6 digits left) to
decimal
decodes row number(!) from Base36 to decimal
calculates maximum for nonempty cells
encodes result as Base36
Drawbacks:
BASE was introduced in Excel2013
Formula return P000004 instead of P4 - but it is still valid cell address - can be use with INDIRECT
Performs a lot of calculations - it is only an attempt to solve the problem with one AGGREGATE only.

Check id every value in ";" separated string exists on a LOV list using just Excel formulas

In a cell I have a multi value separated by semicolon like this:
Red;Blue;Green
I need to compare if each of those values exist on a list:
Black
Orange
Green
Blue
Red
I think it should be an array formula, but I have no idea how to set it.
Is it even possible?
Regards
MichaƂ
You've not mentioned what output you are looking for. Below are the two possible solution.
1. If you are looking for the count of words in a cell from the list use following formula:
=SUMPRODUCT(ISNUMBER(FIND($E$2:$E$6,$A2))*1)
2. If you want words in the cell that are in the list to be displayed in separate columns, use the following array formula
=IFERROR(INDEX($J$2:$J$6,SMALL(IF(ISNUMBER(FIND($J$2:$J$6,$A2)),ROW($J$2:$J$6)-ROW($J$1)),COLUMNS($A1:A1))),"")
Drag/copy above formula across and down as required.
Being an array formula you'll have to commit this formula by pressing Ctrl+Shift+Enter.
You can write this UDF and use it as a formula. Wasn't sure what output is required. This UDF gives number of items that match in the list.
Parameters:
myValue - the cell that contains multi value separated by semicolon
listRange - Range that has the list to check against. Should be a single column list
Function checkList(myValue As Range, listRange As Range) As Integer
Dim t As Variant
t = Split(myValue.Value, ";")
Dim c As Integer
c = 0
For i = LBound(t) To UBound(t)
For j = 1 To listRange.Rows.Count
If (t(i) = listRange(j, 1)) Then
c = c + 1
End If
Next j
Next i
checkList = c
End Function
Since you want to do this only with excel formulas, the input string has to be split to multiple cells before comparing it with the list.
If your input string is in A1, use the below formula and drag it right to split them based on the delimiter ;.
=TRIM(MID(SUBSTITUTE($A1,";",REPT(" ",999)),1+((COLUMN(A1)-1)*999),999))
Assuming your list is in column G, use the below formula which counts the strings Red, Blue and Green in your list and returns Found or Not found.
in C2,
=IF(COUNTIF($G:$G,C1),"Found","Not found")
Hope this helps.

counting multiple instances of a number in a range

I have a range of numbers and I need to identify if the first number of each cell is repeated anywhere in the corresponding row.
For example, in row 2 below, column 2 and column 3 both start with a 3. I know that if I do =LEFT(TRIM(cell)) to get just the first number but how do I find the rows that have repeated numbers in the row so row 1 isn't marked but row 2 is?
100|600|203|700| |
202|302|301|400|600|
Use a helper column with this as an array formula:
=SUMPRODUCT(--(COLUMN($A1:$E1)<>MATCH(INT($A1:$E1/100),INT($A1:$E1/100),0)))>0
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.
Consider the following UDF():
Public Function AnyDups(rng As Range) As Boolean
Dim valu() As String
Dim i As Long, L As Long
L = rng.Count
ReDim valu(1 To L)
AnyDups = False
If L = 1 Then Exit Function
i = 1
For Each r In rng
valu(i) = Left(r.Value, 1)
i = i + 1
Next r
For i = 1 To L - 1
v = valu(i)
For j = i + 1 To L
If v = valu(j) Then AnyDups = True
Next j
Next i
End Function
For example:
The code just loops through the possible combinations of left-most characters in the cells.
It should work with either text or numeric data.
One way to do it would be to use this formula as a basis:
=IF(ISERROR(FIND(LEFT(TRIM(A1),1),B1)),FALSE,"Row "& ROW(A1))
Depending on how you want to check your row, you can adapt it. You could either have one formula to check one cell (Lock the A1 reference and drag right) - which would allow you to know where the match is but take more space on the sheet.
Or, if you don't have too many cells to check in each row, you could concatenate all cells in the same formula:
=IF(ISERROR(FIND(LEFT(TRIM(A1),1),B1&C1&D1&E1)),FALSE,"Row "& ROW(A1))
I'm sure Gary's Student will have a more elegant answer though!

Do math on cells also contaning text in EXCEL

I have a range of cells which I want to do some math on. But I also want those cells to contain some text.
For instance I want the sum of A1 and B1 where A1 contains the number 10 and "z001" and B1 contains the number 20 and "Z004".
Then I want the formula to ignore the text, and just come up with 30.
Is this possible?
For a quick solution, type "=Left(A1, 2) + Left(B1, 2)" into C1. Drag this equation down the rest of your range and you should get the results you want, provided the numbers you are adding are all 2 digits.
You can also use VBA if you need to run the same equation on multiple cells.
If you can get the same results by just removing the letters, try:
For i = 58 To 127
'Change out str with the variable name you have assigned to your cell value.
str = Replace(str, Chr(i), "")
Next i
58 and 127 represent the first and last positions in a range of characters on the Ascii table that are not numerals http://www.asciitable.com/
If you just want to include the first two numbers of each cell in your equation and ignore the "Z00#", you can try:
strLeft = Left(str, 2)
This will reduce your string down to the first two characters of each cell.
You can look here for other ways to remove characters you don't want.
http://www.globaliconnect.com/excel/index.php?option=com_content&view=article&id=269:excel-vba-string-functions-left-right-mid-len-replace-instr-instrrev&catid=79&Itemid=475
Here is in example of how you would implement something like this with simple addition.
Dim a as range
Dim b as range
Dim aLeft as integer
Dim bLeft as integer
Dim cleft as integer
a = Worksheets("WorksheetName").Cells(A1).Value
b = Worksheets("WorksheetName").Cells(B1).Value
aLeft = Left(a, 2)
bLeft = Left(b, 2)
cLeft = aLeft + bLeft
Worksheets("WorksheetName").Cells(C1).Value = cLeft
This would add the first two digits of cells A1 and B1 then display the result in C1.
As I see it, you have 2 options:
Search for the number within each cell and sum it up (see below).
Split the columns to have 1 column of numbers and one of codes (e.g.
"z001"). See on the "Data" tab on the ribbon and click "Text to
Columns" on the Data Tools group.
The first option would be the quickest and more straightforward. You need to make a third column where the sum will be and then use, for example, the function LEFT. This function allows you to retrieve characters from a cell. See example below:
To get "30" I have used the following formula on C2:
=LEFT(A2,2)+LEFT(B2,2)
Note this is not ideal since this formula is looking for 2 characters every time. If you have a scenario with the following code "5z005" it won't work because it will try to sum "5z" as if it was a number. In that case you're better off finding a pattern (code = "number" "z" "number") and splitting the columns as I said on option 2.

Calculate SUM without Adding Values to Rows/Columns?

When calculating series in Excel, most tutorials begin by setting sequence values to certain range of cells, say
A1=1, A2=2, A3=3,..., A10=10
and to get the value of 1+2+...+10, execute
A11=SUM(A1:A10)
But I don't want the "generate the sequence in worksheet cells first" part because initially I don't know the 'n' (10 in the above) and I want to define a custom function that takes n as a function argument.
So, is there a way to do something like this?
B1 = SUM([1:10]) // adding array of 'constants', not cell reference
EDIT: If I could 'summon' some (array of) big number(s) without any cell/ROW/COL operation as in calling rand(), that would be great.
Try using Array Formula as below
=SUM(ROW(A1:A10)) and then press CTRL+SHIFT+ENTER
Row(A1:A10) will become {1,2,3,4,5,6,7,8,9,10}.
Usage:
If you want to sum cells A20 to A50
sumjeff("A", 20,50)
Code
Function sumJeff(letter As String, nFrom As Integer, nTo As Integer) As Double
Dim strAddress As String
strAddress = letter & nFrom & ":" & letter & nTo
sumJeff = Application.WorksheetFunction.Sum(Range(strAddress))
End Function

Resources