This question already has answers here:
Unicode string literals in VBA
(3 answers)
How to type Unicode currency character in Visual Basic Editor
(2 answers)
Closed 9 months ago.
I need to be able to use strings of multiple languages (english, chinese and japanese) in VBA. Changing the region/locale setting of the computer only works if there is one language. Could someone help?
Example code
dim x as string
dim y as string
dim z as string
x = "English text"
y = "尊敬的"
z = "こんにちは"
There's a simple alternative to ashleedawg's suggestion:
Use bytearrays instead of strings to declare the strings. That way, the VBA IDE can store the data independent of locale settings.
I use the following function to declare bytearrays in VBA (Note: errors if you pass anything else than a byte):
Public Function ByteArray(ParamArray bytes() As Variant) As Byte()
Dim output() As Byte
ReDim output(LBound(bytes) To UBound(bytes))
Dim l As Long
For l = LBound(bytes) To UBound(bytes)
output(l) = bytes(l)
Next
ByteArray = output
End Function
If you have this, you can do the following:
dim x as string
dim y as string
dim z as string
x = "English text"
'Or: x = ByteArray(&H45,&H0,&H6E,&H0,&H67,&H0,&H6C,&H0,&H69,&H0,&H73,&H0,&H68,&H0,&H20,&H0,&H74,&H0,&H65,&H0,&H78,&H0,&H74,&H0)
y = ByteArray(&HA,&H5C,&H6C,&H65,&H84,&H76)
z = ByteArray(&H53,&H30,&H93,&H30,&H6B,&H30,&H61,&H30,&H6F,&H30)
To get these bytearrays, I use the following worksheet function:
Public Function UnicodeToByteArray(str As String) As String
If Len(str) = 0 Then Exit Function
Dim bytes() As Byte
bytes = str
Dim l As Long
For l = 0 To UBound(bytes) - 1
UnicodeToByteArray = UnicodeToByteArray & "&H" & Hex(bytes(l)) & ","
Next
UnicodeToByteArray = UnicodeToByteArray & "&H" & Hex(bytes(UBound(bytes)))
End Function
You can use this in a worksheet (e.g. =UnicodeToByteArray(A1) where A1 contains the string), and then copy-paste the result to VBA.
You can directly assign strings to bytearrays and reversed.
Note that unicode support varies throughout VBA. E.g. MsgBox z will result in questionmarks, while Cells(1,1).Value = z will set A1 to the desired string.
Related
I need to separate following strings into Name and Number: e.g.
evil333 into evil and 333
bili454 into bili and 454
elvis04 into elvis and 04
Split(String, "#") ' don't work here because numbers are unknown
similarly
Mid(String, 1, String - #) ' don't work because Numbers length is unknown
so what should be the best way to start? Just want to keep it simple as possible
Update:
For further info follow - https://youtu.be/zjF7oLLgtms
Two more ways for solving this:
Sub test()
Dim sInputString As String
Dim i As Integer
Dim lFirstNumberPos As Long
sInputString = "evil333"
'loop through text in input string
'if value IsNumeric (digit), stop looping
For i = 1 To Len(sInputString)
If IsNumeric(Mid(sInputString, i, 1)) Then
lFirstNumberPos = i
Exit For
End If
Next i
Dim Name As String
Dim Number As String
'return result
Name = Left$(sInputString, lFirstNumberPos - 1)
Number = Mid$(sInputString, lFirstNumberPos)
End Sub
Or another method:
Sub test2()
'if you are going to have too long string it would maybe better to use "instr" method
Dim sInputString As String
Dim lFirstNumberPos As Long
Dim i As Integer
sInputString = "evil333"
Dim lLoopedNumber as Long
LoopedNumber = 0
lFirstNumberPos = Len(sInputString) + 1
'loop through digits 0-9 and stop when any of the digits will be found
For i = 0 To 9
LoopedNumber = InStr(1, sInputString, cstr(i), vbTextCompare)
If LoopedNumber > 0 Then
lFirstNumberPos = Application.Min(LoopedNumber,lFirstNumberPos)
End If
Next i
Dim Name As String
Dim Number As String
'return result
Name = Left$(sInputString, lFirstNumberPos - 1)
Number = Mid$(sInputString, lFirstNumberPos)
End Sub
You should regular expressions (regex) to match the two parts of your strings. The following regex describes how to match the two parts:
/([a-z]+)([0-9]+)/
Their use in VBA is thorougly explained in Portland Runner's answer to How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops
I'm wondering why the below code works as I hoped for, considering that I'm splitting a string into an array (that's also defined as a string), and afterwards comparing it in an arithmetic (numeric) way.
Option Explicit
Sub test()
Dim str As String, arr() As String
Dim num As Integer, i As Integer
str = "12 9 30"
num = 20
arr() = Split(str, " ")
For i = LBound(arr) To UBound(arr)
If arr(i) > num Then
MsgBox (arr(i) & " is larger than " & num)
End If
Next i
End Sub
As intended the msgBox within the if statement is fired, showing that:
12 isn't larger than 20
9 isn't larger than 20
30 is larger than 20
I didn't know/think that such comparison could work as hoped as i'm basically comparing a string to an integer. I assume there's something i'm not aware of, but in that case, what is it?
PS. I was a bit in doubt regarding which forum to post in, but based my choice on this meta question
For answer please refer to the following article: https://msdn.microsoft.com/en-us/library/aa263418(v=vs.60).aspx
In short if you compare string to numeric type variable, string variable is converted to double* type.
*double based on the information from VB .net comparison operators reference (https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/comparison-operators), VB 6.0, VBA and VBA .net are not the same things, however comparison logic should be the same.
VBA seems to be implicitly converting the data type during run-time.
Consider following code which also works.
Sub test2()
Dim str As String, arr() As String, num As String
Dim i As Integer
str = "12 9 30"
num = 12 '\\ Note the way number is being passed.
arr() = Split(str, " ")
For i = LBound(arr) To UBound(arr)
If arr(i) = num Then
MsgBox (arr(i) & " is equal to " & num)
End If
Next i
End Sub
And then below one where arithmetic operation is coercing it to be numeric at run-time.
Sub test3()
Dim str As String, arr() As String, num As String
Dim i As Integer
str = "12 9 30"
num = 12
arr() = Split(str, " ")
For i = LBound(arr) To UBound(arr)
If (arr(i) - num) > 0 Then
MsgBox (arr(i) & " is greater than " & num)
End If
Next i
End Sub
I know it will not answer your question fully but might explain why it is giving correct result. It is advisable to convert to correct data type rather than relying on defaults i.e.
If CInt(arr(i)) > num Then
I have the following string:
21||10/04/2017||34390136||SOME TEXT
How can I extract, in vba, the four values divided by "||" ? (21 , 10/04/2017 , 34390136 , Some Text)
I need four string with each one of the values.
Thanks
Use the SPLIT command to split by the delimeter:
Sub Test()
Dim MyString As String
Dim MySplit As Variant
Dim x As Long
MyString = "21||10/04/2017||34390136||SOME TEXT"
MySplit = Split(MyString, "||")
For x = LBound(MySplit) To UBound(MySplit)
MsgBox MySplit(x)
Next x
End Sub
or as single lines:
split("21||10/04/2017||34390136||SOME TEXT","||")(0)
split("21||10/04/2017||34390136||SOME TEXT","||")(1)
split("21||10/04/2017||34390136||SOME TEXT","||")(2)
split("21||10/04/2017||34390136||SOME TEXT","||")(3)
I have a strange problem here. In my code, variable b string, has the value "Test Test Test". This value we can see while debugging the variable as well as in the text visualizer.
Now the problem is, if I show the same string using Messagebox, the value is just "Test". What can I do here to get the complete value.
I am converting from an ebcdic encoded bytes to corresponding utf8 string and doing the above operation. Any thoughts. below is my sample code.
Dim hex As String = "e385a2a300000000e385a2a3000000e385a2a3"
Dim raw As Byte() = New Byte((hex.Length / 2) - 1) {}
Dim i As Integer
For i = 0 To raw.Length - 1
raw(i) = Convert.ToByte(hex.Substring((i * 2), 2), &H10)
Next i
Dim w As String = System.Text.Encoding.GetEncoding(37).GetString(raw)
Dim raw1 As Byte() = Encoding.UTF8.GetBytes(w)
Dim b As String = Encoding.UTF8.GetString(raw1)
MessageBox.Show(b)
Look at the byte array. You have 4 ASCII 0's after each "Test". ASCII character code 0 corresponds to nul, which is a string termination sequence. If you want spaces instead of nulls there...
Dim b As String = Encoding.UTF8.GetString(raw1).Replace(Chr(0), " ")
It is possible that the string "b" might contains some control character.
To test a control char in string.
For Each p As Char In b
MsgBox(p & " " & Char.IsControl(p) & " " & AscW(p))
Next
Use String#Replace to replace control chars.
b = b.Replace(ChrW(0), " ")
MsgBox(b)
I am new to VB.Net 2008. I have a task to resolve, it is regading extracting characters from a long string to the console, the extracted text shall be reformatted and saved into a CSV file. The string comes out of a database.
It looks something like: UNH+RAM6957+ORDERS:D:96A:UN:EGC103'BGM+38G::ZEW+REQEST6957+9'DTM+Z05:0:805'DTM+137:20100930154
The values are seperated by '.
I can query the database and display the string on the console, but now I need to extract the
Keyword 'ORDERS' for example, and lets say it's following 5 Characters. So the output should look like: ORDERS:D:96A then I need to extract the keyword 'BGM' and its following five characters so the output should look like: BGM+38G:
After extracting all the keywords, the result should be comma seperated and look like:
ORDERS:D:96A,BGM+38G: it should be saved into a CSV file automatically.
I tried already:
'Lookup for containing KeyWords
Dim FoundPosition1 = p_EDI.Contains("ORDERS")
Console.WriteLine(FoundPosition1)
Which gives the starting position of the Keyword.
I tried to trim the whole thing around the keyword "DTM". The EDI variable holds the entire string from the Database:
Dim FoundPosition2 = EDI
FoundPosition2 = Trim(Mid(EDI, InStr(EDI, "DTM")))
Console.WriteLine(FoundPosition2)
Can someone help please?
Thank you in advance!
To illustrate the steps involved:
' Find the position where ORDERS is in the string.'
Dim foundPosition = EDI.IndexOf("ORDERS")
' Start at that position and extract ORDERS + 5 characters = 11 characters in total.'
Dim ordersData = EDI.SubString(foundPosition, 11)
' Find the position where BGM is in the string.'
Dim foundPosition2 = EDI.IndexOf("BGM")
' Start at that position and extract BGM + 5 characters = 8 characters in total.'
Dim bgmData = EDI.SubString(foundPosition2, 8)
' Construct the CVS data.'
Dim cvsData = ordersData & "," & bgmData
I don't have my IDE here, but something like this will work:
dim EDI as string = "UNH+RAM6957+ORDERS:D:96A:UN:EGC103'BGM+38G::ZEW+REQEST6957+9'DTM+Z05:0:805'DTM+137:20100930154"
dim result as string = KeywordPlus(EDI, "ORDER", 5) + "," _
+ KeywordPlus(EDI, "BGM", 5)
function KeywordPlus(s as string, keyword as string, length as integer) as string
dim index as integer = s.IndexOf(keyword)
if index = -1 then return ""
return s.substring(index, keyword.length + length)
end function
for the interrested people among us, I have put the code together, and created
a CSV file out of it. Maybe it can be helpful to others...
If EDI.Contains("LOC") Then
Dim foundPosition1 = EDI.IndexOf("LOC")
' Start at that position and extract ORDERS + 5 characters = 11 characters in total.'
Dim locData = EDI.Substring(foundPosition1, 11)
'Console.WriteLine(locData)
Dim FoundPosition2 = EDI.IndexOf("QTY")
Dim qtyData = EDI.Substring(FoundPosition2, 11)
'Console.WriteLine(qtyData)
' Construct the CSV data.
Dim csvData = locData & "," & qtyData
'Console.WriteLine(csvData)
' Creating the CSV File.
Dim csvFile As String = My.Application.Info.DirectoryPath & "\Test.csv"
Dim outFile As IO.StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(csvFile, True)
outFile.WriteLine(csvData)
outFile.Close()
Console.WriteLine(My.Computer.FileSystem.ReadAllText(csvFile))
End IF
Have fun!