Revisiting Excel parsing - string

I have gone through the variations on these and each has a different solution depending on how the names are in a cell. Let me make it clear. I have an excel sheet containing the names of my colleagues from my college days. The names are in no particular format. The "Name" column has the names like:
1) Dipak C. Chopra
2) Amar D Pathak
3) Lara Naik
4) Reshma Laxman Bhavsar
So as can be seen, some have simply a middle initial, some have it with a period and some have it missing while some have a full middle name. What I wish to do is to rewrite these names in another column by last name so that it turns out like:
1) Chopra Dipak C.
2) Pathak Amar D
3) Naik Lara
4) Bhavsar Reshma Laxman
I can do it but I have to use formulae with variations depending the name in the cell: e.g.
=TRIM(RIGHT(B2,LEN(B2)-FIND(" ",B2)) & " " & LEFT(B2,FIND(" ",B2))) for the 3rd entry
=TRIM(RIGHT(B4,LEN(B4)-FIND(" ",B4)-1) & " " & LEFT(B4,FIND(" ",B4)+1)) for the 2nd entry
=TRIM(RIGHT(B13,LEN(B13)-FIND(" ",B13,FIND(" ",B13)+1))&" "&LEFT(B13,FIND(" ",B13,FIND(" ",B13)+1))) for the 4th entry.
My question is how can I revise this formula to give me the desired result in all the cases mentioned above?

=IF(ISERROR(FIND(" ",B2)),B2,RIGHT(B2,LEN(B2)-FIND("~",SUBSTITUTE(B2," ","~",LEN(B2)-LEN(SUBSTITUTE(B2," ","")))))&" "&LEFT(B2,FIND("~",SUBSTITUTE(B2," ","~",LEN(B2)-LEN(SUBSTITUTE(B2," ",""))))-1))
It involves doing a reverse string search to find the last space and then uses its position to cut the last name off and then add on the rest of the string to the end, if there is no spaces in the string it will just return the value is B2
Beautified
=IF(
ISERROR(
FIND(
" ",
B2
)
),
B2,
RIGHT(
B2,
LEN(
B2
) -
FIND(
"~",
SUBSTITUTE(
B2,
" ",
"~",
LEN(
B2
) -
LEN(
SUBSTITUTE(
B2,
" ",
""
)
)
)
)
) & " " &
LEFT(
B2,
FIND(
"~",
SUBSTITUTE(
B2,
" ",
"~",
LEN(
B2
) -
LEN(
SUBSTITUTE(
B2,
" ",
""
)
)
)
) - 1
)
)

Related

Excel Formula to Insert Spaces Before Capital Letters and Numbers

In column A, starting with A1, I have a set of database column names which are Pascale case and without spaces. I'd like to use an Excel formula in column B to insert spaces before each Capital letter or number. Ideally any consecutive capital letters or numbers would remain together. I've done this in the past with C#, but on this project, I can't even use VBA macros. Example output:
Can this, or something close, be achieved using only formulas?
This is pretty hard, but with ms365 doable with the give sample data:
Formula in B1:
=MAP(A1:A10,LAMBDA(v,TRIM(REDUCE(v,SEQUENCE(LEN(v),,LEN(v),-1),LAMBDA(a,b,LET(x,MAKEARRAY(26,3,LAMBDA(r,c,CHOOSE(c,CHAR(r+64),CHAR(r+96),r-0))),y,MID(a,b,1),z,MID(a,b+1,1),r,BYCOL(x,LAMBDA(c,SUM(EXACT(c,y)+EXACT(c,z)))),IF(MAX(r)=1,LEFT(a,b-1)&IF((CONCAT(r)="110")*(EXACT(UPPER(y),y))," "&y,y&" ")&RIGHT(a,LEN(a)-b),a)))))))
Maybe others have shorter solutions...
Just for fun, this uses a single Reduce but I have defined some auxiliary functions. I put them in a module called 'is' in the Advanced Formula Environment so their full names are Is.Upper, Is.Lower and Is.Digit:
Upper=lambda(c,if(c="",false,and(code(c)>64,code(c)<91)));
Digit=lambda(c,if(c="",false,and(code(c)>47,code(c)<58)));
Lower=lambda(c,if(c="",false,and(code(c)>96,code(c<123))))
=REDUCE(LEFT(A1,1),SEQUENCE(1,LEN(A1)-1,2),LAMBDA(a,c,a&IF(OR(AND(is.Digit(MID(A1,c,1)),NOT(is.Digit(MID(A1,c-1,1)))),AND(is.Upper(MID(A1,c,1)),OR(NOT(is.Upper(MID(A1,c-1,1))),is.Lower(MID(A1,c+1,1)))))," ","")&MID(A1,c,1)))
This is how the main formula looks in the Advanced Formula Environment:
=REDUCE(
LEFT(A2, 1),
SEQUENCE(1, LEN(A2) - 1, 2),
LAMBDA(a, c,
a &
IF(
OR(
AND(
is.Digit(MID(A2, c, 1)),
NOT(is.Digit(MID(A2, c - 1, 1)))
),
AND(
is.Upper(MID(A2, c, 1)),
OR(
NOT(is.Upper(MID(A2, c - 1, 1))),
is.Lower(MID(A2, c + 1, 1))
)
)
),
" ",
""
) & MID(A2, c, 1)
)
)
Note - assumes string length>1.

Use Table Header as Content In a Cell

I am using the column header titles as the comma separated content in another cell. I am using Excel 2016. I have a table named StudentCourse and for a better illustration please see the below example layout:
[Name] [Math] [Geo] [Bio] [Fees] [Fixes]
Ram Very Bad Good Good Unpaid Urgent: Math, Fees
Dam Neutral Good Bad Paid Urgent: Math, Bio
Rik Good Good Good Paid OK: Not Urgent
Nik Good Good Good Partial Urgent: Fees
The values for the subject columns are from a drop down menu which has the options Good, Neutral, Bad and Very Bad and if the values Neutral, Bad or Very Bad are selected then the Fixes column will be updated with the prefix Urgent: and the column header name (Math, Geo or Fees) depending on what needs to be fixed. If, no fixes are needed then the Fixes column's value will be Ok: Not Urgent.
The Fees column also follows the same concept. Meaning that if the Partial (means partial payment) or unpaid dropdown options are selected for the Fees Column value, then the Fees will be added to the Fixes column. So in short the Fixes column is for easily sorting through what needs to be given special by having the values be automatically selected based on what was chosen for the other columns.
I should also mention that I am new to Excel.
Assuming that the table is located at [A1:E9] and there are no [BLANK] cells as confirmed by OP. Enter this formula in [F2] and copy it to [F3:F9].
Excel 2016
= IF( SUMPRODUCT( ($B2:$E2<>{"Good","Good","Good","Paid"})*1 )=0, "Ok: Not Urgent",
"Urgent: " & SUBSTITUTE(
IF( $B2<>"Good", ", " & $B$1, "" )
& IF( $C2<>"Good", ", " & $C$1, "" )
& IF( $D2<>"Good", ", " & $D$1, "" )
& IF( $E2<>"Paid", ", " & $E$1, "" ), ", ", "", 1 ) )
Excel 2019 (Formula Array)
= IF( SUMPRODUCT( ($B2:$E2<>{"Good","Good","Good","Paid"})*1 )=0, "Ok: Not Urgent",
"Urgent: " &
TEXTJOIN( ", ", TRUE, IF( ($B2:$E2<>{"Good","Good","Good","Paid"}), $B$1:$E$1, TEXT(,) ) ) )
The FormulaArray is entered holding down ctrl+shift+enter simultaneously, the formula would be wrapped within { and } if entered correctly.
If you list the acceptable data in column H:I (as example below). You could use:
=IF(TEXTJOIN(", ",1,IF(INDEX($I$1:$I$4,MATCH($B$1:$E$1,$H$1:$H$4,0))=B2:E2,"",$B$1:$E$1))="","OK: No urgent","Urgent: "&TEXTJOIN(", ",1,IF(INDEX($I$1:$I$4,MATCH($B$1:$E$1,$H$1:$H$4,0))=B2:E2,"",$B$1:$E$1)))

Comparison of timestamps in Excel

I've got following data as result from a query. As example 2 rows but in total around 30000 rows.
Some timestamps are empty because no row in that table.
agr_no
timestamp1
timestamp2
timestamp3
00000080064
2005-08-17-09.29.01.427337
2005-08-17-09.29.01.351888
00000080065
2002-04-29-15.04.58.714606
2013-11-18-13.11.46.494690
I would like to have in the next column an indication about which timestamp is the greatest.
For example:
agr_no
timestamp1
timestamp2
timestamp3
Result
00000080064
2005-08-17-09.29.01.427337
2005-08-17-09.29.01.351888
TS1
00000080065
2002-04-29-15.04.58.714606
2013-11-18-13.11.46.494690
TS3
Tried many things but always in trouble with the format of the timestamp so no comparison is possible.
Thanks a lot.
This is quite ugly but,
You can convert your values to dates and then just take the max date, or in this instance, the index of the matched date.
="TS" & MATCH(MAX(IFERROR(DATEVALUE(LEFT(A2:C2,10))+TIME(MID(A2:C2,12,2),MID(A2:C2,15,2),MID(A2:C2,18,2)+(RIGHT(A2:C2,6)/1000)),0)),IFERROR(DATEVALUE(LEFT(A2:C2,10))+TIME(MID(A2:C2,12,2),MID(A2:C2,15,2),MID(A2:C2,18,2)+(RIGHT(A2:C2,6)/1000)),0),0)
Note this assumes the formats of the string dates are either blank OR in strictly in the below format which is consistent with the limited inputs you gave us
yyyy-mm-dd.hh.mm.ss.######
FYI - Your milliseconds value is strange. On your first row the milliseconds actually equates to minutes
Assuming your data is located at [A1:D27] and based on this formula to convert the string TimeStamp to a double:
= IFERROR( VALUE( SUBSTITUTE( SUBSTITUTE( SUBSTITUTE( B2,
"-", " ", 3 ), ".", ":" ), ":", ".", 3 ) ), 0 )
Enter this FormulaArray in E2, then copy E2 downwards till last row:
= "TS" & MATCH( MAX(
IFERROR( VALUE( SUBSTITUTE( SUBSTITUTE( SUBSTITUTE( B2:D2,
"-", " ", 3 ), ".", ":" ), ":", ".", 3 ) ), 0 ) ),
IFERROR( VALUE( SUBSTITUTE( SUBSTITUTE( SUBSTITUTE( B2:D2,
"-", " ", 3 ), ".", ":" ), ":", ".", 3 ) ), 0 ), 0 )
FormulaArray are entered holding down ctrl+shift+enter simultaneously, the formula would be wrapped within { and } if entered correctly.

where exactly i shlould place INDIRECT() in excel?

I have a named range by name 'AlgeriaBchar'. (Algeria-> countryname and Bchar-> statename)
I use constraint on city dropdown as content in country dropdown + state dropdown (i.e. E7 + F7).
But as we can see in img staename is 'Béchar' which i need to remove char 'é' as it doesnt fit in a-z, A-Z, 0-9.
I also need to remove any blank spaces, hiphns, square brackets, apostrophy marks in country and state dropdown contents
I m not getting in which sequence I should put these fucntions to get it to 'AlgeriaBchar'
For better understanding I provided indentation to data validation fucntion in excel.
I'll be putting this fucntion in city dropdown's validaity constraint.
I may need to evaluate each character in a string which will need for loop. MID( E7, 1 ,1 ) gives me only 1st chracter. How can I loop it till the length of the string.
can anyone suggest me.
=IF(
NOT(
AND( CODE( MID( E7, 1 ,1 ) ) >=65 , CODE( MID( E7, 1 ,1 ) ) <=90 )
)
AND(
NOT(
AND( CODE( MID( E7, 1 ,1 ) ) >=97 , CODE( MID( E7, 1 ,1 ) ) <=122 )
)
)
AND(
NOT(
AND( CODE( MID( E7, 1 ,1 ) ) >=48 , CODE( MID( E7, 1 ,1 ) ) <=57 )
)
)
, SUBSTITUTE( E7, MID( E7, 1 ,1 ), "" ) ,""
)
INDIRECT(
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(UPPER($E$7)," ","")
,"-","")
,"'","")
,"[","")
,"]","")
)
)
You may want to use a macro for that. Consider this one (based on this article from extendoffice.com)
1) Hold down the Alt + F11 keys in Excel, and it opens the Microsoft Visual Basic for Applications window.
2) Click Insert > Module, and paste the following macro in the Module Window.
Function StripAccent(thestring As String)
Dim A As String * 1
Dim B As String * 1
Dim i As Integer
Const AccChars = "ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿ-[]' "
For i = 1 To Len(AccChars)
A = Mid(AccChars, i, 1)
thestring = Replace(thestring, A, "")
Next
StripAccent = thestring
End Function
Function TrimmedConcat(A As String, B As String)
TrimmedConcat = StripAccent(A) & StripAccent(B)
End Function
Then in your document, click in a cell, and use TrimmedConcat as if it was a normal function, selecting the country name as the first argument and the city name as the second.
In your example =TrimmedConcat(E7,F7)
I hope that helps!

Evaluating INDIRECT in an array in Excel

I'm trying to write a linear regression function that dynamically references columns, can handle #N/A values, and will function as additional rows are added over time. Here is a sample dataset:
Date Value 1 Value 2
1/2/1991 #N/A #N/A
2/4/2002 276.36 346.31
1/7/2003 252 350
1/21/2004 232 345.5
1/6/2005 257 368
2/1/2006 278.24 390.11
2/23/2007 #N/A 380.46
2/11/2008 326.34 383.04
2/12/2009 #N/A 399.9
2/17/2009 334.39 #N/A
1/29/2010 344.24 400.83
1/27/2011 342.88 404.52
2/7/2012 379 417.91
1/23/2013 #N/A 433.35
Here is the function that I've developed so far, based on this forum post. It calculates the linear regression for Value 1.
=TRANSPOSE(
LINEST(
N(
OFFSET(
INDIRECT("B2" & ":B" & COUNTA(B:B)),
SMALL(
IF(
ISNUMBER(
INDIRECT("A2:A" & COUNTA($A:$A)) *
INDIRECT("B2" & ":B" & COUNTA(B:B))),
ROW(INDIRECT("B2:B" & COUNTA(B:B))) - ROW(B2)),
ROW(INDIRECT("1:" & MIN(
COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
COUNT(INDIRECT("B2:B" & COUNTA(B:B))))))), 0, 1)),
N(
OFFSET(
INDIRECT("A2:A" & COUNTA($A:$A)),
SMALL(
IF(
ISNUMBER(
INDIRECT("A2:A" & COUNTA($A:$A)) *
INDIRECT("B2:B" & COUNTA(B:B))),
ROW(INDIRECT("B2:B" & COUNTA(B:B))) - ROW(B2)),
ROW(INDIRECT("1:" & MIN(
COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
COUNT(INDIRECT("B2:B" & COUNTA(B:B))))))), 0, 1)),
TRUE, FALSE))
With the way it is currently written, dragging my array to the right to solve for Value 2 requires some manual updating of the formula. Everything in quotes in the INDIRECT formulas must be manually changed from B to C. I have 40 columns of data, though, so I tried to make the formula entirely dynamic using ADDRESS, ROW, and COLUMN:
=TRANSPOSE(
LINEST(
N(
OFFSET(
INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2))),
SMALL(
IF(
ISNUMBER(
INDIRECT("A2:A" & COUNTA($A:$A)) *
INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))),
ROW(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))) - ROW(B2)),
ROW(INDIRECT("1:" & MIN(
COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
COUNT(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))))))), 0, 1)),
N(
OFFSET(
INDIRECT("A2:A" & COUNTA($A:$A)),
SMALL(
IF(
ISNUMBER(
INDIRECT("A2:A" & COUNTA($A:$A)) *
INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))),
ROW(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))) - ROW(B2)),
ROW(INDIRECT("1:" & MIN(
COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
COUNT(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))))))), 0, 1)),
TRUE, FALSE))
This gives me #REF!. When I do a step-by-step evaluation of the formula, it looks like the issue comes when Excel evaluates COLUMN. It introduces braces to the formula, which propagate through the rest of the INDIRECT evaluation. Here is a quick comparison:
Original formula:
INDIRECT("B2:B15")
Dynamic formula:
INDIRECT({"$B$2:$B$15"})
This evaluates as #VALUE, and at that point the rest of the formula is broken. Is there a way to force Excel to not use braces in this evaluation, or is there a better way of making this calculation?
Are you only trying to get the SLOPE from the linear regression? If so, you can just use the SLOPE function after converting the #N/A to blanks (using IFERROR in a formula). SLOPE will then just toss out the blanks. If you want the intercept as well, use the same formulas below and substitute INTERCEPT for SLOPE.
Picture of ranges
Formulas are array formulas (use CTRL+SHIFT+ENTER) and copied over. Given this arrangement, the simple formula (non-dyanmic) would be:
=SLOPE(IFERROR(B2:B15,""),$A$2:$A$15)
If you want these to be dynamic, you can use INDEX and COUNTA to get the dynamic range.
=SLOPE(IFERROR(B2:INDEX(B:B,COUNTA(B:B)),""),$A$2:INDEX($A:$A,COUNTA($A:$A)))
Use a Table instead
Even better, you could define this data inside a Table and then use the headers to pull in the whole column. That formula would look nice and copy easily.
Still using an array formula here, but the only variable is the column heading which is used to look into the Table1. This one would be more resistant to blanks in the data which will break the COUNTA used above.
=SLOPE(IFERROR(INDEX(Table1,,MATCH(M1,Table1[#Headers])),""),Table1[Date])
It appears you can use the following, shorter, non-volatile array formula**:
=LINEST(INDEX(B:B,N(IF(1,MODE.MULT(IF(ISNUMBER(B2:B15),{1,1}*ROW(B2:B15)))))),INDEX($A:$A,N(IF(1,MODE.MULT(IF(ISNUMBER(B2:B15),{1,1}*ROW(B2:B15)))))))
B2:B15 can be dynamically defined if desired as per Jeeped's solution.
Regards
You are going to want to get rid of the use of the INDIRECT function as much as possible; certainly as it pertains to substituting column references for string equivalents. It seems that many can be replaced with a form of INDEX/MATCH function pairs.
=TRANSPOSE(
LINEST(
N(
OFFSET(B2:INDEX(B:B, MATCH(1E+99,$A:$A )),
SMALL(
IF(
ISNUMBER(
$A2:INDEX($A:$A, MATCH(1E+99,$A:$A )) *
B2:INDEX(B:B, MATCH(1E+99,$A:$A ))),
ROW(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))) - ROW(B2)),
ROW(INDIRECT("1:" & MIN(
COUNT($A2:INDEX($A:$A, MATCH(1E+99,$A:$A ))),
COUNT(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))))))), 0, 1)),
N(
OFFSET(
$A2:INDEX($A:$A, MATCH(1E+99,$A:$A )),
SMALL(
IF(
ISNUMBER(
$A2:INDEX($A:$A, MATCH(1E+99,$A:$A )) *
B2:INDEX(B:B, MATCH(1E+99,$A:$A ))),
ROW(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))) - ROW(B2)),
ROW(INDIRECT("1:" & MIN(
COUNT($A2:INDEX($A:$A, MATCH(1E+99,$A:$A ))),
COUNT(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))))))), 0, 1)),
TRUE, FALSE))
Fill right as necessary and have column A locked while column B cell range references will shift to column C, D, etc.
        
Further function replacement could likely exchange at least some of the OFFSET functions use for an appropriate INDEX function but the formula seems to work well as it is now.

Resources