xml - caracteres - utf-16 table
Salida de VBA a archivo usando UTF-16 (1)
Tengo un problema muy complejo que es difícil de explicar correctamente. Hay MUCHAS discusiones sobre esto a través de Internet, pero nada definitivo. Cualquier ayuda, o mejor explicación que la mía, es muy apreciada.
Esencialmente, estoy tratando de escribir un archivo XML usando UTF-16 con VBA.
Si hago esto:
sXML = "<?xml version=''1.0'' encoding=''utf-8''?>"
sXML = sXML & rest_of_xml_document
Print #iFile, sXML
entonces obtengo un archivo que es XML válido. Sin embargo, si cambio el "encoding =" a "utf-16", recibo este error de mi validador XML:
Switch from current encoding to specified encoding not supported.
Google me dice que esto significa que el atributo de codificación xml es diferente a la codificación REAL utilizada por el archivo, por lo tanto, debo estar creando un documento utf-8 a través de los comandos Abrir e Imprimir.
Si hago algo como:
With CreateObject("ADODB.Stream")
.Type = 2
.Charset = "utf-16"
.Open
.WriteText sXML
.SaveToFile sFilename, 2
.Close
End With
luego termino con algunos caracteres funky (la BOM) al comienzo de mi archivo que hace que falle la validación XML .
Si abro el archivo en Notepad ++, elimino la lista de materiales y cambio la codificación a "UCS-2", entonces el archivo valida bien con un valor de codificación "utf-16" (lo que significa que UCS-2 está lo suficientemente cerca de UTF-16 que no importa, o que XML puede Switch from current encoding
entre estos dos tipos.
Necesito usar UTF-16 porque UTF-8 no cubre todos los caracteres utilizados en las presentaciones que estoy exportando.
La pregunta:
¿Cómo puedo hacer que VBA se comporte como Notepad ++, creando un archivo de texto codificado en UTF-16 sin una lista de materiales que pueda llenarse con datos XML? CUALQUIER ayuda muy apreciada!
Su punto acerca de que UTF-8 no puede almacenar todos los caracteres que necesita no es válido.
UTF-8 puede almacenar cada carácter definido en el estándar Unicode.
La única diferencia es que, para textos en ciertos idiomas, UTF-8 puede ocupar más espacio para almacenar sus puntos de código que, digamos, UTF-16. Lo contrario también es cierto: para ciertos otros idiomas, como el inglés, el uso de UTF-8 ahorra espacio.
VB6 y VBA, aunque las cadenas de almacenamiento en la memoria en Unicode, cambian implícitamente a ANSI (usando la página de códigos del sistema actual) al hacer el archivo IO. El archivo resultante que obtienes NO está en UTF-8. Está en la página de códigos del sistema actual, que, como puede ver en este útil artículo , se ve igual a UTF-8 si es de EE. UU.
Tratar:
Dim s As String
s = "<?xml version=''1.0'' encoding=''utf-16''?>"
s = s & ChrW$(&H43F&) & ChrW$(&H440&) & ChrW$(&H43E&) & ChrW$(&H432&) & ChrW$(&H435&) & ChrW$(&H440&) & ChrW$(&H43A&) & ChrW$(&H430&)
Dim b() As Byte
b = s
Open "Unicode.txt" For Binary Access Write As #1
Put #1, , b
Close #1
Y si definitivamente debe tener UTF-8, puede hacerse algunos:
Option Explicit
Private Declare Function WideCharToMultiByte Lib "kernel32.dll" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, ByRef lpMultiByteStr As Byte, ByVal cchMultiByte As Long, ByVal lpDefaultChar As String, ByRef lpUsedDefaultChar As Long) As Long
Private Const CP_UTF8 As Long = 65001
Private Const ERROR_INSUFFICIENT_BUFFER As Long = 122&
Public Function ToUTF8(s As String) As Byte()
If Len(s) = 0 Then Exit Function
Dim ccb As Long
ccb = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), ByVal 0&, 0, vbNullString, ByVal 0&)
If ccb = 0 Then
Err.Raise 5, , "Internal error."
End If
Dim b() As Byte
ReDim b(1 To ccb)
If WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), b(LBound(b)), ccb, vbNullString, ByVal 0&) = 0 Then
Err.Raise 5, , "Internal error."
Else
ToUTF8 = b
End If
End Function
Sub Test()
Dim s As String
s = "<?xml version=''1.0'' encoding=''utf-8''?>"
s = s & ChrW$(&H43F&) & ChrW$(&H440&) & ChrW$(&H43E&) & ChrW$(&H432&) & ChrW$(&H435&) & ChrW$(&H440&) & ChrW$(&H43A&) & ChrW$(&H430&)
Dim b() As Byte
b = ToUTF8(s)
Open "utf-8.txt" For Binary Access Write As #1
Put #1, , b
Close #1
End Sub