In VBA, how do you convert text containing Unicode to HTML entities?
Eg. Test chars: èéâ👍 would be converted to Test chars: èéâ👍
In Excel, characters are stored using Unicode UTF-16. The "Thumbs up" character (👍) corresponds to the Unicode character U+1F44D, encoded as follows:
in UTF-16 (hex) : 0xD83D 0xDC4D (d83ddc4d)
in UTF-16 (decimal) : 55357 , 56397
The following function (and test procedure) should convert as expected:
Sub test()
txt = String2Html("Test chars: èéâ" & ChrW(&HD83D) & ChrW(&HDC4D))
debug.print txt ' -> Test chars: èéâ👍
End Sub
Function String2Html(strText As String) As String
Dim i As Integer
Dim strOut As String
Dim char As String
Dim char2 As String
Dim intCharCode As Integer
Dim intChar2Code As Integer
Dim unicode_cp As Long
For i = 1 To Len(strText)
char = Mid(strText, i, 1)
intCharCode = AscW(char)
If (intCharCode And &HD800) = &HD800 Then
i = i + 1
char2 = Mid(strText, i, 1)
intChar2Code = AscW(char2)
unicode_cp = (intCharCode And &H3FF) * (2 ^ 10) + (intChar2Code And &H3FF)
strOut = strOut & "&#x" & CStr((intCharCode And &H3C0) + 1) & Hex(unicode_cp) & ";"
ElseIf intCharCode > 127 Then
strOut = strOut & "&#x" & Hex(intCharCode) & ";"
ElseIf intCharCode < 0 Then
strOut = strOut & "&#x" & Hex(65536 + intCharCode) & ";"
Else
strOut = strOut & char
End If
Next
String2Html = strOut
End Function
To convert Unicode to Asci (eg: æ to æ)
Public Function UnicodeToAscii(sText As String) As String
Dim x As Long, sAscii As String, ascval As Long
If Len(sText) = 0 Then
Exit Function
End If
sAscii = ""
For x = 1 To Len(sText)
ascval = AscW(Mid(sText, x, 1))
If (ascval < 0) Then
ascval = 65536 + ascval ' http://support.microsoft.com/kb/272138
End If
sAscii = sAscii & "&#" & ascval & ";"
Next
UnicodeToAscii = sAscii
End Function
To convert Asci to Unicode (eg: æ to æ)
Public Function AsciiToUnicode(sText As String) As String
Dim saText() As String, sChar As String
Dim sFinal As String, saFinal() As String
Dim x As Long, lPos As Long
If Len(sText) = 0 Then
Exit Function
End If
saText = Split(sText, ";") 'Unicode Chars are semicolon separated
If UBound(saText) = 0 And InStr(1, sText, "&#") = 0 Then
AsciiToUnicode = sText
Exit Function
End If
ReDim saFinal(UBound(saText))
For x = 0 To UBound(saText)
lPos = InStr(1, saText(x), "&#", vbTextCompare)
If lPos > 0 Then
sChar = Mid$(saText(x), lPos + 2, Len(saText(x)) - (lPos + 1))
If IsNumeric(sChar) Then
If CLng(sChar) > 255 Then
sChar = ChrW$(sChar)
Else
sChar = Chr$(sChar)
End If
End If
saFinal(x) = Left$(saText(x), lPos - 1) & sChar
ElseIf x < UBound(saText) Then
saFinal(x) = saText(x) & ";" 'This Semicolon wasn't a Unicode Character
Else
saFinal(x) = saText(x)
End If
Next
sFinal = Join(saFinal, "")
AsciiToUnicode = sFinal
Erase saText
Erase saFinal
End Function
I hope this would be help someone,
I got this code from here
how do I check if the string variable is empty in vba?
if:
Dim StrFile1 As String, StrFile2 As String
Dim Text3 As String
Dim Len1 as Integer, Len2 As Integer
With NewMail
Text3 = Cells(i, 3).Value
StrPath = Cells(i, 2).Value & Text3
Text = Cells(i, 1).Value
.Subject =
' adds the data in column3 with space as subject
.From =
.To = Text
.BCC = ""
.TextBody =
StrFile1 = Dir(StrPath & "*.txt")
Len1 = Len(StrFile1)
Do While Len(StrFile1) > 0
.AddAttachment StrPath & StrFile1
StrFile1 = Dir
Loop
StrFile2 = Dir(StrPath & "*.pdf")
Len2 = Len(StrFile2)
Do While Len(StrFile2) > 0
.AddAttachment StrPath & StrFile2
StrFile2 = Dir
Loop
If (Len1 & Len2) = 0 Then
GoTo Last
'.AddAttachment Text3
.Send
End With
i = i + 1
Loop
Last:
End With
i = i + 1
Loop
Now i want to check simultaneously if Len1 and Len2 are 0, if so then I want to go to Last.
When I use this code I get a message/Compile error "Want to end with without with"
and
i am not sure if
If (Len1 & Len2) = 0 Then
GoTo Last
this is a proper code.
and Do i need to declare the label Last??
You have many way to do that like below :
Dim StrFiles As String
StrFiles = Trim(StrFile1 & StrFile2)
If IsEmpty(StrFiles) Then
If StrFiles = vbNullString Then
If StrFiles = "" Then
If StrFiles = Empty Then
If Len(StrFiles) = 0 Then
you can use + operator to check 2 strings are empty reference to your code, because Len Function returns an integer containing either the number of characters in a string
If (Len1 + Len2) = 0 Then
You can use Trim(strFile1 & vbNullString) = vbNullString to check if the string is empty.
So:
If Trim(strFile1 & vbNullString) = vbNullString Then
Debug.print "Empty String!"
End If
Thanks to #LordPeter
is.empty doesn't exist for VBA, but the second option works.
Alternatively, you can write:
(strFile1 & strFile2) = vbNullString
or
(strFile1 & strFile2) = ""
Yet another way is:
If Len(strFile1 & strFile2) > 0 Then
I did test to ensure that strings which aren't set return a length of 0, which appeared to be the case.
After all my searching for code to read in a VLOOKUP formula and converting it to INDEX/MATCH came up empty, I wrote some myself.
However, the code (below) is lacking some of the flexibility I would like, but I can't seem to figure out how to make it work. Specifically, I would like to test each range criterion in the VLOOKUP formula for being an absolute reference or not, i.e. preceded by $, and carry that through to the INDEX/MATCH formula that results. For example, the formula =VLOOKUP(A2,$A$1:B$11,2,FALSE) should convert to =INDEX(B$1:B$11,MATCH(A2,$A1:$A11,0)).
NOTE: This sub depends on two functions (ColumnLetterToNumber and ColumnNumberToLetter). As their names imply they take column letters or numbers and interconvert them. Both these functions are short, simple, and work without problems. However, if anyone believes that the code to one or both of them would be helpful, I would be happy to provide them.
Additionally, any ideas on improving code readability and/or execution efficiency would also be appreciated.
Option Explicit
Public Sub ConvertToIndex()
Dim booLookupType As Boolean
Dim booLeftOfColon As Boolean
Dim booHasRowRef As Boolean
Dim lngStartCol As Long
Dim lngRefCol As Long
Dim lngStart As Long
Dim lngEnd As Long
Dim lngMatchType As Long
Dim lngInt As Long
Dim lngRowRef As Long
Dim strRefCol As String
Dim strOldFormula As String
Dim strNewFormula As String
Dim strLookupCell As String
Dim strValueCol As String
Dim strMatchCol As String
Dim strStartRow As String
Dim strEndRow As String
Dim strCheck As String
Dim strLookupRange As String
Dim strTabRef As String
Dim strSheetRef As String
Dim rngToMod As Range
Dim rngModCell As Range
Set rngToMod = Selection
For Each rngModCell In rngToMod
strOldFormula = rngModCell.Formula
lngStart = InStrRev(strOldFormula, "VLOOKUP(")
If lngStart > 0 Then
lngStart = InStr(lngStart, strOldFormula, "(") + 1
lngEnd = InStr(lngStart, strOldFormula, ",")
strLookupCell = Mid(strOldFormula, lngStart, lngEnd - lngStart)
lngStart = lngEnd + 1
lngEnd = InStr(lngStart, strOldFormula, ",")
strLookupRange = Mid(strOldFormula, lngStart, lngEnd - lngStart)
lngStart = lngEnd + 1
lngEnd = InStr(lngStart, strOldFormula, ",")
lngRefCol = CInt(Mid(strOldFormula, lngStart, lngEnd - lngStart))
lngStart = lngEnd + 1
lngEnd = InStr(lngStart, strOldFormula, ")")
booLookupType = (Mid(strOldFormula, lngStart, lngEnd - lngStart) = "TRUE")
If booLookupType Then
lngMatchType = 1
Else
lngMatchType = 0
End If
booLeftOfColon = True
lngEnd = InStr(1, strLookupRange, "]")
If lngEnd > 0 Then
strSheetRef = Left(strLookupRange, lngEnd)
strLookupRange = Right(strLookupRange, Len(strLookupRange) - lngEnd)
Else
strSheetRef = ""
End If
lngEnd = InStr(1, strLookupRange, "!")
If lngEnd > 0 Then
strTabRef = Left(strLookupRange, lngEnd)
strLookupRange = Right(strLookupRange, Len(strLookupRange) - lngEnd)
Else
strTabRef = ""
End If
For lngInt = 1 To Len(strLookupRange)
strCheck = Mid(strLookupRange, lngInt, 1)
Select Case True
Case strCheck = ":"
booLeftOfColon = False
Case booLeftOfColon
If IsNumeric(strCheck) Then
strStartRow = strStartRow & strCheck
Else
strMatchCol = strMatchCol & strCheck
End If
Case Else
If IsNumeric(strCheck) Then strEndRow = strEndRow & strCheck
End Select
Next lngInt
strMatchCol = Replace(strMatchCol, "$", "")
lngStartCol = ColumnLetterToNumber(strMatchCol)
strValueCol = ColumnNumberToLetter(lngStartCol + lngRefCol - 1)
If Len(strStartRow) > 0 Then strStartRow = "$" & strStartRow
If Len(strEndRow) > 0 Then strEndRow = "$" & strEndRow
strValueCol = strSheetRef & strTabRef & strValueCol & strStartRow & ":" & strValueCol & strEndRow
strMatchCol = strSheetRef & strTabRef & strMatchCol & strStartRow & ":" & strMatchCol & strEndRow
strNewFormula = "=INDEX(" & strValueCol & ",MATCH(" & "$" & strLookupCell & "," & strMatchCol & "," & lngMatchType & "))"
rngModCell.Formula = strNewFormula
End If
Next rngModCell
End Sub
At this time I am not looking for help to take this to the next step of enabling it to process VLOOKUP/HLOOKUP or VLOOKUP/MATCH combination formulas.
To avoid all errors I can think of, you would need to change it to a not so good looking way like this:
Sub changeToIndex()
Dim xText As Boolean
Dim xBrac As Long
Dim VLSep As New Collection
Dim i As Long, t As String
With Selection.Cells(1, 1) 'just for now
'it assumes that there is NEVER a text string which has VLOOKUP like =A1&"mean text with VLOOKUP inside it"
While InStr(1, .Formula, "VLOOKUP", vbTextCompare)
Set VLSep = New Collection
VLSep.Add " " & InStr(1, .Formula, "VLOOKUP", vbTextCompare) + 7
'get the parts
For i = VLSep(1) + 1 To Len(.Formula)
t = Mid(.Formula, i, 1)
If t = """" Then
xText = Not xText
ElseIf Not xText Then 'avoid "(", ")" and "," inside of the string to be count
If t = "(" Then
xBrac = xBrac + 1
ElseIf xBrac Then 'cover up if inside of other functions
If t = ")" Then xBrac = xBrac - 1
ElseIf t = ")" Then
VLSep.Add " " & i
Exit For
ElseIf t = "," Then
VLSep.Add " " & i 'the space is to avoid errors with index and item if both are numbers
End If
End If
Next
Dim xFind As String 'get all the parts
Dim xRng As String
Dim xCol As String
Dim xType As String
xFind = Mid(.Formula, VLSep(1) + 1, VLSep(2) - VLSep(1) - 1)
xRng = Mid(.Formula, VLSep(2) + 1, VLSep(3) - VLSep(2) - 1)
xCol = Mid(.Formula, VLSep(3) + 1, VLSep(4) - VLSep(3) - 1)
If VLSep.Count = 5 Then
xType = Mid(.Formula, VLSep(4) + 1, VLSep(5) - VLSep(4) - 1)
Else
xType = "0"
End If
Dim fullFormulaNew As String 'get the whole formulas
Dim fullFormulaOld As String
fullFormulaNew = "INDEX(" & xRng & ",MATCH(" & xFind & ",INDEX(" & xRng & ",,1)," & xType & ")," & xCol & ")"
fullFormulaOld = Mid(Selection.Cells(1, 1).Formula, VLSep(1) - 7, VLSep(VLSep.Count) - VLSep(1) + 8)
.Formula = Replace(.Formula, fullFormulaOld, fullFormulaNew) 'simply replace the old one with the new one
Wend
End With
End Sub
It also should work for very complex formulas. Still you would need some special checks to cut everything so it looks like you want. I just assumed that the range for the vlookup may be something like IF(A1=1,B1:C10,L5:N30) and this said, you would need additional subs to also clear something like this up. :(
A formula like
=VLOOKUP(VLOOKUP(IF(TRUE,A2,"aaa"),$A$1:B$11,2),$B$1:$C$11,2,FALSE)
will be changed (messed up) this way to
=INDEX($B$1:$C$11,MATCH(INDEX($A$1:B$11,MATCH(IF(TRUE,A2,"aaa"),INDEX($A$1:B$11,,1),0),2),INDEX($B$1:$C$11,,1),FALSE),2)
EDIT
Assuming your formulas are "normal" you can replace the the last part with:
Dim xFind As String 'get all the parts
Dim xRngI As String, xRngM As String
Dim xCol As String
Dim xType As String
xFind = Mid(.Formula, VLSep(1) + 1, VLSep(2) - VLSep(1) - 1)
xRngI = Mid(.Formula, VLSep(2) + 1, VLSep(3) - VLSep(2) - 1)
xCol = Mid(.Formula, VLSep(3) + 1, VLSep(4) - VLSep(3) - 1)
If VLSep.Count = 5 Then
xType = Mid(.Formula, VLSep(4) + 1, VLSep(5) - VLSep(4) - 1)
Else
xType = "0"
End If
If xType = "FALSE" Then xType = 0
Do While Not IsNumeric(xCol)
Select Case MsgBox("Error: The Column to pick from is not numerical! Do you want to manually set the column (Yes) or directly use the last column of the input range (No)?", vbYesNoCancel)
Case vbYes
xCol = Application.InputBox("Input the column number for the input range (" & xRngI & "). '1' will be the range " & Range(xRngI).Columns(1).Address(0, 0) & ".", "Column to pick from", 1, , , , , 2)
Case vbNo
xCol = Range(xRngI).Columns.Count
Case vbCancel
xCol = " "
Exit Do
End Select
If xCol <> CInt(xCol) Or xCol > Range(xRngI).Columns.Count Or xCol = 0 Then xCol = " "
Loop
If IsNumeric(xCol) Then
Dim absRs As Boolean, absRe As Boolean, absCs As Boolean, absCe As Boolean
absCs = (Left(xRngI, 1) = "$")
absCe = (Mid(xRngI, InStr(xRngI, ":") + 1, 1) = "$")
absRs = (InStr(2, Left(xRngI, InStr(xRngI, ":") - 1), "$") > 0)
absRe = (InStr(Mid(xRngI, InStr(xRngI, ":") + 2), "$") > 0)
xRngM = Range(xRngI).Columns(1).Cells(1, 1).Address(absRs, absCs) & ":" & Range(xRngI).Columns(1).Cells(Range(xRngI).Rows.Count, 1).Address(absRe, absCs) 'for MATCH
xRngI = Range(xRngI).Cells(1, CLng(xCol)).Address(absRs, absCe) & ":" & Range(xRngI).Cells(Range(xRngI).Rows.Count, CLng(xCol)).Address(absRe, absCe) 'for INDEX
Dim fullFormulaNew As String, fullFormulaOld As String
fullFormulaNew = "INDEX(" & xRngI & ",MATCH(" & xFind & "," & xRngM & "," & xType & "))"
fullFormulaOld = Mid(Selection.Cells(1, 1).Formula, VLSep(1) - 7, VLSep(VLSep.Count) - VLSep(1) + 8)
.Formula = Replace(.Formula, fullFormulaOld, fullFormulaNew) 'simply replace the old one with the new one
End If
Wend
End With
End Sub
As you can see: the "simpler" the outcome, the more code you need. If the lookup_range is not just a address, this will fail.
If you still have any questions, just ask ;)
There is code below that I used to change ".." to ".". For example I have a name of file like "file..pdf" and I would like to have "file.pdf", but It removes all dots. I don't know how to change it:
Function strLegalFileName2(ByVal FName) As String
Dim i As Integer
Const strIllegals = "*&..&*"
strLegalFileName2 = FName
For i = 1 To Len(strIllegals)
strLegalFileName2 = Replace(strLegalFileName2, Mid$(strIllegals, i, 1), ".")
Next i
End Function
Sub LoopThroughFiles2()
Dim FName As Variant
Dim strNew As String
Dim strDir As String
strDir = "path"
FName = Dir(strDir & "*..*")
Do While Len(FName) > 0
strNew = strLegalFileName2(FName)
If StrComp(strNew, FName) <> 0 Then Name (strDir & FName) As (strDir & strNew)
FName = Dir
Loop
End Sub
Because you go through all character in your file name:
For i = 1 To Len(strIllegals)
Therefore it will remove all "." in your file name.
Just simple use:
Function strLegalFileName2(ByVal FName) As String
Dim i As Integer
Const strIllegals = "*&..&*"
strLegalFileName2 = FName
strLegalFileName2 = Replace(strLegalFileName2, "..", ".")
End Function
If you want to change some special characters to some other characters I suggest you to use this function:
Function strLegalFileName2(ByVal FName) As String
Dim strIllegal() As String
Dim i As Integer
Const strIllegals = "..#=>#."
strIllegal = Split(strIllegals, "#|#")
For i = LBound(strIllegal) To UBound(strIllegal)
FName = Replace(FName, Mid(strIllegal(i), 1, InStr(1, strIllegal(i), "#=>#") - 1), Mid(strIllegal(i), InStr(1, strIllegal(i), "#=>#") + 4))
Next i
strLegalFileName2 = FName
End Function
For more illegal you can change strIllegals = "..#=>#." to something like strIllegals = "..#=>#.#|#&#=># AND " that will change & to AND.
I'm a graphic artist, new to Excel and VBA but trying to use it to process mountains of data in excel to be used as variable data in Illustrator.
If I want to convert cells with product names for signs like "Budwieser, Bud Light & Bud Black Crown" to an abbreviation following the format "Budweiser_BL_BBC"
I have written a function that I thought would accomplish my task but it returns #VALUE!
Edit
To explain the logic: my idea was to take the string, split it on " & " and then split the first position of the resulting array on ", " then adding what was after the "&" to the end of the second array - this array, sProd, has the products separated into different positions of the array.
Then looping through that array and splitting each product at the spaces creating a jagged array.
Then loop through that array again creating a string taking only the first letter of each word in each product, separating products with an underscore. The exception being that the first word of the first product is spelled out and set in proper case. (Just saw an error in my logic and added the code for the first word exception).
Edit #2
The function should return a string with the first word of the original string set in proper case with all other words abbreviated to their first letter and products separated by underscores. So "Budweiser, Bud Light & Bud Light Lime" returns "Budweiser_BL_BLL", "All Coke & Dr Pepper Products" would return "AllC_DPP" and "Gatorade" returns "Gatorade".
This is my first bout with Excel and VBA.
Function Abbrev(p As String) As String
Dim sAmpersand() As Variant
Dim sProd() As Variant
sAmpersand = Split(p, " & ")
sProd = Split(sAmpersand(0), ", ")
sProd(UBound(sProd)) = sAmpersand(1)
Dim ProductCount As Integer
Dim ProductEnd As Integer
ProductEnd = UBound(sProd) - 1
For ProductCount = 0 To ProductEnd
sProd(ProductCount) = Split(sProd(ProductCount), " ")
ProductCount = ProductCount + 1
Next ProductCount
Dim WordCount As Integer
Dim WordEnd As Integer
WordEnd = UBound(sProd(ProductCount)) - 1
Abbrev = StrConv(sProd(0)(0), vbProperCase)
For ProductCount = 0 To ProductEnd
For WordCount = 0 To WordEnd
If ProductCount = 0 Then
WordCount = 1
End If
Abbrev = Abbrev & Left(sProd(ProductCount)(WordCount), 1)
WordCount = WordCount + 1
Next WordCount
If ProductCount + 1 < ProductEnd Then
Abbrev = Abbrev & "_"
End If
ProductCount = ProductCount + 1
Next ProductCount
End Function
Working code:
Function Abbrev(p As String) As String
Dim res As String, w1, w2
res = Split(Split(p, ",")(0), " ")(0)
If res = Split(p, ",")(0) Then res = res & "_"
For Each w1 In Split(Mid(Replace(p, " &", ","), Len(res) + 1), ",")
For Each w2 In Split(w1, " ")
res = res & Left(w2, 1)
Next w2
res = res & "_"
Next w1
Abbrev = IIf(Right(res, 1) <> "_", res, Left(res, Len(res) - 1))
End Function
Here's a better abbreviate function:
Function Abbreviate(Name As String) As String
Dim I As Integer
Dim sResult As String
Dim sTemp As String
I = InStr(Name, " ")
If I < 1 Then
Abbreviate = Name
Exit Function
End If
sResult = Left$(Name, I)
sTemp = Name
Do While I > 0
sTemp = Right$(sTemp, Len(sTemp) - I)
If Left$(sTemp, 1) = "(" Then
If Mid$(sTemp & "***", 3, 1) = ")" Then
sResult = sResult & " " & Left$(sTemp, 3)
Else
sResult = sResult & " " & Left$(sTemp, 1)
End If
Else
sResult = sResult & " " & Left(sTemp, 1)
End If
I = InStr(sTemp, " ")
Loop
Abbreviate = sResult
End Function
This is from user al_b_cnu on mrexcel.com
Here is a modified version to shorten up the result a bit:
Function Abbreviate(Name As String) As String
Dim I As Integer
Dim sResult As String
Dim sTemp As String
I = InStr(Name, " ")
If I < 1 Then
Abbreviate = Name
Exit Function
End If
sResult = Left$(Name, I)
sTemp = Name
Do While I > 0
sTemp = Right$(sTemp, Len(sTemp) - I)
If Left$(sTemp, 1) = "(" Then
If Mid$(sTemp & "***", 3, 1) = ")" Then
sResult = sResult & Left$(sTemp, 3)
Else
sResult = sResult & Left$(sTemp, 1)
End If
Else
sResult = sResult & Left(sTemp, 1)
End If
I = InStr(sTemp, " ")
Loop
Abbreviate = sResult
End Function