9

I would like to declare (in a VBA class module) some private constant strings that contain Japanese characters. Is there a way to construct String literals (or combining literals in a way) that may be accepted as initializers in a Const declaration? i.e. something like:

Private Const MY_CONST = ...

or

Private Const MY_CONST As String = ...

I use MS Excel v14.0.6112.5000 (MS Office Professional Plus 2010).

What won't work:

  • Pasting the Japanese chars directly in a string literal (e.g. ... = "変数") because the VBA editor will mess with the chars;
  • Using ChrW() or ChrW$() (e.g. ... = ChrW$(22793) & ChrW$(25968)), because function calls are not allowed in Const initializers.

What I wouldn't like:

  • Faking the Const by creating Private Property Get returning the string, because the string will be recreated every time I access the property (plus, is confusing and ugly... but, okay, the last two things are rather a matter of taste).
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • have you tried to change the font of editor to one that supports japanese? –  May 15 '14 at 12:22
  • 3
    fonts are not the issue. the VBA editor saves VBA files as Windows-1252 which does not support Japanese – z̫͋ May 15 '14 at 12:23
  • @me how: No, I didn't try. But the fonts that are available have only the variants: Baltic, Central European, Cyrillic, Greek, Turkish and Vietnamese. Plus, anyone that will run my code will need to do the same, right? Or maybe not... anyways, I will try. –  May 15 '14 at 12:31
  • @CST-Link also investigate [**this**](http://www.mydigitallife.info/how-to-install-microsoft-applocale-in-windows-7/) (*haven't tried myself just heard about it*) –  May 15 '14 at 12:40

3 Answers3

4

Faking the Const by creating Private Property Get returning the string, because the string will be recreated every time I access the property (plus, is confusing and ugly... but, okay, the last two things are rather a matter of taste).

You need not recreate the string each time you access the property.

While this is still ugly as a matter of taste, make a read-only property (essentially Const, since it doesn't have a Property Let procedure), and construct the string in the Class_Initialize event:

'## CLASS MODULE
Private pUnicodeString As String

Sub Class_Initialize()
    pUnicodeString = ChrW(22793) & ChrW(25968)
End Sub

Property Get UnicodeString() As String
    UnicodeString = pUnicodeString
End Property

And then invoke it like:

'## STANDARD MODULE
Sub Test()
Dim c As myClass
Set c = New myClass

[A1].Value = c.UnicodeString

End Sub
David Zemens
  • 53,033
  • 11
  • 81
  • 130
  • I was thinking about something like this as a last resort (hence: "I wouldn't like"), except creating private members in the class for storing the pre-calculated results. I guess it's because I was trying to avoid re-storing the strings in each class instance -- i know it's ridiculous to thinking about saving few kBytes of memory, but some bad habits die hard... :-) –  May 15 '14 at 14:47
  • (cont): However, I thought that the language itself allows creating `Const` initilizers for full Unicode range, and I didn't know of such a syntactical "trick". But your posting supports the idea that there's no such a thing for now (by the way, thanks for your answer). –  May 15 '14 at 14:50
  • Right, I don't know that there is a way to do it... I have only used single-character constants and that can't be done without a conversion from Long: http://social.msdn.microsoft.com/Forums/en-US/ba1f6bc5-beeb-4a0c-8cdd-afd3ea95b0ee/excelvba-unicode-literals – David Zemens May 15 '14 at 15:34
  • 1
    I chose yours as answer, though I did in a slightly different manner in the end (separate standard Module, initialized at worksheet open, Public Property Get for each string). Like this, the strings are not duplicated in each class instance, and I can also reuse strings in several classes (at the expense of keeping "class-local" things local). –  May 18 '14 at 08:31
  • An alternative to intiializing at workbook open, is to add a `VB_PredeclaredId = True` attribute to the class, and initiaize in the `Class_Initialize` handler instead; then use the class' default instance as if it were a standard module. – Mathieu Guindon Jan 15 '19 at 17:33
  • 1
    Amplifying remark FYI: The ChrW charcode argument is a *Long* that identifies a character, *but* doesn't allow values greater than **65535 (hex value &HFFFF**. You find several valid work arounds at this SO site [Get-unicode-characters-with-charcode-values-greater-hex-ffff](https://stackoverflow.com/questions/56008191/get-unicode-characters-with-charcode-values-greater-hex-ffff) – T.M. Sep 28 '19 at 16:56
3

The encoding of VBA source file is Windows-1252, which does not support Japanese.

You cannot change the encoding of the source file, so you have to write its binary equivalent and then convert it before using it

Const str = vbTab & "Ype" ' I use vbTab because the VBA editor replaces tabulation with spaces
'...
ustr = StrConv(str, vbFromUnicode)
'ustr value is now "変数"

Use notepad to convert the string: copy-paste the unicode string, save the file as unicode (not utf-8) and open it as ANSI, then copy-paste it into the VBA editor without the first two characters (ÿþ), which is the BOM marker

Explanation

変数 is U+5909 U+6570 in unicode which is 0x09 0x59 0x70 0x65 in UTF-16LE (Windows unicode encoding), and this sequence corresponds to <tab>Ype in Windows-1252

z̫͋
  • 1,531
  • 10
  • 15
  • While it doesn't answer precisely to my question, this is definitely an interesting workaround: instead 70 `Property Get`, I could get away with 70 `Const` and a single `Property Get` for conversion. Thanks! One would think that--for something that stores internally all its strings in Unicode--they'd provide an easy way of escaping codes into a string, but... :-) –  May 15 '14 at 12:57
  • 1
    @CST-Link I know this is a rather ugly solution, but i am not aware of any possibility to change the VBA source file encoding. Which is strange because VBA Strings use unicode internally, but even stranger the VBA documentation says that you can use Unicode in the source file, and even declare Unicode [variable names](http://msdn.microsoft.com/en-us/library/ee199767.aspx)! – z̫͋ May 15 '14 at 13:06
  • While I *REALLY* liked your solution for its cleverness, unfortunately is not general enough. One char that I had to deal with, it "contained" an ASCII SOH (0x01), and I could not find *a single way* of storing that in a VBA initializer. So I went for brute-force: I just created a Module of Property-interfaced constructed Japanese strings that have an English ID. And, by the way, about the link that you mentioned in your comment; it *is* surprising: you could declare Unicode variable names, but the code is not portable! (tried it with one of my Japanese colleagues). Funny, isn't it? :-D –  May 16 '14 at 20:38
2

Another approach is to use an Enum in combination with a function to provide VBA autocomplete based on friendly names. I prefer this method because it keeps all the Unicode definitions in one place, and uses the readable names throughout the rest of my project.

' List friendly names of Unicode characters
Public Enum eUnicodeConst
    RightArrow
    LeftArrow
    Clock2
End Enum

'---------------------------------------------------------------------------------------
' Procedure : UniConst
' Author    : Adam Waller
' Date      : 7/7/2020
' Purpose   : Search for characters: https://emojipedia.org/
'           : Look up UTF-16 Decimal value(s) from the following site:
'           : http://www.fileformat.info/info/unicode/char/search.htm
'---------------------------------------------------------------------------------------
'
Public Function UniConst(Text As eUnicodeConst) As String
    Select Case Text
        Case LeftArrow:     UniConst = ChrW(8592)
        Case RightArrow:    UniConst = ChrW(8594)
        Case Clock2:        UniConst = ChrW(55357) & ChrW(56657)
    End Select
End Function

Now in my code, I can just use the UniConst function anytime I need a Unicode character or snippet without having to look character codes.

enter image description here

AdamsTips
  • 1,648
  • 17
  • 22