I have a CSV in which column A is populated with strings, such as:
ABCDE/FGHI/JKL/MNOPQR
I need to populate column C with everything after the last occurrence of the "/". In this example, it would have to be "MNOPQR".
Is there a function that could be used for this? "RIGHT" doesn't seem to do the trick. I don't know what the length of the substring will be in each row, so I definitely have to look for the "/".
If your text is in A4, put this in another cell:
=MID(A4,LEN(LEFT(A4,FIND(CHAR(1),SUBSTITUTE(A4,"/",CHAR(1),LEN(A4)-LEN(SUBSTITUTE(A4,"/",""))))))+1,LEN(A4)-LEN(LEFT(A4,FIND(CHAR(1),SUBSTITUTE(A4,"/",CHAR(1),LEN(A4)-LEN(SUBSTITUTE(A4,"/",""))))))+1)
I think that should work. Thanks to #Jerry for the main part, where it finds the last / in a string.
edit:
Per #ScottCraner, this is shorter: =MID(A1,SEARCH("}}}",SUBSTITUTE(A1,"/","}}}",LEN(A1)-LEN(SUBSTITUTE(A1,"/",""))))+1,LEN(A1))
Here's a bit shorter formula to return the last delimited substring in a string.
=TRIM(RIGHT(SUBSTITUTE(A1,"/",REPT(" ",99)),99))
Replace the delimiter with 99 spaces, then return the rightmost 99 characters. The leading characters must be spaces also, so TRIM gets rid of them.
A simple formula approach using FilterXML might be:
=FILTERXML("<items><i>" & SUBSTITUTE(A1,"/","</i><i>") & "</i></items>","//i[position()=last()]")
Profitting from the dynamic features of vers. 2019+ you can change the cell address to a range input, e.g. A1:A10 allowing output in a so called spill range.
VBA approach
As the VBA tag has been recently added to OP,
an obvious VBA approach would be to split the string input and get the last array element via Ubound():
Dim tmp As Variant
tmp = Split("ABCDE/FGHI/JKL/MNOPQR", "/")
Debug.print tmp(Ubound(tmp)) ' ~~> MNOPQR
Related
I have a list of strings in cells - 1000s of them - and I need to work out the characters per word but separated by word - preferably in 1 swift formula...
For Example:
1. "Black Cup With Handle" > Formula I need > 5,3,4,6
"Giant Bear Statue" > Formula I need > 5,4,6
I need this for a recurring task which has been macro'd in a very inefficient way to count words into columns (of which we need to use up to 20 for the just encase) but this needs to be tackled.
Usually, we count the spaces and layer nested serach() formulas to piggyback onto one and other to break down the structure then character counts the individual words...
I could alternatively the macro to substitute the spaces for commas and used text to columns but that still leaves me with a prolonged counting process for what im looking for
we obviously use =LEN(A1)-LEN(SUBSTITUTE(A1," ","")) to count the spaces in the word
we currently then use =SEACRH() function combined with =MID() functions (and some bizarre numbers) to reveal each word into its own individual cell
then =LEN once again bu on all individual words - very long-winded
Im hoping to find a shorter way to do this but feeling there may not be a dynamic enough way to do it with formula alone, hoping someone can prove me wrong!
You'll have different options depending on your Excel version.
OPTION 1: TEXTJOIN
I think you are looking for a TEXTJOIN function. Just bare in mind that you can only use this the more later versions of Excel (see link to documentation) and it could work like this:
Formula in B1:
=TEXTJOIN(",",TRUE,LEN(FILTERXML("<t><s>"&SUBSTITUTE(A1," ","</s><s>")&"</s></t>","//s")))
NOTE: It's an array formula and you need to enter it using CtrlShiftEnter
To make it so that you won't need to use the above key-combo, we can include an INDEX:
=TEXTJOIN(",",TRUE,INDEX(LEN(FILTERXML("<t><s>"&SUBSTITUTE(A1," ","</s><s>")&"</s></t>","//s")),))
Additional Information:
FILTERXML
This function takes (as per documentation) two required arguments:
A string in valid XML
A string in valid XPath
Because we want to return an array of elements (words) from the cell, we need to SUBSTITUTE the spaces for end-tags (</..>) and concatenate that with a start-tag (<..>) at the start of the string and another end-tag at the end.
I'll have to rely on an XML explaination on the tags as to why <?><?> works and it's meaning, because as far as my testing goes I could swap the letters around or replace by another letter with the same results as long as the final Xpath would resemble the same character. It would be great if someone would be able to complement this answer with a better explanation on this matter.
For more FILTERXML "tricks", have a look here
TEXTJOIN
If you are a Office 365 subscriber or own Excel 2019 you can make use of this function. There are (as per documentation) at least 3 required arguments:
A delimiter which must be a text string, either empty, or one or more characters enclosed by double quotes, or a reference to a valid text string. If a number is supplied, it will be treated as text.
The second argument can hold either TRUE or FALSE and determines whether or not you want to exclude/include empty values
The third argument is the text item to be joined. A text string, or array of strings, such as a range of cells.
Now this is where we can join the two functions together, FILTERXML returning an array which we can use in TEXTJOIN.
INDEX + LEN
I'll have to explain the use of these functions together. I don't think LEN and INDEX will need much of an introduction on their own, but together they work quite nicely. Natively there will be a force called implicit intersection that will prevent LEN from returning an array of values when you pass an array of values to the function, in this case through our FILTERXML.
Normally you would disable this mechanism using a key combination of: CtrlShiftEnter, better known as CSE.
Now what INDEX does is disabling this implicit intersection making LEN able to return an array, removing the need to CSE the formula. INDEX is one of the functions that has this "power". A more in depth explanation on implicit intersection can be found here
OPTION 2: UDF
Without access to TEXTJOIN I think you'll need to have a look at using an UDF, possibly looking like below:
Function TEXTJOIN(rng As Range) As String
TEXTJOIN = Join(Application.Evaluate("LEN({""" & Join(Split(rng, " "), """,""") & """})"), ",")
End Function
You can call this in B1 like so: =TEXTJOIN(A1)
Additional Information:
The UDF consists out of three main mechanisms that work together:
JOIN
This funciton takes two parameters, where the first one is required:
First parameter is a one-dimensional array containing substrings
The second (optional) parameter is a string character used to separate the substrings in the returned string. If omitted, the space character (" ") is used. If delimiter is a zero-length string (""), all items in the list are concatenated with no delimiters.
The function returns a string value
SPLIT
This function takes a string and delimits it by a specified character/substring. It takes the following arguments:
1st: A required string expression containing substrings and delimiters. If expression is a zero-length string(""), Split returns an empty array, that is, an array with no elements and no data.
2nd: The optional delimiter which is a string character used to identify substring limits. If omitted, the space character (" ") is assumed to be the delimiter. If delimiter is a zero-length string, a single-element array containing the entire expression string is returned.
3rd: An optional limit, a number of substrings to be returned; -1 indicates that all substrings are returned.
4th: Compare, also optional, is a numeric value indicating the kind of comparison to use when evaluating substrings. See Settings section for values.
In this case we would only need the first two arguments.
Application.Evaluate
This is IMO one of the most handy mechanisms you can use to pull of a returned array of values without having to loop through items/cells. It may get slow when you feed the function a large array formula, but in this case it will be fine. The funtion converts a Microsoft Excel name into an object or value, and when we pass it an formula, it thus will return the results. In this particular case it will return an array.
I'm not totally clear on what end-result you're looking for, or whether you're okay with a VBA solution, but this is my interpretation:
Function lengths(txt As String) As String
Dim wrd
For Each wrd In Split(txt)
If lengths <> "" Then lengths = lengths & ","
lengths = lengths & Len(wrd)
Next wrd
End Function
Paste the code into a VBA module and then, for example, if A1 contained Black Cup With Handle then in another cell you could use =length(A1) which would return 5,3,4,6.
If you want to use a VBA code you could try this:
Option Explicit
Sub test()
Dim arr As Variant
Dim str As String
Dim i As Long, j As Long, LastRow As Long
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow
str = .Range("A" & i).Value
arr = Split(str, " ")
For j = LBound(arr) To UBound(arr)
.Cells(i, j + 3).Value = Len(arr(j))
Next j
Next i
End With
End Sub
Results:
I have a column of cells containing a variable amount of text up to 140 characters in length. What I would like to do is write a function that will parse these strings for only words beginning with "#" and organize them in a single adjacent cell separated by spaces.
These substrings vary in length and in their position within the string. And there might be more than one substring beginning with "#" in the cell to pull.
I have tried it in many different ways which have been unsuccessful. Thanks in advance for your advice!
Here is a way that seems to work, but is probably not the "correct" way:
The objective was to parse column C, containing tweets, for all the "mentions" (strings beginning with #) and put them in an adjacent cell in column D.
I took all the content from column C and pasted it into a new sheet. Then I did text-to-column so that the tweet was put into cells word by word. On these cells I used the function (dragged out) =IF(ISNUMBER(FIND("#",B3)),CONCATENATE(B3," "),"") in order to separate the twitter handles only into columns below. I think there needs to be a space added in case there are multiple handles to join.
Then I used another nested CONCATENATE function =CONCATENATE(IF(B34="","",B34),IF(B35="","",B35)...,IF(B65="","",B65) to put the handles, now followed by spaces, together in a single cell. It had to be written this way as a workaround for the #VALUE error for the CONCATENATE function in blank cells.
Then I selected the whole row, copied and transposed it into a column. Then selected the column, pasted values only into my original sheet in column D. The handles all line up with the corresponding tweet.
I would love to learn how to do this in the proper way.
Dim regEx As Object
Dim strPattern As String: strPattern = "^#"
Set regEx = CreateObject("VBScript.RegExp")
regEx.Pattern = strPattern
If regEx.Test(valueOfCellToCheck) Then
' do your logic here
Else
' skip cell
End If
I'm messing with a spreadsheet containing postal addresses that have been inserted in the cells' comments
Each comment contain an address composed of a variable number of lines (damn UK addresses, they can have up to 7 lines!) in the following format:
Line1,
Line2,
Line3,
[...],
State
With my poor skills, I've managed to extract the comment with a VBA script, obtaining the following string on a single cell:
Line1,Line2,Line3,[...],State
At this point each string between commas must be extracted to its own cell.
I've managed to extract the 1st 3 lines with the following formulas:
For Line1:
=LEFT(A8;(SEARCH(",";A8))-1)
For Line2:
=MID(A8; SEARCH(",";A8)+1; SEARCH(","; A8; SEARCH(","; A8)+1)-SEARCH(",";A8)-1)
For Line3:
=MID(A8; SEARCH(",";A8;SEARCH(",";A8;SEARCH(",";A8;SEARCH(",";A8)))+1)+1;SEARCH(","; A8; SEARCH(","; A8;SEARCH(",";A8)+1)+1)-SEARCH(",";A8;SEARCH(",";A8)+1)-1)
From this point I start to get overflow errors from my brain... I probably need some days of sleep.
Can anybody help me to get to "line6", and finally suggest me how to pull out the "State line" which ends without comma?
I thought I could pull out the "State" line with =RIGHT(",";SEARCH(",";A8)-1) but I'm obviously doing something wrong because that pulls out a comma instead of a string.
I guess I could do everything with a VBA script, but I'm not that skilled yet :(
With comma separated data in A1, in B1 enter:
=TRIM(MID(SUBSTITUTE($A1,",",REPT(" ",999)),COLUMNS($A:A)*999-998,999))
and copy across. For example:
Note:
Why not use TextToColumns ?
The row of formulas re-calculates automatically if A1 changes.
The row of formulas will work even if A1, itself, contains a formula.
If you are wanting to do this programmatically instead of using a built-in, check out the split function for chopping up your comma separated string. It will split up your input string into an array. Then you can do whatever you like with the array.
Dim Names() As String
Names() = Split(inputValue, ",")
For i = 0 To UBound(Names)
' do what you want with each piece
Next
Gary's Student's answer is great for using the built-in functions.
If you want a VBA solution:
Sub spitString()
Dim sourceRange As Range
Dim stringArr() As String
Dim i As Integer
Set sourceRange = ActiveSheet.Range("A1")
stringArr = Split(sourceRange.Value, ",")
For i = LBound(stringArr) To UBound(stringArr)
sourceRange.Offset(0, i + 1).Value = stringArr(i)
Next i
End Sub
You could avoid adding comments: Are you aware that users can add line breaks inside a cell by pressing ALT+RETURN?
If having high rows d is a problem and you don't like that formatting, an alternative approach might be to write a simple bit of code that changes the height of the current row when a user clicks in a certain range. It would , make other rows less high. Perhaps.
Just a thought. It has benefits keeping it simple.
Harvey.
E.g
A1:I
A2:am
A3:a
A4:boy
I want to merge them all to a single cell "Iamaboy"
This example shows 4 cells merge into 1 cell however I have many cells (more than 100), I can't type them one by one using A1 & A2 & A3 & A4 what can I do?
If you prefer to do this without VBA, you can try the following:
Have your data in cells A1:A999 (or such)
Set cell B1 to "=A1"
Set cell B2 to "=B1&A2"
Copy cell B2 all the way down to B999 (e.g. by copying B2, selecting cells B3:B99 and pasting)
Cell B999 will now contain the concatenated text string you are looking for.
I present to you my ConcatenateRange VBA function (thanks Jean for the naming advice!) . It will take a range of cells (any dimension, any direction, etc.) and merge them together into a single string. As an optional third parameter, you can add a seperator (like a space, or commas sererated).
In this case, you'd write this to use it:
=ConcatenateRange(A1:A4)
Function ConcatenateRange(ByVal cell_range As range, _
Optional ByVal separator As String) As String
Dim newString As String
Dim cell As Variant
For Each cell in cell_range
If Len(cell) <> 0 Then
newString = newString & (separator & cell)
End if
Next
If Len(newString) <> 0 Then
newString = Right$(newString, (Len(newString) - Len(separator)))
End If
ConcatenateRange = newString
End Function
Inside CONCATENATE you can use TRANSPOSE if you expand it (F9) then remove the surrounding {}brackets like this recommends
=CONCATENATE(TRANSPOSE(B2:B19))
Becomes
=CONCATENATE("Oh ","combining ", "a " ...)
You may need to add your own separator on the end, say create a column C and transpose that column.
=B1&" "
=B2&" "
=B3&" "
In simple cases you can use next method which doesn`t require you to create a function or to copy code to several cells:
In any cell write next code
=Transpose(A1:A9)
Where A1:A9 are cells you would like to merge.
Without leaving the cell press F9
After that, the cell will contain the string:
={A1,A2,A3,A4,A5,A6,A7,A8,A9}
Source: http://www.get-digital-help.com/2011/02/09/concatenate-a-cell-range-without-vba-in-excel/
Update: One part can be ambiguous. Without leaving the cell means having your cell in editor mode. Alternatevly you can press F9 while are in cell editor panel (normaly it can be found above the spreadsheet)
Use VBA's already existing Join function. VBA functions aren't exposed in Excel, so I wrap Join in a user-defined function that exposes its functionality. The simplest form is:
Function JoinXL(arr As Variant, Optional delimiter As String = " ")
'arr must be a one-dimensional array.
JoinXL = Join(arr, delimiter)
End Function
Example usage:
=JoinXL(TRANSPOSE(A1:A4)," ")
entered as an array formula (using Ctrl-Shift-Enter).
Now, JoinXL accepts only one-dimensional arrays as input. In Excel, ranges return two-dimensional arrays. In the above example, TRANSPOSE converts the 4×1 two-dimensional array into a 4-element one-dimensional array (this is the documented behaviour of TRANSPOSE when it is fed with a single-column two-dimensional array).
For a horizontal range, you would have to do a double TRANSPOSE:
=JoinXL(TRANSPOSE(TRANSPOSE(A1:D1)))
The inner TRANSPOSE converts the 1×4 two-dimensional array into a 4×1 two-dimensional array, which the outer TRANSPOSE then converts into the expected 4-element one-dimensional array.
This usage of TRANSPOSE is a well-known way of converting 2D arrays into 1D arrays in Excel, but it looks terrible. A more elegant solution would be to hide this away in the JoinXL VBA function.
For those who have Excel 2016 (and I suppose next versions), there is now directly the CONCAT function, which will replace the CONCATENATE function.
So the correct way to do it in Excel 2016 is :
=CONCAT(A1:A4)
which will produce :
Iamaboy
For users of olders versions of Excel, the other answers are relevant.
For Excel 2011 on Mac it's different. I did it as a three step process.
Create a column of values in column A.
In column B, to the right of the first cell, create a rule that uses the concatenate function on the column value and ",". For example, assuming A1 is the first row, the formula for B1 is =B1. For the next row to row N, the formula is =Concatenate(",",A2). You end up with:
QA
,Sekuli
,Testing
,Applitools
,Visual Testing
,Test Automation
,Selenium
In column C create a formula that concatenates all previous values. Because it is additive you will get all at the end. The formula for cell C1 is =B1. For all other rows to N, the formula is =Concatenate(C1,B2). And you get:
QA,Sekuli
QA,Sekuli,Testing
QA,Sekuli,Testing,Applitools
QA,Sekuli,Testing,Applitools,Visual Testing
QA,Sekuli,Testing,Applitools,Visual Testing,Test Automation
QA,Sekuli,Testing,Applitools,Visual Testing,Test Automation,Selenium
The last cell of the list will be what you want. This is compatible with Excel on Windows or Mac.
I use the CONCATENATE method to take the values of a column and wrap quotes around them with columns in between in order to quickly populate the WHERE IN () clause of a SQL statement.
I always just type =CONCATENATE("'",B2,"'",",") and then select that and drag it down, which creates =CONCATENATE("'",B3,"'",","), =CONCATENATE("'",B4,"'",","), etc. then highlight that whole column, copy paste to a plain text editor and paste back if needed, thus stripping the row separation. It works, but again, just as a one time deal, this is not a good solution for someone who needs this all the time.
I know this is really a really old question, but I was trying to do the same thing and I stumbled upon a new formula in excel called "TEXTJOIN".
For the question, the following formula solves the problem
=TEXTJOIN("",TRUE,(a1:a4))
The signature of "TEXTJOIN" is explained as TEXTJOIN(delimiter,ignore_empty,text1,[text2],[text3],...)
I needed a general purpose Concatenate With Separator (since I don't have TEXTJOIN) so I wrote this:
Public Function ConcatWS(separator As String, ParamArray cell_range()) As String
'---concatenate with seperator
For n = LBound(cell_range) To UBound(cell_range)
For Each cell In cell_range(n)
If Len(cell) <> 0 Then
ConcatWS = ConcatWS & IIf(ConcatWS <> "", separator, "") & cell
End If
Next
Next n
End Function
Which allows us to go crazy with flexibility in including cell ranges:
=ConcatWS(" ", Fields, E1:G2, L6:M9, O6)
NOTE: "Fields" is a Named Range and the separator may be blank
I have names in a column. I need to split just the last names from that column into another column.
The last name is delimited by a space from the right side.
The contents in cell A2 = Alistair Stevens and I entered the formula in cell B2 (I need 'Stevens' in cell B2)
I tried using the following formulas:
=RIGHT(A2,FIND(" ",A2,1)-1)
=RIGHT(A2,FIND(" ",A2))
Both these formulas work for this cell but when I fill it down / copy and paste it for the cells below it doesn't work. I get the wrong values!!
A3 -> David Mckenzie
B3 -> Mckenzie
This works, even when there are middle names:
=MID(A2,FIND(CHAR(1),SUBSTITUTE(A2," ",CHAR(1),LEN(A2)-LEN(SUBSTITUTE(A2," ",""))))+1,LEN(A2))
If you want everything BUT the last name, check out this answer.
If there are trailing spaces in your names, then you may want to remove them by replacing all instances of A2 by TRIM(A2) in the above formula.
Note that it is only by pure chance that your first formula =RIGHT(A2,FIND(" ",A2,1)-1) kind of works for Alistair Stevens. This is because "Alistair" and " Stevens" happen to contain the same number of characters (if you count the leading space in " Stevens").
The answer provided by #Jean provides a working but obscure solution (although it doesn't handle trailing spaces)
As an alternative consider a vba user defined function (UDF)
Function RightWord(r As Range) As Variant
Dim s As String
s = Trim(r.Value)
RightWord = Mid(s, InStrRev(s, " ") + 1)
End Function
Use in sheet as
=RightWord(A2)
Try this function in Excel:
Public Shared Function SPLITTEXT(Text As String, SplitAt As String, ReturnZeroBasedIndex As Integer) As String
Dim s() As String = Split(Text, SplitAt)
If ReturnZeroBasedIndex <= s.Count - 1 Then
Return s(ReturnZeroBasedIndex)
Else
Return ""
End If
End Function
You use it like this:
First Name (A1) | Last Name (A2)
Value in cell A1 = Michael Zomparelli
I want the last name in column A2.
=SPLITTEXT(A1, " ", 1)
The last param is the zero-based index you want to return. So if you split on the space char then index 0 = Michael and index 1 = Zomparelli
The above function is a .Net function, but can easily be converted to VBA.
If you want to get the second to last word in a text, you can use this macro as a function in your spreadsheet:
Public Function Get2ndText(S As String) As String
Dim sArr() As String
Dim i As Integer
sArr = Split(S, " ")
'get the next to the last string
i = UBound(sArr) - 1
Get2ndText = sArr(i)
End Function
Then in your spreadsheet B1 as the text:
CURRENT OWNER 915 BROADWAY ST HOUSTON TX 77012-2126
in B2 your formula would be:
=Get2ndText(B1)
The result would be
TX
Simpler would be:
=TRIM(RIGHT(SUBSTITUTE(TRIM(A2)," ",REPT(" ",99)),99))
You can use A2 in place of TRIM(A2) if you are sure that your data doesn't contain any unwanted spaces.
Based on concept explained by Rick Rothstein:
http://www.excelfox.com/forum/showthread.php/333-Get-Field-from-Delimited-Text-String
Sorry for being necroposter!
Right(A1, Len(A1)-Find("(asterisk)",Substitute(A1, "(space)","(asterisk)",Len(A1)-Len(Substitute(A1,"(space)", "(no space)")))))
Try this. Hope it works.
Try this:
=RIGHT(TRIM(A2),LEN(TRIM(A2))-FIND(" ",TRIM(A2)))
I was able to copy/paste the formula and it worked fine.
Here is a list of Excel text functions (which worked in May 2011, and but is subject to being broken the next time Microsoft changes their website). :-(
You can use a multiple-stage-nested IF() functions to handle middle names or initials, titles, etc. if you expect them. Excel formulas do not support looping, so there are some limits to what you can do.
RIGHT return whatever number of characters in the second parameter from the right of the first parameter. So, you want the total length of your column A - subtract the index. which is therefore:
=RIGHT(A2, LEN(A2)-FIND(" ", A2, 1))
And you should consider using TRIM(A2) everywhere it appears...
Try this:
Right(RC[-1],Len(RC[-1])-InStrRev(RC[-1]," "))