[LINUX] [VBA] Eine Funktion, die bestimmt, ob die Zeichenfolge des UTF-8-Dateisystems 255 oder weniger beträgt, und eine Funktion, die die Zeichenfolge von UTF-8 in Byte zählt.

Von Ansi zu UTF-8

Angst beginnt mit der Zählmethode in ANSI Eine Funktion zum einfachen Erstellen von ansiLenB Excel vor dem Starten von Access Passen Sie das UTF-16LE-Ersatzpaar an Über das Ausgrabungsersatzpaar Holen Sie sich den UTF-16 UTF-8 SJis-Zeichencode für alle Zeichen, die Excel für Microsoft 365 VBA Win32 Api und Spill verwenden Und nun

Probleme mit der Länge des Dateinamens und dem Zeichencode des Blogs des Programmiererpräsidenten

Erstens liegt ein Problem mit dem Zeichencode vor. Unter Linux und MacOS lautet der Dateiname normalerweise UTF-8. Windows scheint UNICODE in NTFS zu sein, aber es scheint Shift_JIS (CP932) in der App zu sein (weil ich nicht so interessiert bin ...). Wenn Sie mit ZIP härten und mit UTF-8 härten, werden die Zeichen daher verstümmelt. Es kann nicht geholfen werden. Wenn Sie also eine Datei mit dem CP932-Dateinamen unter Linux oder MacOS zwangsweise erstellen und mit ZIP einfrieren, funktioniert dies. Wenn Sie jedoch unter MacOS einen CP932-Dateinamen erstellen, ist dieser häufig für jedes Betriebssystem schwerer, sodass Linux besser ist. ..

Wenn Sie der Meinung sind, dass Sie das Problem des Zeichencodes behoben haben, tritt diesmal das Problem der Länge des Dateinamens auf. In Windows scheint es bis zu 256 Zeichen einschließlich des Pfads zu geben, sodass lange Dateinamen zu einem Fehler führen. Es bleibt keine andere Wahl, als lange Dateinamen abzuschneiden, aber das Abschneiden von ASCII-Zeichen ist einfach, das Abschneiden von Multibyte-Zeichen ist jedoch mühsam. Wenn Sie es an einer geeigneten Stelle schneiden, werden die Zeichen verstümmelt. Es kann nicht geholfen werden, daher wird es in C-Sprache usw. in breite Zeichen konvertiert, abgeschnitten und dann auf Multibyte zurückgesetzt.

In der Vergangenheit gab es viele CP932 für Windows und EUC für UNIX, und in vielen Fällen konnte davon ausgegangen werden, dass Japanisch 2 Byte groß war. Mit der Verbreitung des Internets sind jedoch Zeichen aus der ganzen Welt nebeneinander entstanden. Infolgedessen sind Multi-Bytes nicht mehr ungefähr 2 Bytes groß, und es ist schwierig geworden, sie selbst zu verwalten. Es wäre besser, eine Bibliothek zu verwenden, die gehorsam mit mehreren Bytes umgeht ... </ b>

Präsident ...

(Ausgelassen) Jetzt können Sie ihm endlich einen Dateinamen geben, den Sie unter Windows entpacken können. "Erwartet" liegt daran, dass die Pfadlänge bis zu 256 Zeichen beträgt und daher je nach zu erweiterndem Verzeichnis überschritten werden kann.

Unter UNIX-basierten Betriebssystemen wie Linux beträgt die maximale Dateinamenlänge übrigens 255 Byte. Die maximale Pfadlänge beträgt 1023 Byte (die Grenze bei der Übergabe an Systemaufrufe), was erheblich einfacher zu handhaben ist als Windows. </ B>

Also im Fall eines Linux-Servers Der Dateiname lautet Der Zeichencode lautet UTF-8 255 Zeichen in halber Breite Es stellt sich heraus, dass. Diese 255 Zeichen mit halber Breite bedeuten, dass Zeichen mit voller Breite 85 Zeichen sind. Dies liegt daran, dass eine Halbwertsbreite von 1 Byte 3 Bytes beträgt. Zusätzlich beträgt das Ersatzpaar 4 Bytes. Es wurde dies offenbart Holen Sie sich den UTF-16 UTF-8 SJis-Zeichencode für alle Zeichen, die Excel für Microsoft 365 VBA Win32 Api und Spill verwenden Hier wird ein Blatt aus SheetMake2 erstellt. Im Bereich der Beurteilungsgenauigkeit dieser Win32-API wird die Zeichenfolge in eine UTF-8-Binärdatei konvertiert. Dies wird verwendet, um in Bytes zu zählen. Auch dieses Mal werden wir die Win32-API verwenden. Der folgende Code wurde zusätzlich zum [vorherigen] geschrieben (https://qiita.com/Q11Q/items/98d1f5e4e886bec6c240).

#If VBA7 Then
Declare PtrSafe Function MessageBox Lib "user32" Alias "MessageBoxW" _
    (ByVal hwnd As LongPtr, ByVal lpText As LongPtr, _
     ByVal lpCaption As LongPtr, ByVal wType As Long) As Long
Declare PtrSafe Function GetFocus Lib "user32" () As LongPtr
Declare PtrSafe Function GetWindowsDirectory Lib "Kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
 Declare PtrSafe Function GetSystemDirectory Lib "Kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
 Declare PtrSafe Function GetTempPath Lib "Kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
'Private Declare PtrSafe Function SetCurrentDirectory Lib "kernel32" (ByVal lpPathName As Long) As Long
' Set rrent Directory
Private Declare PtrSafe Function SetCurrentDirectory Lib "Kernel32" Alias _
                            "SetCurrentDirectoryA" (ByVal CurrentDir As String) As Long
'Private Declare PtrSafe Function SetCurrentDirectory Lib "kernel32.dll" Alias "SetCurrentDirectoryW" (ByVal lpPathName As Long) As Long
'Private Declare PtrSafe Function SetCurrentDirectory Lib "kernel32.dll" Alias "SetCurrentDirectoryA" (ByVal lpPathName As Long) As Long

#Else
'Die folgende Declare-Anweisung wurde dem Standardmodul hinzugefügt
Declare Function MessageBox Lib "user32" Alias "MessageBoxW" _
    (ByVal hwnd As Long, ByVal lpText As Long, _
     ByVal lpCaption As Long, ByVal wType As Long) As Long
Declare Function GetFocus Lib "user32" () As Long
Private Declare Function GetWindowsDirectory Lib "kernel32" _
 Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, _
 ByVal nSize As Long) As Long
#End If
Private Declare PtrSafe Function MultiByteToWideChar Lib "kernel32.dll" ( _
    ByVal CodePage As Long, _
    ByVal dwFlags As Long, _
    ByVal lpMultiByteStr As LongPtr, _
    ByVal cchMultiByte As Long, _
    ByVal lpWideCharStr As LongPtr, _
    ByVal cchWideChar As Long) As Long

Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32.dll" ( _
    ByVal CodePage As Long, _
    ByVal dwFlags As Long, _
    ByVal lpWideCharStr As LongPtr, _
    ByVal cchWideChar As Long, _
    ByVal lpMultiByteStr As LongPtr, _
    ByVal cchMultiByte As Long, _
    ByVal lpDefaultChar As LongPtr, _
    ByVal lpUsedDefaultChar As Long) As Long
Private Const CP_UTF8 = 65001

Private Const ERROR_INSUFFICIENT_BUFFER = 122&

'UFT-Code für 16LE Sarrogate Pair
Sub TestSarrogatePair()
' For Excel
'Angenommen, die ActiveCell enthält ein Ersatzpaar
'Zum Testen, Suche nach seinem überlegenen und minderwertigen Ersatz
'Anzeige mit MsgBoxEx
'Verwenden Sie aus diesem Grund die Windows-API
' UTF-16 LE ,Bb für BE(0) bb(1) bb(2) bb(3)werden
Dim b As String
Dim bb() As Byte
Dim Text As String
b = ActiveCell.Value
bb = b
Debug.Print "AscW Result(Dec -> Hex)" & vbTab & Hex(AscW(b))
Debug.Print "&H" & Hex(bb(1)) & Hex(bb(0))
Debug.Print "&H" & Hex(bb(3)) & Hex(bb(2))
Text = ChrW("&H" & Hex(bb(1)) & Hex(bb(0))) & ChrW("&H" & Hex(bb(3)) & Hex(bb(2)))
Debug.Print "ChrW(" & "&H" & Hex(bb(1)) & Hex(bb(0)) & ") & ChrW(&H" & Hex(bb(3)) & Hex(bb(2)) & ")"
MsgBoxEx Text
End Sub
'UTF-16 LE
Function UTF16Sarrogate(s As String)
Dim bb() As Byte
If IsUpperSarrogateCharacter(s) And IsLowerSarrogateCharcter(s) Then
bb = s
UTF16Sarrogate = "0x" & CStr(Hex(bb(1)) & Hex(bb(0))) & " " & "0x" & CStr(Hex(bb(3)) & Hex(bb(2)))
Exit Function
Else
UTF16Sarrogate = ""
End If
End Function
Function IsUpperSarrogateCharacter(s As String)
If Hex(AscW(s)) >= Hex(&HD800) And Hex(AscW(s)) <= Hex(&HDBFF) Then
IsUpperSarrogateCharacter = True: Exit Function
Else
IsUpperSarrogateCharacter = False: Exit Function
End If
End Function
Function IsLowerSarrogateCharcter(s As String)
Dim bb() As Byte
If IsUpperSarrogateCharacter(s) = True Then
bb = s
'Debug.Print Hex("&H" & bb(3) & bb(2))
If Hex("&H" & bb(3) & bb(2)) <= Hex(&HDC00) And Hex("&H" & bb(3) & bb(2)) <= Hex(&HDFFF) Then
IsLowerSarrogateCharcter = True: Exit Function
Else
IsLowerSarrogateCharcter = False: Exit Function
End If
End If
End Function
Function VBAAscW(s As String)
If AscW(s) < 0 Then
VBAAscW = AscW(s) + 65536: Exit Function
Else
VBAAscW = AscW(s): Exit Function
End If
End Function
' Shift-Jis
Function VBA_ASC(s As String)
If isSJIS(s) Then
VBA_ASC = Hex(Asc(s)): Exit Function
Else
VBA_ASC = "": Exit Function
End If
End Function
Function isSJIS(ByVal argStr As String) As Boolean
'https://excel-ubara.com/excelvba4/EXCEL_VBA_403.html
    Dim sQuestion As String
    sQuestion = Chr(63) '?:Falls es ein Missverständnis im Zeichenliteral gibt
    Dim i As Long
    For i = 1 To Len(argStr)
        If Mid(argStr, i, 1) <> sQuestion And _
           Asc(Mid(argStr, i, 1)) = Asc(sQuestion) Then
            isSJIS = False
            Exit Function
        End If
    Next
    isSJIS = True
End Function
Function LenByteUTF8(ByRef s As String) As Long
    If Len(s) = 0 Then
        LenByteUTF8 = 0
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    LenByteUTF8 = UBound(Ret) + 1
End Function
Function IsLengthle255byteOnUTF8(s As String) As Boolean
'Es ist eine Testversion und wird überprüft.
' UTF-In 8 konvertieren und Byte-Array zuweisen, um die Anzahl zu zählen
'Falsch, wenn größer als 255
'Bei Verwendung dieser Funktion
' https://qiita.com/Q11Q/items/a2d61545d9e5c4e15f22
'Achten Sie auf die VBE-Einstellungen
    If Len(s) = 0 Then
        IsLengthle255byteOnUTF8 = False
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    Dim cnt As Long
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    cnt = UBound(Ret) + 1
    If cnt > 255 Then IsLengthle255byteOnUTF8 = False: Exit Function Else IsLengthle255byteOnUTF8 = True: Exit Function
End Function

Zum vorherigen Modul hinzufügen. Was ich diesmal hinzugefügt habe LenByteUTF8

Function LengthUTF8(s As String)
'Es ist eine Testversion und wird überprüft.
' UTF-In 8 konvertieren und Byte-Array zuweisen, um die Anzahl zu zählen
'Falsch, wenn größer als 255
'Bei Verwendung dieser Funktion
' https://qiita.com/Q11Q/items/a2d61545d9e5c4e15f22
'Achten Sie auf die VBE-Einstellungen
    If Len(s) = 0 Then
        LengthUTF8 = 0
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    Dim cnt As Long
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    cnt = UBound(Ret) + 1
    LengthUTF8 = cnt
End Function

Und IsLengthle 255byteOnUTF8 Ist.

Function IsLengthle255byteOnUTF8(s As String) As Boolean
'Es ist eine Testversion und wird überprüft.
' UTF-In 8 konvertieren und Byte-Array zuweisen, um die Anzahl zu zählen
'Falsch, wenn größer als 255
'Bei Verwendung dieser Funktion
' https://qiita.com/Q11Q/items/a2d61545d9e5c4e15f22
'Achten Sie auf die VBE-Einstellungen
    If Len(s) = 0 Then
        IsLengthle255byteOnUTF8 = False
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    Dim cnt As Long
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    cnt = UBound(Ret) + 1
    If cnt > 255 Then IsLengthle255byteOnUTF8 = False: Exit Function Else IsLengthle255byteOnUTF8 = True: Exit Function
End Function

In der vorherigen Version von UUTF8 können Sie sehen, wie in Byteeinheiten gezählt wird.

ReDim Ret(0 To nBufferSize - 1) Hier werden Byteeinheiten gezählt. Es mag in Ordnung sein, es so zu löschen, wie es ist, aber ich kenne das Verhalten von Win32API nicht, daher werde ich es definitiv dem Array zuweisen. Addieren Sie dann 1 zur Anzahl der von Ubound erfassten Elemente. Es ist möglicherweise möglich, dies auf 1 zu setzen, wenn Redim anstelle von 0 verwendet wird. Da dieses Array jedoch in Win32Api enthalten ist, habe ich beschlossen, es nicht zu ändern.

Dies ist nicht die Länge des Verzeichnisses oder der Datei auf dem Windows-Server

Wie im Blog des Präsidenten angegeben, ist es Linux, nicht Windows, das in UTF-8 255 Zeichen und 255 Bytes in halber Breite sein soll, und die Dateilänge des Windows-Servers kann damit nicht gemessen werden.

Das Ersatzpaar besteht aus 4 Bytes

Wenn auf dieser Basis gezählt wird, verbraucht das Ersatzpaar 4 Bytes und 4 Zeichen in halber Breite. Auch wenn es wie ein Zeichen voller Breite aussieht, werden 42 Zeichen als Begrenzung angesehen. Wenn Sie suchen, finden Sie verschiedene Theorien, z. B. 5 oder 6 Bytes. Laut IBM-Materialien hat UTF-8 maximal 4 Bytes. https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.5.0/com.ibm.db2.luw.admin.nls.doc/doc/c0004816.html Daher ist das Maximum auf 4 Bytes eingestellt. Ein 4-Byte-Beispiel ist ein Ersatzpaar.

Bytes und Anzahl der Zeichen

Diese Funktion konvertiert die Zeichenfolge in UTF-8-Bytes. Es scheint also, dass Sie es durch einen Code ersetzen können, unabhängig davon, ob es in voller oder halber Breite ist, und es so lang machen. Mit anderen Worten, die Kapazität beträgt 255 Bytes und die Anzahl der Zeichen beträgt 255, sodass sie im Text ordnungsgemäß verwendet werden.

Win32 API und Stärken

Es ist sicherlich ein langer Code, aber Sie müssen sich nicht auf ADODB beziehen. Außerdem wird toUTF8 in ein UTF-8-Byte-Array konvertiert, sodass es ohne Verschütten nutzlos wäre. Es ist jedoch nur im Arbeitsblatt von Excel gültig, sodass es schwierig ist, es nur in Excel zu verwenden. Da diese Funktion die Anzahl der Zeichen in die Anzahl der Bytes ändert und 255 Zeichen bestimmt, kann sie nicht nur in Excel, sondern auch in Access, Word und Publisehr Outlook verwendet werden.

Recommended Posts