I'm trying to concatenate a bunch of columns in Excel. I know I can manually do with:
=A1&", "&B1&", "&C1 (and so on)
but I have about 40 columns, and I'm looking for a way to streamline this process.
Thanks in advance for any help!
As a user function taking a range
Public Function ClarkeyCat(ByRef rng As Range) As Variant
Dim c As Range
Dim ans As Variant
For Each c In rng
If (c.Value <> "") Then
ans = IIf(ans = "", "", ans & ",") & c.Value
End If
Next
ClarkeyCat = ans
End Function
Changing the Variant types, if you need to (to string, most likely).
Use like this:
I would use vba for this. For each column you would want something like (assuming values are in row 1)
myString = ""
for i = 1 to 40
if i <> 40 then
myString = myString & Cells(1, i) & ", "
else:
myString = myString & Cells(1, i)
end if
next i
myString will then have the contents of your concatenated string.
Let me post my function too. I've run into this problem as well in the past.
My problem usually arise when I try to concatenate dates, errors and blank cells.
So I try to cover most of those using below:
Function CONCATPLUS(ref_value As Range, Optional delimiter As Variant) As String
Dim cel As Range
Dim refFormat As String, myvalue As String
If ref_value.Cells.Count = 1 Then CONCATPLUS = CVErr(xlErrNA): Exit Function
If IsMissing(delimiter) Then delimiter = " "
For Each cel In ref_value
refFormat = cel.NumberFormat
Select Case TypeName(cel.Value)
Case "Empty": myvalue = vbNullString
Case "Date": myvalue = Format(cel, refFormat)
Case "Double"
Select Case True
Case refFormat = "General": myvalue = cel
Case InStr(refFormat, "?/?") > 0: myvalue = cel.Text
Case Else: myvalue = Format(cel, refFormat)
End Select
Case "Error"
Select Case True
Case cel = CVErr(xlErrDiv0): myvalue = "#DIV/0!"
Case cel = CVErr(xlErrNA): myvalue = "#N/A"
Case cel = CVErr(xlErrName): myvalue = "#NAME?"
Case cel = CVErr(xlErrNull): myvalue = "#NULL!"
Case cel = CVErr(xlErrNum): myvalue = "#NUM!"
Case cel = CVErr(xlErrRef): myvalue = "#REF!"
Case cel = CVErr(xlErrValue): myvalue = "#VALUE!"
Case Else: myvalue = "#Error"
End Select
Case "Currency": myvalue = cel.Text
Case Else: myvalue = cel
End Select
If Len(myvalue) <> 0 Then
If CONCATPLUS = "" Then
CONCATPLUS = myvalue
Else
CONCATPLUS = CONCATPLUS & delimiter & myvalue
End If
End If
Next
End Function
As of now, I've not encountered a cell entry this function cannot concatenate.
Feel free to adjust to your needs or hearts content. HTH.
When concatenating a range single row or column you can do this in a single shot using Application.Transpose to avoid range loops
This UDF has three arguments
A 1D range (can be a column or row)
An optional delimiter (, is used if there is no entrey)
An optional entry to specify if the range is a row (enter TRUE for a range - which on further thought I will update the UDF to automatically detect whether the range is row OR column BASED)
Note that in terms of the other answers
IIF evaluates both the TRUE and FALSE arguments as VBA doesn't [short circuit](
http://en.wikipedia.org/wiki/Short-circuit_evaluation). So IFF can be expensive inside loops
when concatenating join the long string to the combined output of the short strings, rather than long with short, then long with short again
code
Function ConCat(rng1 As Range, Optional StrDelim As String, Optional bRow As Boolean) As String
Dim x
If StrDelim = vbNullString Then StrDelim = ","
x = Application.Transpose(rng1)
If bRow Then x = Application.Transpose(x)
ConCat = Join(x, StrDelim)
End Function
In the example below
the formula (D1) is =concat(A1:C1,",",TRUE)
the formula in E1 is =concat(E3:E5,", ")
You can always use Visual Basic For Applications (VBA). It is microsofts language for Office. Here is an example of what you might be looking for but try the Google Machine to learn more about VBA and how to input this code into your spreadsheet.
Sub ConcatColumns()
Do While ActiveCell <> "" 'Loops until the active cell is blank.
'The "&" must have a space on both sides or it will be
'treated as a variable type of long integer.
ActiveCell.Offset(0, 1).FormulaR1C1 = _
ActiveCell.Offset(0, -1) & " " & ActiveCell.Offset(0, 0)
ActiveCell.Offset(1, 0).Select
Loop
End Sub
Related
Disclaimer- my case is specific, and in my case my code works because I know the pattern.
I was looking for an answer everywhere, and the codes I tried were not quite what I was looking for, this is my solution if you are looking for a set of numbers.
In my case, I was looking for 7 digits, starting with digit 1 in a a column with random strings, some string had the number some others didn't.
The number will appear in these three scenarios "1XXXXXX", "PXXXXXXXX", "PXXXXXXXXX"(this has more digits because there is a slash).
Here are the examples of strings:
9797 P/O1743061 465347 Hermann Schatte Earl Lowe
9797 Po 1743071 404440 Claude Gaudette Jose Luis Lopez
9817 1822037 463889 Jean Caron Mickelly Blaise
My Code
Sub getnum()
'i don't use explicit so i didn't declare everything
Dim stlen As String
Dim i As Integer
Dim arra() As String
Dim arran() As String
Orig.AutoFilterMode = False
Call BeginMacro
LastRow = Orig.Cells(Rows.Count, 1).End(xlUp).Row
Orig.Range("J2:J" & LastRow).Clear
'loop though column
For n = 2 To LastRow
celref = Orig.Cells(n, 4).Value
'split string on white spaces
arra() = Split(celref, " ")
'turn string to multiple strings
For counter = LBound(arra) To UBound(arra)
strin = arra(counter)
'remove white spaces from string
storage = Trim(strin)
lenof = Len(storage)
'if string has 9 characthers, check for conditions
If lenof = 9 Then
'position of first and last charachter
somstr = Mid(storage, 1, 1)
somot = Mid(storage, 9, 1)
If somstr = "P" Or somstr = "p" And IsNumeric(somot) = True Then
'removes Po or PO and keeps only 7 digits
storage = Right(storage, 7)
'stores in column J
Orig.Cells(n, 10).Value = storage
End If
ElseIf lenof = 10 Then
somstr = Mid(storage, 1, 1)
somot = Mid(storage, 10, 1)
'other conditions
If somstr = "P" Or somstr = "p" And IsNumeric(somot) = True Then
'removes Po or PO and keeps only 7 digits
storage = Right(storage, 7)
'stores in column J
Orig.Cells(n, 10).Value = storage
End If
End If
'eliminate comma within
arran() = Split(storage, ",")
If Orig.Cells(n, 10).Value <> storage Then
For counter2 = LBound(arran) To UBound(arran)
strin2 = arran(counter2)
storage2 = Trim(strin2)
'final condition if is 7 digits and starts with 1
If IsNumeric(storage2) = True And Len(storage2) = 7 Then
car = Mid(storage2, 1, 1)
If car = 1 Then
'stores in columns J at specific position
Orig.Cells(n, 10).Value = storage2
End If
Else
If isnumeric(orig.cells(n,10).value) =true and _
len(orig.cells(n,10).value = 7 then
orig.cells(n,10).value = orig.cells(n,10).value
else
Orig.Cells(n, 10).Value = "no po# in D"
End If
Next counter2
End If
Next counter
Next n
Call EndMacro
End Sub
you may try this
Option Explicit
Sub getnum()
Dim position As Variant
Dim cell As Range
With Worksheets("Orig") ' change it to your actual sheet name
With Intersect(.UsedRange, Columns("J"))
.Replace what:="P/O", replacement:="P/O ", lookat:=xlPart
For Each cell In .Cells
position = InStr(cell.Text, " 1")
If position > 0 Then cell.Value = Mid(cell.Value, position + 1, 7)
Next
End With
End With
End Sub
This code paste two formulas one in column G and one in column J). The first formula checks for a "P" in the first character of the cell in column 2 and if there is a "P" it extracts the last 7 characters in the string and puts them in column G. The second formula checks if there is not a "P" and if not extracts the last 7 characters in the string and puts them in column J.
Sub Extract()
Dim ws As Worksheet
Dim lRow As Long
Set ws = ThisWorkbook.Sheets("Sheet3")
lRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
ws.Range("G2:G" & lRow).Formula = "=IF(LEFT(B2)=""P"",(RIGHT(B2,7)),"""")"
ws.Range("J2:J" & lRow).Formula = "=IF(LEFT(B2)<>""P"",(RIGHT(B2, 7)),"""")"
End Sub
You may use the RegEx to extract the number in desired format.
Please give this a try...
Function Get10DigitNumber(ByVal Str As String) As String
Dim RE As Object
Set RE = CreateObject("VBScript.RegExp")
With RE
.Global = False
.Pattern = "1\d{6}"
End With
If RE.test(Str) Then
Get10DigitNumber = RE.Execute(Str)(0)
End If
End Function
Then if you want to use this function on the worksheet itself, assuming your string is in A2, try this...
=Get10DigitNumber(A2)
OR
You may use this function in another sub routine/macro like this...
Debug.Print Get10DigitNumber(<pass your string variable here>)
Edited Function:
Function Get10DigitNumber(ByVal Str As String) As String
Dim RE As Object, Matches As Object
Set RE = CreateObject("VBScript.RegExp")
With RE
.Global = False
.Pattern = "[Pp]?\/?[Oo]?(1\d{6})\b"
End With
If RE.test(Str) Then
Set Matches = RE.Execute(Str)
Get10DigitNumber = Matches(0).SubMatches(0)
End If
End Function
And use if as already described above.
After understanding what you were doing, I think this will work. Any feedback would be appreciated.
Dim cell As Range, LRow As Long
LRow = ActiveSheet.Cells(Rows.Count, 4).End(xlUp).Row
For Each cell In Range("D2:D" & LRow)
If cell.Value Like "*Po *" Then
cell.Offset(0, 6).Value = Split(cell.Value, " ")(2)
Else: cell.Offset(0, 6).Value = Split(cell.Value, " ")(1)
End If
Next cell
For Each cell In Range("J2:J" & LRow)
If Len(cell.Value) > 7 Then
cell.Value = Right(cell.Value, 7)
End If
Next
I have tried this code which works fine for a cell that only contain number:
Sub IncreaseCellValue()
'Add 1 to the existing cell value
Range("A1").Value = Range("A1") + 1
End Sub
How can I do something similar if the cell has text and a number. For example, I have "Apple 1" and I want to "increase" the cell text to "Apple 2" and next time I run the macro I want "Apple 3".
Here's another way you could solve this problem:
Sub IncreaseCellValue()
Dim value As Variant
'Add 1 to the existing cell value
If IsNumeric(Range("A1").value) Then
Range("A1").value = Range("A1") + 1
Else
value = Split(Range("A1").value, " ")
Range("A1").value = value(0) & " " & (CInt(value(1)) + 1)
End If
End Sub
It will cover the 2 cases you presented in your question but not every scenario you could throw at it.
Try using the following function
Sub IncreaseCellValue()
'Add 1 to the existing cell value
Range("A1").Value = Replace(Range("A1").Value2, CleanString(Range("A1")), vbNullString) & CInt(CleanString(Range("A1").Value2)) + 1
End Sub
Function CleanString(strIn As String) As String
Dim objRegex
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.Pattern = "[^\d]+"
CleanString = .Replace(strIn, vbNullString)
End With
End Function
please check:
Option Explicit
Sub IncreaseCellValue()
'Add 1 to the existing cell value
Dim rg As Range
Set rg = Cells(Rows.Count, "A").End(xlUp)
Range("A1" & ":" & rg.Address).AutoFill Destination:=Range("A1" & ":" & rg.Offset(1, 0).Address), Type:=xlFillDefault
End Sub
Or you may try something like this...
Function GetNumber(ByVal rng As Range) As Long
Dim i As Long
For i = Len(rng.Value) To 1 Step -1
If IsNumeric(Mid(rng.Value, i, 1)) Then
GetNumber = GetNumber & Mid(rng.Value, i, 1)
Else
Exit For
End If
Next i
End Function
Sub IncrementNumber()
Dim num As Long
num = GetNumber(Range("A1"))
Range("A1").Value = Replace(Range("A1").Value, num, num + 1)
End Sub
Assuming there are blank columns in between and there can be more than 1 blank column in between,
how do I go about coding in vba excel.
Items in a column:
Nice
to
meet
you.
As a result I am looking for:
Nice to meet you.
As commented, this is a function I've written to connect Range values in one go.
It concatenates it based on how you see it in the cell.
I'm not entirely sure though if I've covered all the possibilities but you can give it a try.
Public Function CONCATPLUS(ref_value As Range, Optional delimiter As Variant) As String
Dim cel As Range
Dim refFormat As String, myvalue As String
If ref_value.Cells.Count = 1 Then CONCATPLUS = CVErr(xlErrNA): Exit Function
If IsMissing(delimiter) Then delimiter = " "
For Each cel In ref_value
refFormat = cel.NumberFormat
Select Case TypeName(cel.Value)
Case "Empty": myvalue = vbNullString
Case "Date": myvalue = Format(cel, refFormat)
Case "Double"
If refFormat <> "General" Then
myvalue = Format(cel, refFormat)
Else
myvalue = cel
End If
Case "Error"
Select Case True
Case cel = CVErr(xlErrDiv0): myvalue = "#DIV/0!"
Case cel = CVErr(xlErrNA): myvalue = "#N/A"
Case cel = CVErr(xlErrName): myvalue = "#NAME?"
Case cel = CVErr(xlErrNull): myvalue = "#NULL!"
Case cel = CVErr(xlErrNum): myvalue = "#NUM!"
Case cel = CVErr(xlErrRef): myvalue = "#REF!"
Case cel = CVErr(xlErrValue): myvalue = "#VALUE!"
Case Else: myvalue = "#Error"
End Select
Case Else: myvalue = cel
End Select
If Len(myvalue) <> 0 Then
If CONCATPLUS = "" Then
CONCATPLUS = myvalue
Else
CONCATPLUS = CONCATPLUS & delimiter & myvalue
End If
End If
Next
End Function
. I have an excel spreadsheet which contains some strings with unicode control characters that aren't visible in Windows 7. Therefore, I would like to write a macro to iterate through each cell in a column, checking if a control character is present. If a control character is found, I would like to populate the adjacent cell in the next column with the character name and the index it can be found within the string.
This is what I have so far:
Sub control_chr()
'
' control_chr Macro
'
'
Dim control_characters(Chr(28), Chr(29), Chr(30), Chr(31), Chr(32))
Dim r As Range, cell As Range
Set r = Range("F4:F1029")
For Each cell In r
For Each Character In control_characters
the next step would be to search the cell for each character and populate adjacent cells with the results. My first thought was to use the SEARCH() function since it returns the index of where the character is found. This is my first time using visual basic and I'm not sure how to proceed
Here's some code that does what you asked:
Sub ListControlChars()
Dim control_characters As Variant
Dim r As Range, cell As Range, ResultCell As Range
Dim CharPosition As Long
Dim i As Long
control_characters = Array(28, 29, 30, 31, 32)
Set r = ActiveSheet.Range("F4:F1029")
For Each cell In r
Set ResultCell = cell.Offset(0, 1)
ResultCell.ClearContents
CharPosition = 0
For i = LBound(control_characters) To UBound(control_characters)
CharPosition = InStr(cell, Chr(control_characters(i)))
If CharPosition > 0 Then
ResultCell = ResultCell.Value & "Char " & control_characters(i) & ": Position " & CharPosition & " - "
End If
Next i
Next cell
End Sub
If you want to do it in Excel you could set it up like this:
The formula in B2 is:
=IFERROR(SEARCH(CHAR(B$1),$A2),"")
I can't recall if I coded this up or found it somewhere else, but this works for me when encountering issues with loading data into certain databases which fail on unrecognised special characters
Function IterateThruCells()
Dim cell As Range
For Each cell In ActiveSheet.UsedRange.Cells
If cell.Value <> "" Then
If ContainsSpecialCharacters(cell.Value) = True Then
Debug.Print cell.Address & ": " & cell.Value
End If
End If
Next
End Function
Function ContainsSpecialCharacters(str As String) As Boolean
Dim I
For I = 1 To Len(str)
ch = Mid(str, I, 1)
Select Case ch
Case "0" To "9", "A" To "Z", "a" To "z", " ", "(", ")", "/", "-", ".", ",", "_", "&", "'", "$", ">", "<", "–"
ContainsSpecialCharacters = False
Case Else
ContainsSpecialCharacters = True
Exit For
End Select
Next
End Function
I'm not entirely sure how to word this but, I have an Excel macro that enables a search functionality within my workbook. My issue is that I need the search to understand 'é' as 'e'. So that if I search for 'Belem', my result would come back with 'Belém'. How would I go about this? Thanks for any time and consideration.
Sub city()
If ActiveSheet.Name <> "City" Then Exit Sub
LastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Sheets("Results").Range("3:10000").Delete
SearchTerm = Application.InputBox("What are you looking for?")
Application.ScreenUpdating = False
Range("W1") = SearchTerm
Range("W2:W" & LastRow).FormulaR1C1 = _
"=IF(ISERR(SEARCH(R1C23,RC[-22]&RC[-21]&RC[-20]&RC[-19]&RC[-18]&RC[-17]&RC[-16]&RC[-15]&RC[-15]&RC[-14]&RC[-13]&RC[-12]&RC[-11]&RC[-10]&RC[-9]&RC[-8]&RC[-7]&RC[-6]&RC[-5]&RC[-4]&RC[-3]&RC[-2]&RC[-1])),0,1)"
If WorksheetFunction.CountIf(Columns(23), 1) = 0 Then
Columns(23).Delete
Application.ScreenUpdating = True
MsgBox "None found."
Else
For Each Cell In Range("A2:A" & LastRow)
If Cell.Offset(, 22) = 1 Then
Cell.Resize(, 51).Copy Sheets("Results").Range("A" & Rows.Count).End(xlUp).Offset(1)
x = x + 1
End If
Next Cell
Columns(22).Delete
Application.ScreenUpdating = True
If x = 1 Then
MsgBox "1 matching record was copied to Search Results tab."
Else
MsgBox x & " matching records were copied to Search Results tab."
End If
End If
End Sub
You can modify the search parameter and then use the like operator as follows:
Sub city()
Dim rngResult As Range
Dim searchTerm As String, counter As Integer
Dim values As Variant, value As Variant
If ActiveSheet.Name <> "City" Then Exit Sub
'First Cell with the results
Set rngResult = <First cell of the result Range>
'Uses a variant array to get all values from the range. This speeds up the routine
values = <Area of Search>.Value
'Converts to lowercase to do a case insensitive search (e.g. Belem = belem)
searchTerm = LCase(Application.InputBox("What are you looking for?"))
If searchTerm = "" Then Exit Sub
' "§" is just a placeholder
searchTerm = Replace(searchTerm, "e", "§")
searchTerm = Replace(searchTerm, "é", "§")
searchTerm = Replace(searchTerm, "§", "[eé]")
Application.ScreenUpdating = False
counter = 0
For Each value In values
If LCase(value) Like searchTerm Then
rngResult = value
Set rngResult = rngResult.Offset(1, 0) 'Moves to the next line
counter = counter + 1
End If
Next value
If counter = 0 Then
MsgBox "None found."
Else
MsgBox "Found " & counter & " results"
'Do what you need to do with the results
End If
Application.ScreenUpdating = True
End Sub
All the results will be at the column of rngResult.
The code works by replacing "e" and "é" by "§" and then replacing "§" by "[eé]", (e.g. "bélem" -> "bél§m" -> "b§l§m" -> "b[eé]l[eé]m").
The like will match either "e" or "é" on that position. You can learn more about it here or in the help files. Here is a Example:
bélem Like "b[eé]l[eé]m" ' true
belem like "b[eé]l[eé]m" ' true
recife like "b[eé]l[eé]m" ' false
You can search more graphs by adding other criteria like:
'Like will match "a","á", "à" and "ã"
searchTerm = Replace(searchTerm, "a", "§")
searchTerm = Replace(searchTerm, "á", "§")
searchTerm = Replace(searchTerm, "à", "§")
searchTerm = Replace(searchTerm, "ã", "§")
searchTerm = Replace(searchTerm, "§", "[aáàã]")
This method has the advantage that you only need one "translation" in order to do comparisons. This can improve the performance if you have a large dataset
You can keep an array of all the characters you want to replace and what you want to replace them with. It's easier if you "search" your data a little differently that using that formula. Here's how I would do it.
Sub FindCity()
Dim shResults As Worksheet
Dim vaData As Variant
Dim i As Long, j As Long
Dim sSearchTerm As String
Dim sData As String
Dim rNext As Range
'Put all the data into an array
vaData = ActiveSheet.UsedRange.Value
'Get the search therm
sSearchTerm = Application.InputBox("What are you looking for?")
'Define and clear the results sheet
Set shResults = ActiveWorkbook.Worksheets("Results")
shResults.Range("A3").Resize(shResults.UsedRange.Rows.Count, 1).EntireRow.Delete
'Loop through the data
For i = LBound(vaData, 1) To UBound(vaData, 1)
For j = LBound(vaData, 2) To UBound(vaData, 2)
'Get rid of diacritial characters
sData = LCase(Anglicize(vaData(i, j)))
'Look for a match
If InStr(1, sData, LCase(Anglicize(sSearchTerm))) > 0 Then
'Write the row to the next available row on Results
Set rNext = shResults.Cells(shResults.Rows.Count, 1).End(xlUp).Offset(1, 0)
rNext.Resize(1, UBound(vaData, 2)).Value = Application.Index(vaData, i, 0)
'Stop looking in that row after one match
Exit For
End If
Next j
Next i
End Sub
Public Function Anglicize(ByVal sInput As String) As String
Dim vaGood As Variant
Dim vaBad As Variant
Dim i As Long
Dim sReturn As String
'Replace any 'bad' characters with 'good' characters
vaGood = Split("S,Z,s,z,Y,A,A,A,A,A,A,C,E,E,E,E,I,I,I,I,D,N,O,O,O,O,O,U,U,U,U,Y,a,a,a,a,a,a,c,e,e,e,e,i,i,i,i,d,n,o,o,o,o,o,u,u,u,u,y,y", ",")
vaBad = Split("Š,Ž,š,ž,Ÿ,À,Á,Â,Ã,Ä,Å,Ç,È,É,Ê,Ë,Ì,Í,Î,Ï,Ð,Ñ,Ò,Ó,Ô,Õ,Ö,Ù,Ú,Û,Ü,Ý,à,á,â,ã,ä,å,ç,è,é,ê,ë,ì,í,î,ï,ð,ñ,ò,ó,ô,õ,ö,ù,ú,û,ü,ý,ÿ", ",")
sReturn = sInput
For i = LBound(vaBad) To UBound(vaBad)
sReturn = Replace$(sReturn, vaBad(i), vaGood(i))
Next i
Anglicize = sReturn
End Function
List of characters from Excel 2007 VBA Converting Accented Characters to Regular