. 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
Related
Can anyone help bring me to the finish line with this Do While Loop?
Essentially, I've got a column in my spreadsheet that is populated with of sentences. I'm trying to evaluate every word in each cell to determine if it contains a keyword existing as an element in the keywords Array. If so, the included keywords are to be listed in the corresponding cells on the column "Keywords."
However, when keywords were mentioned twice my sub routine lists them twice, eg. "keyword, keyword." All I need to do is remove the duplicate keywords from my output
Here is what I have thus far for this somewhat expansive sub routine.
Private Sub brand_names() 'inserts column with product brand mentioned in SalesForce Case
Dim ws As Worksheet
Dim last_col As Integer
Dim PuncChars, products, x, InArray As Variant
Dim i As Long, r As Long, q As Long
Dim txt, inputstring As String
keywords = Array("KEYWORDONE","KEYWORDTWO","KEYWORDTHREE")
PuncChars = Array(".", ",", ";", ":", "'", "!", "#", _
"$", "%", "&", "(", ")", " - ", "_", "--", "+", _
"=", "~", "/", "\", "{", "}", "[", "]", """", "?", "*", "#")
Set ws = ThisWorkbook.Worksheets("Applicable Spreadsheet")
last_col = ws.Cells(1, Columns.Count).End(xlToLeft).Column + 1
ws.Cells(1, last_col).Value = "Keywords"
On Error GoTo Endproc
Application.ScreenUpdating = False
r = 2
Do While Not Cells(r, 12) = ""
' coverts to UPPERCASE
txt = UCase(Cells(r, 12))
' Remove punctuation
For i = 0 To UBound(PuncChars)
txt = Replace(txt, PuncChars(i), " ")
Next i
' Remove excess spaces
txt = WorksheetFunction.Trim(txt)
' Extract the words
x = Split(txt)
'append words to array
For i = 0 To UBound(x)
For z = 0 To UBound(keywords)
If x(i) = keywords(z) Then
ws.Cells(r, last_col).Value = ws.Cells(r, last_col).Value & x(i) & ","
End If
Next z
Next i
'code to remove duplicates would go here
r = r + 1
Loop
'need to remove duplciates from mentioned brands and add comma between each one
Endproc:
Application.ScreenUpdating = True
Exit Sub
MsgBox ("error")
End Sub
I'm trying to add a line to my Do loop that will reduce the duplicate keywords in the output cells, so that rather than "KEYWORDONE,KEYWORDONE" it just says "KEYWORDONE"
Does anyone have an idea how I can do this from within the Do loop?
I'm trying to build a formula that can lookup multiple ISO country codes separated by comma contained in one cell (Cell A2, Image 1) with a reference to a list of country codes and education scoring (Columns F and G, Image 1). Then return the average of the scores of all countries on cell B2. does anyone know if I can build a formula to handle that?
I didn't think you could do this with cell formula, but then I saw this post and came up with this:
=AVERAGE(IF(ISNA(MATCH($F$2:$F$99, TRIM(MID(SUBSTITUTE(A2,",",REPT(" ",99)),(ROW(OFFSET($A$1,,,LEN(A2)-LEN(SUBSTITUTE(A2,",",""))+1))-1)*99+((ROW(OFFSET($A$1,,,LEN(A2)-LEN(SUBSTITUTE(A2,",",""))+1)))=1),99)), 0)), "", $G$2:$G$99 ))
Try pasting into cell B2 as an array formula (Ctrl + Shift + Enter) and fill-down... And don't ask me how it works.
You could try VBA:
Option Explicit
Sub test()
Dim i As Long
Dim strCode As String, strScore As String
Dim rngVlookup As Range
Dim Code As Variant
With ThisWorkbook.Worksheets("Sheet1")
Set rngVlookup = .Range("F2:G34")
For i = 2 To 3
strCode = ""
strScore = ""
strCode = .Range("A" & i).Value
For Each Code In Split(strCode, ",")
If strScore = "" Then
On Error Resume Next
strScore = Application.WorksheetFunction.VLookup(Trim(Code), rngVlookup, 2, False)
Else
On Error Resume Next
strScore = strScore & ", " & Application.WorksheetFunction.VLookup(Trim(Code), rngVlookup, 2, False)
End If
Next Code
With .Range("B" & i)
.Value = strScore
.NumberFormat = "0.000000"
End With
Next i
End With
End Sub
I'm trying to find an exact word from a sentence by excel VBA with below code.
Dim col As Range, cell1 As Range, a As String, i As Integer
Set col = Range("KW[KW1]")
Dim target, cell As Range
Sheets("Data").Select
Set target = Range(Range("B1"), Range("B65536").End(xlUp))
Dim term, tag As String
For Each cell1 In col
a = cell1.Value
term = a
tag = a
For Each cell In target
If InStr(1, cell, term, 1) Then
For i = 1 To 50
If cell.Offset(0, i).Value = "" Then
cell.Offset(0, i).Value = tag
GoTo Step1
End If
Next i
End If
Step1:
Next cell
Next cell1
End Sub
But its giving result for "wood" from "Rosewood" which is wrong. How to find only exact word "wood"
Easiest way to do exact word searches is to surround the search text and the word you're looking for with spaces. Using your code it would like this:
If InStr(1, " " & cell & " ", " " & term & " ", 1) Then
That way it won't find "wood" within "Rosewood"
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
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