我该如何解决VBA和Powershell之间的特殊字符编码问题?

3

为了一个较大的vba应用程序,我需要使用powershell脚本来获取共享文件夹中的文件名。由于我住在德国,这些文件名包含许多德语特殊字符,如üä等。

Powershell脚本的输出,在PS控制台上应该(并且确实)正确显示这些字符,但在VBA中却没有正确显示。我编写了这个最小示例来证明这一点。

任何能返回für而不是fr的解决方案都会得到赞赏。

Option Explicit
Const HK = """"

Sub ScanDrive()
    Dim s As String, command As String
   
    command = "echo 'für'"
    Debug.Print (command)
    'Method1: start PS in CMD with /u parameter
    s = CreateObject("Wscript.Shell").exec("cmd /u /c powershell.exe -command " & HK & command & HK).StdOut.ReadAll
    Debug.Print (s)
    'Method2: start PS directly (preferred)
    s = CreateObject("Wscript.Shell").exec("powershell.exe -command " & HK & command & HK).StdOut.ReadAll
    Debug.Print (s)
End Sub

我的输出看起来像这样(虽然VBA根本不显示“ `”字符):

echo 'für'
fr

fr

我已经学习到在写入文件输出时可以更改PS的输出编码,但不幸的是这不是一个选项。

我理解,我需要让Excel读取UTF-8(我猜这就是它的编码方式),或者让PS控制台输出Win-1252(这只是我的猜测,Excel使用的编码方式)。

由于我必须在公司部署此脚本,我不能依赖于PS控制台的任何全局开关。

更新

根据JosefZ的评论,我将命令作为[System.Console] :: OutputEncoding并在VBA中获得了以下结果:

IsSingleByte      : True
BodyName          : ibm850
EncodingName      : Westeurop„isch (DOS)
HeaderName        : ibm850
WebName           : ibm850
WindowsCodePage   : 1252
IsBrowserDisplay  : False
IsBrowserSave     : False
IsMailNewsDisplay : False
IsMailNewsSave    : False
EncoderFallback   : System.Text.InternalEncoderBestFitFallback
DecoderFallback   : System.Text.InternalDecoderBestFitFallback
IsReadOnly        : True
CodePage          : 850

与直接在PowerShell中运行它相反,其中它说明:

IsSingleByte      : True
BodyName          : iso-8859-1
EncodingName      : Westeuropäisch (Windows)
HeaderName        : Windows-1252
WebName           : Windows-1252
WindowsCodePage   : 1252
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
EncoderFallback   : System.Text.InternalEncoderBestFitFallback
DecoderFallback   : System.Text.InternalDecoderBestFitFallback
IsReadOnly        : True
CodePage          : 1252

CreateObject("Wscript.Shell")似乎在Dos编码和CP850上工作。


1
我猜 $OutputEncoding[System.Console]::OutputEncoding[System.Console]::InputEncoding 必须与 VBA 脚本编码(或内部 Excel 编码)一致... - JosefZ
@JosefZ,感谢您对这些命令的见解。我更新了问题,并添加了这些命令的输出。 - Daniel Kaupp
1
不是答案,但我发现这很有趣,可能对你有用:https://francescofoti.com/2020/01/solving-the-unicode-utf8-utf16-and-text-files-conundrum-in-vba/ - Tim Williams
不错的问题/答案; +1。不过,您是否愿意编辑问题标题,使其更精确地涉及特殊字符编码方面的问题?我相信这样可能会在未来帮助更多的人。 - Tragamor
1个回答

4
幸运的是,我找到了解决方案。 JosefZ的评论让我找到了正确的方向,并引导我找到了Garric对另一个问题的被低估的答案this
将他的解决方案应用于我的原始最小示例代码得到了这个:
Option Explicit
Const HK = """"

Sub ScanDrive()
    Dim s As String, command As String
    Dim codepage As String
    codepage = "windows-1252"
    command = "$OutputEncoding = [Console]::outputEncoding = [System.Text.Encoding]::GetEncoding('" + codepage + "'); echo 'für'"
    Debug.Print (command)
    s = CreateObject("Wscript.Shell").Exec("powershell.exe -command " & HK & command & HK).StdOut.ReadAll
    Debug.Print (s)
End Sub

Et Voilá - 我们已经正确地使用了德语Umlauts :)


还有一件可能会让人困惑的事情:如果你在powershell中运行这个命令,它会报错,说你不能给其中一个变量赋值。省略任何一个被赋值的变量都可以解决错误,但是这样就无法在vba中正常工作了。由于我们不使用Stderr,我认为这仍然是可以接受的。 - Daniel Kaupp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接